Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
R data.table bug:lappy on.SD在使用get()时对列重新排序。可能的解决办法?_R_Data.table - Fatal编程技术网

R data.table bug:lappy on.SD在使用get()时对列重新排序。可能的解决办法?

R data.table bug:lappy on.SD在使用get()时对列重新排序。可能的解决办法?,r,data.table,R,Data.table,我发现data.table的一个奇怪行为。我想知道是否有办法避免它,或者有一个解决办法 在我的数据管理中,我经常使用lappy和.SD为列分配新值。要正确分配多个列,必须保持lappy的输出列的顺序。 我发现情况并非如此 这里是正常的行为 library(data.table) plouf <- data.table(x = 1, y = 2, z = 3) cols <- c("y","x") plouf[,.SD,.SDcols = cols ,by = z] plouf[,la

我发现
data.table的一个奇怪行为。我想知道是否有办法避免它,或者有一个解决办法

在我的数据管理中,我经常使用
lappy
.SD
为列分配新值。要正确分配多个列,必须保持
lappy
的输出列的顺序。 我发现情况并非如此

这里是正常的行为

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]
例如,我需要重新分配给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的顺序毫无理由地改变了,这时它应该产生与上一个“工作”示例相同的结果。如果将
lappy
的输出分配给新的列向量,则将错误的值分配给
c(“y”,“x”)
。似乎在
.SD
i
部分中使用
get
会触发此错误

这对分配的影响示例:

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]

plouf[,c(cols):=lappy(.SD[get(“x”)>=1&get(“x”)而不是subseting
.SD
,您可以在lappy函数中进行子集设置。如果用于子集设置的逻辑向量作为第三个参数传递给lappy,则不会在每次lappy传递时重新计算

注意:我将函数改为乘以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)
df%
data.table(a=runif(长度()
,b=)
图书馆(微基准)
微基准(
subSD=df[,lapply(.SD[a<.2],和),b]
,in_func=df[,lapply(.SD,函数(x,i)和(x[i]),a<.2),b]
,次=10L)
#单位:毫秒
#expr最小lq平均uq最大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 
set.seed(0)
rm(df)
df%
data.table(a=runif(长度()
,b=)
图书馆(微基准)
微基准(
subSD=df[,lapply(.SD[a<.2],和),b]
,in_func=df[,lapply(.SD,函数(x,i)和(x[i]),a<.2),b]
,次=2L)
#单位:秒
#expr最小lq平均uq最大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

在github的bug报告中,@jangoreki建议:


作为一种解决方法,您可以使用“现在替换”而不是“获取”

就我个人而言,我会经常使用它,而不是作为一种解决办法,我发现R元编程特性更优越。 还要注意,有一天我们应该能够使用
.var
,而不是
get(var)
,请参见(#2816,#3199) 多亏了保守的向后兼容R代码开发,R元编程一直有效,而且我认为它也将一直有效


我投票将这个问题作为离题题来结束,因为更适合于at而不是
get(“x”)==1
您可以使用
eval(替换(v==1,list(v=as.symbol(“x”)))
。这避免了这个问题。@zx8754我将在那里发布,但我的帖子的想法是获得一个workaround@denis
.SD[[“x”]]%介于%c(1,3)之间
。也许可以更新你的帖子,明确你正在寻找解决方法,并在你的github问题报告中添加链接?@denis没问题,社区不需要同意我的投票。只是想带上这个“bug”引起开发人员的注意。在这里,这样做将为您提供一个解决方案,而不是一个解决方案。非常感谢。我不知道我可以这样写,我非常喜欢它
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 
var = "x"
expr = substitute(
  plouf[, c(cols) := lapply(.SD[.var == 1],function(x){x}), .SDcols = cols, by = z][],
  list(.var=as.name(var))
)
print(expr)
#plouf[, `:=`(c(cols), lapply(.SD[x == 1], function(x) {
#    x
#})), .SDcols = cols, by = z][]
eval(expr)
#   x y z
#1: 2 1 3