2013-02-20 85 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)) 
}