在for循环中通过`:=`赋值(R data.table)

Mic*_*ico 5 r data.table

我试图在for循环中分配一些新变量(我试图创建具有共同结构的变量,但这些变量取决于子样本)。

我一生都在尝试在示例数据上重现此错误,但我做不到。这是有效的代码,可以理解我要做什么的要点:

DT <- data.table(
  id = rep(1:100, each = 20L),
  period = rep(-9:10, 100L),
  grp = rep(sample(4L, size = 100L, replace = TRUE), each = 20L),
  y = runif(2000, min=0, max=5), key = c("id", "period")
)
DT[ , x := cumsum(y), by = id]
DT2 <- DT[id %in% seq(1, 100, by=2)]
DT3 <- DT[id %in% seq(1, 100, by=3)]

for (dd in list(DT, DT2, DT3)){
  setkey(setkey(dd, grp)[dd[period==0, sum(x), by = grp], x_at_0_by_grp := V1], id, period)
}
Run Code Online (Sandbox Code Playgroud)

这很好用-但是,当我对自己的代码执行此操作时,它会生成无效.internal.selfref警告(并且不会创建我想要的变量):

[.data.table(setkey(dt,treatment)中,dt [posting_rel == 0,sum(current_balance),:通过复制整个表来检测并修复了无效的.internal.selfref,以便:=可以通过引用添加此新列。早些时候,此data.table已由R复制(或使用structure()或类似方法手动创建),避免key <-,names <-和attr <-,这在R中当前(并且很奇怪)可以复制整个数据表,使用set *语法避免复制:?set,?setnames和?setattr。此外,在R <= v3.0.2中,list(DT1,DT2)复制了整个DT1和DT2(R的list() (用于复制命名对象);如果有问题,请升级到R> v3.0.2。如果此消息无济于事,请向datatable-help报告,以便解决根本原因。

实际上,当我仅将数据子集合并到合并中所需的那些列时,它也可以在我的数据上正常工作(尽管不会保存到原始数据集)。

这向我表明这是键控问题,但是我在每个步骤中都明确设置了键。我完全不知道如何从这里调试它,因为除了完整的数据集之外,我无法得到重复的错误。

如果将操作分解为多个步骤,则在合并步骤中会出现错误:

for (dd in list(DT, DT2, DT3)){
  dummy <- dd[period==0, sum(x), by = grp]
  setkey(dd, grp)
  dd[dummy, x_at_0_by_grp := V1] #***ERROR HERE***
  setkey(dd, id, period)
}
Run Code Online (Sandbox Code Playgroud)

快速更新-如果我使用强制转换lapply而不是在for循环内转换,也会产生错误。

有什么想法到底是怎么回事?


更新:我提出了一种解决方法:

nnames <- c("dt", "dt2", "dt3")

dt_list <- list(DT, DT2, DT3)

for (ii in 1:3){
  dummy <- copy(dt_list[[ii]])
  dummy[ , x_at_0_by_grp := sum(x[period == 0]), by=grp]
  assign(nnames[ii], dummy)
}
Run Code Online (Sandbox Code Playgroud)

仍然想了解发生了什么,也许是在这种情况下迭代地分配变量的更好方法。

Fra*_*ank 2

对于 20-30 个条件,将它们保留在列表之外(使用手动名称dt2,如 等)太笨重,所以我假设您将它们全部放在dt_list.

我建议仅使用您正在计算的统计数据制作表格,然后对rbind它们进行 ing:

xxt <- rbindlist(lapply(1:length(dt_list),function(i) 
         dt_list[[i]][,list(cond=i,xx=sum(x[period==0])),by=grp]))
Run Code Online (Sandbox Code Playgroud)

这创造了

    grp cond       xx
 1:   1    1 623.3448
 2:   2    1 784.8438
 3:   4    1 699.2362
 4:   3    1 367.7196
 5:   1    2 323.6268
 6:   4    2 307.0374
 7:   2    2 447.0753
 8:   3    2 185.7377
 9:   1    3 275.4897
10:   4    3 243.0214
11:   2    3 149.6041
12:   3    3 166.3626
Run Code Online (Sandbox Code Playgroud)

如果你真的想要这些变量,你可以轻松地合并回来。例如,对于dt2

myi = 2
setkey(dt_list[[myi]],grp)[xxt[cond==myi,list(grp,xx)]]
Run Code Online (Sandbox Code Playgroud)

这并不能解决您遇到的错误,但我认为这是更好的方法。