我发现了一个奇怪的 data.table
行为。我想知道是否有办法避免它或解决方法。
在我的数据管理中,我经常使用 lapply
和 .SD
来为列分配新值。要正确分配几列,必须保持 lapply
的输出列的顺序。
我发现情况并非如此。
这里的正常行为
library(data.table)
plouf <- data.table(x = 1, y = 2, z = 3)
cols <- c("y","x")
plouf[,.SD,.SDcols = cols ,by = z]
plouf[,lapply(.SD,function(x){x}),.SDcols = cols ,by = z]
plouf[,lapply(.SD[x == 1],function(x){x}),.SDcols = cols ,by = z]
所有这些行给出:
z y x
1: 3 2 1
例如,我需要将其重新分配给 c("y","x")。但如果我这样做:
plouf[,lapply(.SD[get("x") == 1],function(x){x}),.SDcols = c("y","x"),by = z]
z x y
1: 3 1 2
这里 x 和 y 的顺序无缘无故改变了,它应该产生与上一个“工作”示例相同的结果。如果然后将错误的值分配给
c("y","x")
如果我将 lapply
的输出分配给新的列向量。好像是在get
的i
部分使用.SD
触发了这个bug。这对分配的影响示例:
plouf[, c(cols ) := lapply(.SD[get("x") == 1],function(x){x}),
.SDcols = cols ,by = z][]
# x y z
# 1: 2 1 3
有没有人有解决方法?我使用的代码看起来更像是:
plouf[, c(cols ) := lapply(.SD[get("x") >= 1 & get("x") <= 3],function(x){mean}),
.SDcols = cols ,by = z]
github 上的问题:https://github.com/Rdatatable/data.table/issues/4089
最佳答案
您可以在 lapply 函数中进行子集化,而不是子集化 .SD
。如果用于子集的逻辑向量作为第三个参数传递给 lapply,则不会在每次 lapply 传递时重新评估。
注意:我将函数更改为乘以 10,否则我根本无法判断代码是否在执行任何操作
plouf[, (cols) := lapply(.SD, function(x, i) 10*mean(x[i]),
get("x") %between% c(1, 3)),
.SDcols = cols ,by = z][]
# x y z
# 1: 10 20 3
还有其他解决方法可以让您对 .SD 进行子集化,但我认为按组对
.SD
进行子集化比单独对每一列进行子集化要慢。set.seed(0)
df <- rep(1:50000, sample(500:1000, 50000, T)) %>%
data.table(a = runif(length(.))
,b = .)
library(microbenchmark)
microbenchmark(
subSD = df[, lapply(.SD[a < .2], sum), b]
, in_func = df[, lapply(.SD, function(x, i) sum(x[i]), a < .2), b]
, times = 10L)
# Unit: milliseconds
# expr min lq mean median uq max neval cld
# subSD 19323.19 20398.3666 21289.345 20708.4346 22466.010 23738.467 10 b
# in_func 972.64 987.7891 1016.252 995.4236 1038.069 1125.709 10 a
编辑:更大的基准
set.seed(0)
rm(df)
df <- rep(1:5e5, sample(50:100, 5e5, T)) %>%
data.table(a = runif(length(.))
,b = .)
library(microbenchmark)
microbenchmark(
subSD = df[, lapply(.SD[a < .2], sum), b]
, in_func = df[, lapply(.SD, function(x, i) sum(x[i]), a < .2), b]
, times = 2L)
# Unit: seconds
# expr min lq mean median uq max neval cld
# subSD 207.111290 207.111290 214.147649 214.147649 221.18401 221.18401 2 b
# in_func 3.560467 3.560467 3.651359 3.651359 3.74225 3.74225 2 a
关于r - data.table 错误 : lapply on . SD 在使用 get() 时对列重新排序。可能的解决方法?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/59176071/