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) 

Ë