data.table:向量扫描v用数字列进行二进制搜索 - 超慢setkey

时间:2013-12-21 14:46:20

标签: r data.table

我正在尝试找到通过几个数字列对大型数据集进行子集化的最快方法。正如data.table所承诺的那样,二进制搜索所花费的时间比矢量扫描要快得多。但是,二进制搜索需要预先执行setkey。正如您在此代码中看到的那样,需要非常长的时间!考虑到这段时间后,矢量扫描要快得多:

set.seed(1)
n=10^7
nums <- round(runif(n,0,10000))
DT = data.table(s=sample(nums,n), exp=sample(nums,n), 
         init=sample(nums,n), contval=sample(nums,n))
this_s = DT[0.5*n,s] 
this_exp = DT[0.5*n,exp]
this_init = DT[0.5*n,init]
system.time(ans1<-DT[s==this_s&exp==this_exp&init==this_init,4,with=FALSE])
#   user  system elapsed 
#   0.65    0.01    0.67 
system.time(setkey(DT,s,exp,init))
#   user  system elapsed 
#  41.56    0.03   41.59 
system.time(ans2<-DT[J(this_s,this_exp,this_init),4,with=FALSE])
#   user  system elapsed 
#    0       0       0 
identical(ans1,ans2)
# [1] TRUE

我做错了吗?我已经阅读了data.table常见问题解答等。非常感谢任何帮助。

非常感谢。

1 个答案:

答案 0 :(得分:5)

该行:

nums <- round(runif(n,0,10000))

nums作为numeric类型而不是integer。这有很大的不同。 data.table常见问题解答和介绍适用于integercharacter列;你不会在这些类型上看到setkey那么慢。例如:

nums <- as.integer(round(runif(n,0,10000)))
...
setkey(DT,s,exp,init)  # much faster now

虽然还有两点......

首先,在data.table v1.8.11的当前开发版本中,排序/排序操作更快。 @jihoward对数字列的排序是一件非常耗时的操作。但是,它仍然在1.8.11中快5-8倍(因为6通道基数顺序实现,请检查this post)。比较1.8.10和1.8.11之间的setkey操作所花费的时间:

# v 1.8.11
system.time(setkey(DT,s,exp,init))
#    user  system elapsed 
#   8.358   0.375   8.844 

# v 1.8.10
system.time(setkey(DT,s,exp,init))
#   user  system elapsed 
# 66.609   0.489  75.216 

我的系统改进了8.5倍。所以,我的猜测是你需要大约4.9秒。

其次,正如@Roland所提到的,如果你的目标是执行几个子集,那就是你要做的所有事情,那么当然做是没有意义的setkey as,它必须找到列的顺序,然后重新排序整个data.table(通过引用使内存占用空间非常小,请在setkey上查看this post以获取更多信息)。