2010-05-24 48 views
76
df <- data.frame(var1=c('a', 'b', 'c'), var2=c('d', 'e', 'f'), freq=1:3) 

什麼是擴大上述data.frame的前兩列最簡單的方法,讓 每一行出現的次數在'freq'欄中指定?複製data.frame中的每一行,並指定副本數爲每行

換句話說,從這個去:

df 
    var1 var2 freq 
1 a d 1 
2 b e 2 
3 c f 3 

要這樣:

df.expanded 
    var1 var2 
1 a d 
2 b e 
3 b e 
4 c f 
5 c f 
6 c f 

回答

106

這裏有一個解決方案:

df.expanded <- df[rep(row.names(df), df$freq), 1:2] 

結果:

var1 var2 
1  a d 
2  b e 
2.1 b e 
3  c f 
3.1 c f 
3.2 c f 
+0

太好了!我總是忘記你可以使用方括號。我一直在想索引只是爲了子集或重新排序。我有另一個遠不那麼優雅的解決方案,毫無疑問效率較低。無論如何,我可能會發帖,以便其他人可以比較。 – wkmor1 2010-05-24 10:30:21

+14

對於大型'data.frame',更高效的是用'seq.int(1,nrow(df))'或'seq_len(nrow(df))'替換'row.names(df)'。 – Marek 2010-05-25 11:54:19

+0

這對於一個大數據框非常奏效 - 150萬行,5列,非常快。謝謝! – gabe 2012-11-21 06:16:34

13

@ neilfws的解決方案適用於data.frame s,但不適用於data.table s,因爲它們缺少row.names屬性。這種方法既適用於:

df.expanded <- df[rep(seq(nrow(df)), df$freq), 1:2] 

對於data.table雖然你將需要添加with=F,可以有選擇地刪除df$

dt <- data.table(df) 
dt.expanded <- dt[rep(seq(.N), freq), !"freq", with=F] 
splitstackshape
+6

'.N'現在可以在'dt []'的第一個參數中訪問,所以你可以使用'dt [rep(seq(.N),freq),!「freq」,= FALSE]或類似的。 – Frank 2015-07-07 21:26:58

+0

謝謝,更新。 – 2016-09-08 22:06:15

+1

另一種選擇:'df [rep(seq(.N),freq)] [,freq:= NULL]' – Jaap 2017-04-10 06:04:40

33

使用expandRows()

library(splitstackshape) 
expandRows(df, "freq") 

簡單的語法非常快,適用於data.framedata.table

結果:

var1 var2 
1  a d 
2  b e 
2.1 b e 
3  c f 
3.1 c f 
3.2 c f 
2

如果你必須做非常大的data.frames我會推薦它轉換成data.table並使用下面這個操作,它應該運行得更快:

library(data.table) 
dt <- data.table(df) 
dt.expanded <- dt[ ,list(freq=rep(1,freq)),by=c("var1","var2")] 
dt.expanded[ ,freq := NULL] 
dt.expanded 

把這個解決方案如何更快的是:

df <- data.frame(var1=1:2e3, var2=1:2e3, freq=1:2e3) 
system.time(df.exp <- df[rep(row.names(df), df$freq), 1:2]) 
## user system elapsed 
## 4.57 0.00 4.56 
dt <- data.table(df) 
system.time(dt.expanded <- dt[ ,list(freq=rep(1,freq)),by=c("var1","var2")]) 
## user system elapsed 
## 0.05 0.01 0.06 
+0

我收到一個錯誤:'rep(1,freq)中的錯誤:'times'argument'無效。並且已經有了數據。表格回答這個問題,你可能想描述你的方法是不同的,或者它比當前的data.table答案更好。或者,如果沒有重大區別,您可以將其添加爲現有答案的評論。 – 2015-07-07 16:20:35

+0

@ SamFirke:謝謝你的評論。奇怪,我只是試了一遍,我沒有這樣的錯誤。你是否使用OP的問題中最初的'df'?我的回答更好,因爲其他答案是通過使用'data.frame'語法來濫用'data.table'包,請參閱'data.table'的常見問題:「通過數字來引用列通常是不好的做法而不是名字。「 – vonjd 2015-07-07 16:37:57

+1

感謝您的解釋。你的代碼適用於OP發佈的樣例'df',但是當我試圖在更大的data.frame上進行基準測試時,我發現了這個錯誤。我使用的data.frame是:'set.seed(1) dfbig < - data.frame(var1 = sample(letters,1000,replace = TRUE),var2 = sample(LETTERS,1000,replace = TRUE),freq = sample(1:10,1000,replace = TRUE))'在微小的數據框架上,基準答案在我的基準測試中效果很好,但它不能很好地適應更大的數據框架。其他三個答案成功運行這個更大的數據框架。 – 2015-07-07 17:06:48

4

老問題,在tidyverse動詞:

library(tidyr) # version >= 0.8.0 
df <- data.frame(var1=c('a', 'b', 'c'), var2=c('d', 'e', 'f'), freq=1:3) 
df %>% 
    uncount(freq) 

Ë

相關問題