复制data.frame的每一行,并指定每行的复制次数
df <- data.frame(var1=c('a', 'b', 'c'), var2=c('d', 'e', 'f'), freq=1:3)
什么是最简单的方法来扩大上面的data.frame的前两列,以便每一行出现在“freq”列中指定的次数?
换句话说,从这个angular度来看:
df var1 var2 freq 1 ad 1 2 be 2 3 cf 3
对此:
df.expanded var1 var2 1 ad 2 be 3 be 4 cf 5 cf 6 cf
这里有一个解决scheme:
df.expanded <- df[rep(row.names(df), df$freq), 1:2]
结果:
var1 var2 1 ad 2 be 2.1 be 3 cf 3.1 cf 3.2 cf
使用splitstackshape
包中的expandRows()
:
library(splitstackshape) expandRows(df, "freq")
简单的语法,非常快,适用于data.frame
或data.table
。
结果:
var1 var2 1 ad 2 be 2.1 be 3 cf 3.1 cf 3.2 cf
@ neilfws的解决scheme适用于data.frame
,但不适用于data.table
因为它们缺lessrow.names
属性。 这种方法适用于:
df.expanded <- df[rep(seq(nrow(df)), df$freq), 1:2]
对于data.table
虽然你需要添加with=F
并可以select删除df$
:
dt <- data.table(df) dt.expanded <- dt[rep(seq(.N), freq), !"freq", with=F]
万一你必须在非常大的data.frames上做这个操作,我build议把它转换成一个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
看看这个解决scheme有多快
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