请查看以下示例代码。
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]
不起作用?
答案 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