在 cmets 上进行扩展。
来自 Frank 在评论中提供的 What is the purpose of setting a key in data.table? 中的 Arun 帖子:
- 即使在其他情况下,除非您重复执行连接,否则键控连接和临时连接之间应该没有明显的性能差异。
和
因此,必须弄清楚花在重新排序整个 data.table 上的时间是否值得花时间进行高效缓存的连接/聚合。通常,除非在同一个 keyed data.table 上执行重复的分组/连接操作,否则应该不会有明显的差异。
因此,OP 的快速有效的“data.table”风格解决方案实际上取决于问题的维度,即数据集的大小和将执行的搜索次数。 p>
如果两者都很大,以下是一些时间:
数据:
library(data.table)
set.seed(0L)
M <- 1e7
dtKeyed <- data.table(x=1:M, y=2:(M+1)) #R-3.4.4 data.table_1.10.4-3 win-x64
dtNoKey <- copy(dtKeyed)
system.time(setkey(dtKeyed, x, y)) #not free
dtKeyed
nsearches <- 1e3
points <- apply(matrix(sample(M, nsearches*2, replace=TRUE), ncol=2), 1, as.list)
变化:
findPtNoKey <- function() {
lapply(points, function(p) dtNoKey[p, on=names(dtNoKey), .N > 0, nomatch=0])
}
findPtOnKey <- function() {
lapply(points, function(p) dtKeyed[p, on=names(dtKeyed), .N > 0, nomatch=0])
}
findPtKeyed <- function() {
lapply(points, function(p) dtKeyed[p, .N > 0, nomatch=0])
}
library(microbenchmark)
microbenchmark(findPtKeyed(), findPtOnKey(), findPtNoKey(), times=3L)
时间安排:
#rem to add back the timing from setkey into the timing for findPtKeyed
Unit: milliseconds
expr min lq mean median uq max neval
findPtKeyed() 924.6846 928.3025 946.0892 931.9205 956.7914 981.6624 3
findPtOnKey() 1119.9686 1129.5641 1143.4505 1139.1597 1155.1915 1171.2233 3
findPtNoKey() 146186.2216 154934.5463 161016.1277 163682.8709 168431.0807 173179.2905 3
准确性检查:
ref <- findPtNoKey()
identical(findPtKeyed(), ref)
#[1] TRUE
identical(findPtOnKey(), ref)
#[1] TRUE