raf*_*ira 13 r data.table
这是关于行操作的一个很好的解释data.table
我想到的另一种选择是id
为每一行使用唯一的,然后使用by
参数应用一个函数.像这样:
library(data.table)
dt <- data.table(V0 =LETTERS[c(1,1,2,2,3)],
V1=1:5,
V2=3:7,
V3=5:1)
# create a column with row positions
dt[, rowpos := .I]
# calculate standard deviation by row
dt[ , sdd := sd(.SD[, -1, with=FALSE]), by = rowpos ]
Run Code Online (Sandbox Code Playgroud)
问题:
有没有理由不使用这种方法?也许其他更有效的替代品?
为什么使用by = .I
不起作用?
dt[ , sdd := sd(.SD[, -1, with=FALSE]), by = .I ]
dww*_*dww 17
1)嗯,不使用它的一个原因,至少在这个with=
例子中是性能,以及创建不必要的列.与下面的选项f2相比,它快了近4倍且不需要rowpos列:
dt <- data.table(V0 =LETTERS[c(1,1,2,2,3)], V1=1:5, V2=3:7, V3=5:1)
f1 <- function(dt){
dt[, rowpos := .I]
dt[ , sdd := rowSums(.SD[, 2:4]), by = rowpos ] }
f2 <- function(dt){dt[, sdd := rowSums(dt[, 2:4])]}
library(microbenchmark)
microbenchmark(f1(dt),f2(dt))
# Unit: milliseconds
# expr min lq mean median uq max neval cld
# f1(dt) 3.669049 3.732434 4.013946 3.793352 3.972714 5.834608 100 b
# f2(dt) 1.052702 1.085857 1.154132 1.105301 1.138658 2.825464 100 a
Run Code Online (Sandbox Code Playgroud)
2)关于你的第二个问题,虽然rowsums
不起作用,但dt[, sdd := sum(.SD[, 2:4]), by = .I]
效果很好.鉴于根据dt[, sdd := sum(.SD[, 2:4]), by = 1:NROW(dt)]
".I是等于seq_len(nrow(x))的整数向量",人们可能期望它们是等价的.然而,不同之处在于它?data.table
是用于.I
而不是用于j
,因为它的值是由by
而不是事先评估而返回的.
也可以预期(请参阅上面关于@eddi的问题的评论).I
应该抛出一个错误.但是这不会发生,因为加载by=.I
包会by = .I
在data.table命名空间中创建一个对象,该对象可以从全局环境访问,其值为data.table
.您可以通过.I
在命令提示符下键入来测试它.(请注意,同样适用于NULL
,.I
,.SD
,.EACHI
,和.N
)
.I
# Error: object '.I' not found
library(data.table)
.I
# NULL
data.table::.I
# NULL
Run Code Online (Sandbox Code Playgroud)
这样做的结果就是行为.GRP
等同于.BY
.
3)虽然我们已经在第1部分已经看到,在by = .I
已经有效地循环行的情况下,有比创建rowpos列更快的方法.但是当我们没有快速的行方式时,循环呢?
对循环进行基准测试by = NULL
和rowSums
版本在这里by = rowpos
提供by = 1:NROW(dt)
信息,并证明循环版本比任何一种for
方法都快:
dt <- data.table(V0 = rep(LETTERS[c(1,1,2,2,3)], 1e3), V1=1:5, V2=3:7, V3=5:1)
f.rowpos <- function() {
dt[, rowpos := .I]
dt[, sdd := sum(.SD[, 2:4]), by = rowpos ]
}
f.nrow <- function() {
dt[, sdd := sum(.SD[, 2:4]), by = seq_len(NROW(dt)) ]
}
f.forset<- function() {
for (i in seq_len(NROW(dt))) set(dt, i, 'sdd', sum(dt[i, 2:4]))
}
microbenchmark(f.rowpos(),f.nrow(), f.forset(), times = 5)
# Unit: milliseconds
# expr min lq mean median uq max neval
# f.rowpos() 559.1115 575.3162 580.2853 578.6865 588.5532 599.7591 5
# f.nrow() 558.4327 582.4434 584.6893 587.1732 588.6689 606.7282 5
# f.forset() 1172.6560 1178.8399 1298.4842 1255.4375 1292.7393 1592.7486 5
Run Code Online (Sandbox Code Playgroud)
因此,总而言之,即使在没有优化功能的情况下,例如set()
已经按行运行的功能,也总是可以选择使用更快的行列,而不需要创建冗余列.
归档时间: |
|
查看次数: |
3662 次 |
最近记录: |