【问题标题】:Subsetting data.table by 2nd column only of a 2 column key, using binary search not vector scan仅通过 2 列键的第 2 列对 data.table 进行子集,使用二进制搜索而不是矢量扫描
【发布时间】:2013-03-13 22:10:01
【问题描述】:

我最近在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

【问题讨论】:

标签: r data.table


【解决方案1】:

是的,您可以将所有值传递给第一个键值和具有第二个键的特定值的子集。

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

【讨论】:

  • 谢谢,与通常的 data.table 性能相比看起来有点低效,虽然比 R 向量搜索要好...
  • 是的,我想不出更好的方法。但我不认为它打算以这种方式使用,一般来说。例如,如果您检查DF[DF$x == "a" & DF$y == "25", ]DT[J("a", 25)],您会发现区别。
  • 当然,但是你必须重新排序......如果我们想要DF[DF$x == "a" | DF$y == "25", ](OR而不是AND)
  • @Arun 在nomatch=0 中进行了编辑。这是需要的,对吧?以前没有发现。
  • @MatthewDowle 我不知道哪种方法实际上会更好(对于速度和/或添加功能),但named columns in J could define the key to use 将是一个非常实用且强大的选择,再次感谢您的@987654340 @!
【解决方案2】:

基于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     

如果您多次使用索引,这是值得的。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2014-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多