拆分data.table

jam*_*rta 10 r data.table

我有一个data.table,我想分成两个.我这样做如下:

dt <- data.table(a=c(1,2,3,3),b=c(1,1,2,2))
sdt <- split(dt,dt$b==2)
Run Code Online (Sandbox Code Playgroud)

但如果我想将这样的事情作为下一步

sdt[[1]][,c:=.N,by=a]
Run Code Online (Sandbox Code Playgroud)

我收到以下警告信息.

警告消息:在[.data.table(sdt [[1]] ,, :=(c,.N),by = a):通过获取整个表的副本检测并修复无效的.internal.selfref,以便:=可以添加这个新的列引用.在较早的时候,这个data.table已经被R复制了.避免键< - ,名称< - 和attr < - 当前(并且奇怪地)在R中可以复制整个data.table.使用set*语法来避免复制:setkey(),setnames()和setattr().此外,list(DT1,DT2)将复制整个DT1和DT2(R的list()复制命名对象),如果需要(将被实现)使用reflist().如果此消息没有帮助,请向datatable-help报告,以便修复根本原因.

只是想知道是否有更好的方法来分割表,以便它更有效(并且不会得到这个消息)?

Mat*_*wle 10

这适用于v1.8.7(也可能在v1.8.6中工作):

> sdt = lapply(split(1:nrow(dt), dt$b==2), function(x)dt[x])
> sdt
$`FALSE`
   a b
1: 1 1
2: 2 1

$`TRUE`
   a b
1: 3 2
2: 3 2

> sdt[[1]][,c:=.N,by=a]     # now no warning
> sdt
$`FALSE`
   a b c
1: 1 1 1
2: 2 1 1

$`TRUE`
   a b
1: 3 2
2: 3 2
Run Code Online (Sandbox Code Playgroud)

但是,正如@mnel所说,这是低效的.如果可能,请避免分裂.

  • @Arun完全正确,这就是为什么它无效.它应该在有效时指向自己.如果你看`.Internal(inspect(sdt [[1]]))`你应该看到它的指针地址不同(复制了).这就是`.internal.selfref`旨在检测的东西.副本的问题不在于复制本身,而是当R执行该复制时,它不会维护过度分配的列指针向量.因此,当`:=`尝试添加新列(它必须再次重新分配)时,如果您有两个绑定到同一对象,则会发出警告.一切正确和有意. (3认同)
  • 一如既往,感谢真棒和耐心的解释! (3认同)
  • @Arun所以警告是试图说:不要`base :: split`找到其他方式,比如我的回答,做分裂. (2认同)
  • @Arun还有`data.table ::: selfrefok(sdt [[1]])`,它检查`.internal.selfref`是否有效.返回0/1.故意不出口,因为它只是用于调试/检查. (2认同)