我最近在data.table
发现了二进制搜索。如果表格在多个键上排序,则只能在第二个键上搜索?
DT = data.table(x=sample(letters,1e7,T),y=sample(1:25,1e7,T),rnorm(1e7))
setkey(DT,x,y)
#R> DT[J('x')]
# x y V3
# 1: x 1 0.89109
# 2: x 1 -2.01457
# ---
#384922: x 25 0.09676
#384923: x 25 0.25168
#R> DT[J('x',3)]
# x y V3
# 1: x 3 -0.88165
# 2: x 3 1.51028
# ---
#15383: x 3 -1.62218
#15384: x 3 -0.63601
编辑:感谢@Arun
R> system.time(DT[J(unique(x), 25)])
user system elapsed
0.220 0.068 0.288
R> system.time(DT[y==25])
user system elapsed
0.268 0.092 0.359
答案 0 :(得分:18)
是的,您可以将所有值传递给第一个键值,并使用第二个键的特定值传递子集。
DT[J(unique(x), 25), nomatch=0]
如果您需要在第二个键中使用多个值进行子集(例如,相当于DT[y %in% 25:24]
),则更通用的解决方案是使用CJ
DT[CJ(unique(x), 25:24), nomatch=0]
Note默认情况下CJ
对列进行排序并将键设置为所有列,这意味着结果也会被排序。如果这不合适,您应该使用sorted=FALSE
DT[CJ(unique(x), 25:24, sorted=FALSE), nomatch=0]
还有一项功能请求,以便将来向data.table
添加辅助密钥。我相信计划是添加一个新功能set2key
。
FR#1007 Build in secondary keys
还有merge
,它有data.table
的方法。它为你构建了它内部的二级密钥,所以应该比基础合并更快。请参阅?merge.data.table
。
答案 1 :(得分:6)
基于this email thread我写了以下函数:
create_index = function(dt, ..., verbose = getOption("datatable.verbose")) {
cols = data.table:::getdots()
res = dt[, cols, with=FALSE]
res[, i:=1:nrow(dt)]
setkeyv(res, cols, verbose = verbose)
}
JI = function(index, ...) {
index[J(...),i]$i
}
以下是我的系统上有更大DT(1e8行)的结果:
> system.time(DT[J("c")])
user system elapsed
0.168 0.136 0.306
> system.time(DT[J(unique(x), 25)])
user system elapsed
2.472 1.508 3.980
> system.time(DT[y==25])
user system elapsed
4.532 2.149 6.674
> system.time(IDX_y <- create_index(DT, y))
user system elapsed
3.076 2.428 5.503
> system.time(DT[JI(IDX_y, 25)])
user system elapsed
0.512 0.320 0.831
如果你多次使用索引值得的话。