根据每个组的行索引,对数据表进行子集筛选

4
这似乎是一个我无法找到解决方案的琐碎问题:
考虑这两个数据表:
library(data.table)
dt <- data.table(id = c(1,1,1,2,2,2),
                 val = c(10,20,30,10,20,30))

dt1 <- data.table(id = c(1,2),
                  V1 = c(2,1))

如何对dt进行子集操作,其中dt1告诉我需要对分组后的id的第几行(V1)进行子集操作?

例如,在这个例子中,结果将会是:

#    id val
# 1:  1  20
# 2:  2  10

更新

对提议的解决方案进行了快速基准测试。

library(data.table)
s <- 100000
set.seed(123)
dt <- data.table(id = rep(seq(1:s), each=10),
                 val = rnorm(n = s*10, 0, 1))

dt1 <- data.table(id = seq(1:s),
                  V1 = sample(1:10, s, replace=T))


library(microbenchmark)

microbenchmark(

  akrun = { dt[dt1, on='id'][, .SD[1:.N==V1] ,id] },

  david = { dt[dt1, val[i.V1], on = 'id', by = .EACHI] },

  symbolix = { dt[, id_seq := seq(1:.N), by=id][dt1, on=c(id_seq = "V1", "id") , nomatch=0] },

   times = 5

 )
#Unit: milliseconds
#     expr         min          lq        mean      median          uq         max neval
#    akrun 17809.51370 17887.89037 18005.32357 18043.80279 18130.78978 18154.62118     5
#    david    48.17367    53.76436    53.79004    54.69096    55.59657    56.72467     5
 #symbolix   507.67312   511.23492   562.59743   571.31160   579.61228   643.15525     5
2个回答

6
另一种选择是在连接时使用by = .EACHI来对val进行子集操作。
dt[dt1, val[i.V1], on = 'id', by = .EACHI]
#    id V1
# 1:  1 20
# 2:  2 10

如果有更多的列,您可以使用.SD[i.V1]代替。


顺便说一句,在data.table v >= 1.9.8中,.SD[val]操作将被完全优化为使用GForce,所以请耐心等待。


.SD在1.9.7中已经优化了吗?我有点困惑。 - talat
@docendodiscimus 这个优化是针对显式使用正整数的情况进行的,例如 .SD[2L],但如果像 val <- 2L; .SD[val] 这样将其作为变量传递,则不会进行优化。这个问题应该在 v1.9.8 中得到解决(希望如此)。 - David Arenburg
1
非常好。我一直在苦苦寻找一个.EACHI的解决方案,所以很高兴看到这个! - SymbolixAU

3
一种选择是按'id'进行join on,然后进行子集操作。
dt[dt1, on='id'][, .SD[1:.N==V1] ,id][,V1:=NULL][]
#   id val
#1:  1  20
#2:  2  10

1
在类似的主题上,也许可以使用 dt[, id_seq := seq(1:.N), by=id][dt1, on=c(id_seq = "V1", "id"), nomatch=0](避免 .SD 分配)? - SymbolixAU

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接