2013-02-20 63 views
9

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

dt <- data.table(a=c(1,2,3,3),b=c(1,1,2,2)) 
sdt <- split(dt,dt$b==2) 

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

sdt[[1]][,c:=.N,by=a] 

我碰到下面的警告消息。

警告消息:在[.data.table(SDT [[1]],...,:=(C,.N),通过= A): 通过取整个 的副本检测和固定无效.internal.selfref表,这样:=可以通过引用添加这个新列。在 早些时候,这个data.table已被R复制。避免密钥< - , 名称< - 和attr < - 在R目前(和奇怪)可能复制整个 data.table。使用set *语法来避免复制:setkey(), setnames()和setattr()。此外,列表(DT1,DT2)将复制整个DT1 和DT2(R的list()副本命名对象),如果需要(将实施) ,请使用reflist()。如果此消息无效,请 向datatable-help报告,以便修复根本原因。

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

+3

为什么你要在第一时间分割data.table?分割我们创建一个列表,所以警告处理为什么副本已经发生 – mnel 2013-02-20 10:56:29

+0

我基于时间分割为我的实验创建了两套。 – jamborta 2013-02-20 11:01:09

+0

我很好奇在这种情况下'.N'的含义? – 2013-02-20 11:02:31

回答

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 

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

+1

我不太明白为什么它说'无效.internal.selfref',因为当我做'属性(SDR [[1]])$。internal.selfref',值似乎是' dt'(和'dt2 < - copy(dt)'上的相同)。任何想法? – Arun 2013-02-20 11:29:57

+3

@阿伦正好,这就是为什么它无效。它应该在有效时指向自己。如果你看看'.Internal(inspect(sdt [[1]]))'你应该看到它的指针地址是不同的(一个副本被采用)。这就是'.internal.selfref'被设计用于检测。副本的问题不是复制本身,而是当R进行复制时,它不维护列指针的分配向量。因此,当':='尝试添加一个新列时(它必须再次分配过多),以防万一您有两个绑定到同一个对象。所有正确的和预期的。 – 2013-02-20 11:38:37

+2

@Arun所以这个警告试图说:不要'base :: split'找到其他方式,比如我的答案,做分割。 – 2013-02-20 11:45:20

4

我正在寻找一些方法来做data.table中的拆分,我遇到了这个老问题。

有时候你想要做分割,而data.table“by”方法不方便。

其实你可以轻松地做手工将拆分只data.table指令,它非常有效地工作:

SplitDataTable <- function(dt,attr) { 
    boundaries=c(0,which(head(dt[[attr]],-1)!=tail(dt[[attr]],-1)),nrow(dt)) 
    return(
    mapply(
     function(start,end) {dt[start:end,]}, 
     head(boundaries,-1)+1, 
     tail(boundaries,-1), 
     SIMPLIFY=F)) 
}