如何通过索引和条件过滤R data.table

时间:2016-03-07 09:41:43

标签: r data.table

请查看以下示例代码。

DT <-data.table(1:15,0,rbinom(15,2,0.5))

我可以按条件DT[V3 == 1,]进行过滤,也可以按索引DT[1:5,]选择行。

我怎么能两个都做?在以下代码中,索引行的序列似乎被忽略:

DT[V3 == 1 & 1:5]

我可以DT[1:5,][V3 == 1],但是,例如,我将无法修改已过滤的行:

DT[1:5,][V3 == 1, V2 := 1]

这仅适用于以下解决方法:

DT[V3 == 1 & DT[,.I <= 5], V2 := 1]

然而,这看起来对我来说也是数据框架。是否有更优雅的方式以及为什么DT[V3 == 1 & 1:5]不起作用?

2 个答案:

答案 0 :(得分:7)

对于@ akrun的例子,这是一个更快的方法:

set.seed(24)
DT <- data.table(1:1e6, 0, rbinom(1e6, 2, 0.5))
DT1 <- copy(DT)
DT2 <- copy(DT)

library(microbenchmark)
microbenchmark( 
    DT1[which(V3[1:5]==1L), V2:= 1], 
    DT2[intersect(which(V3==1), 1:5), V2 := 1]
, times = 1, unit = "relative" )

# Unit: relative
#        expr      min       lq     mean   median       uq      max neval
#  sequential  1.00000  1.00000  1.00000  1.00000  1.00000  1.00000     1
#     set_ops 55.43582 55.43582 55.43582 55.43582 55.43582 55.43582     1

在评估条件之前我们通过索引进行子集的意义上的“顺序”。

概括是

cond = quote(V3 == 1)
indx = 1:5

DT[ DT[indx, indx[eval(cond)]], V2 := 1]
# or
set(DT, i = DT[indx, indx[eval(cond)]], j = "V2", v = 1)

答案 1 :(得分:2)

我们可以尝试

DT[V3==1 & 1:.N %in% 1:5,  V2 := 1]

或另一种选择是

DT[intersect(which(V3==1), 1:5), V2 := 1]

基准

set.seed(24)
DT <- data.table(1:1e6, 0, rbinom(1e6, 2, 0.5))
DT1 <- copy(DT)
DT2 <- copy(DT)

OP的版本

system.time({
 DT[V3 == 1 & DT[,.I <= 5], V2:= 1] 
})
#user  system elapsed 
#0.08    0.00    0.08 

修改选项

system.time({
 DT1[V3==1 & 1:.N %in% 1:5,  V2 := 1]
})
# user  system elapsed 
#  0.14    0.00    0.14 

system.time({
  DT2[intersect(which(V3==1), 1:5), V2 := 1]
})
 # user  system elapsed 
 #  0.05    0.00    0.05