Answers:
这是一种解决方案:
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
data.frame
更大的效率,row.names(df)
用seq.int(1,nrow(df))
或代替seq_len(nrow(df))
。
expandRows()
从splitstackshape
包装中使用:
library(splitstackshape)
expandRows(df, "freq")
简单语法,非常快,可以在data.frame
或上使用data.table
。
结果:
var1 var2
1 a d
2 b e
2.1 b e
3 c f
3.1 c f
3.2 c f
@neilfws的解决方案适用于data.frame
s,但不适用于data.table
s,因为它们缺少该row.names
属性。此方法适用于以下两种情况:
df.expanded <- df[rep(seq(nrow(df)), df$freq), 1:2]
的代码data.table
是一点点清洁器:
# convert to data.table by reference
setDT(df)
df.expanded <- df[rep(seq(.N), freq), !"freq"]
df[rep(seq(.N), freq)][, freq := NULL]
df[rep(1:.N, freq)][, freq:=NULL]
如果您必须在非常大的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
Error in rep(1, freq) : invalid 'times' argument
。并且鉴于此问题已经有一个data.table答案,您可能需要描述您的方法与当前data.table答案有何不同或何时更好。或者,如果没有重大区别,则可以将其作为注释添加到现有答案中。
df
OP的原件?我的答案更好,因为另一个答案是data.table
使用data.frame
语法来滥用包,请参阅FAQ data.table
:“通常,以数字而不是名称来引用列是一种不好的做法。”
df
在OP发布的示例中对我有用,但是当我尝试在更大的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))
在微小的data.frame上,基本答案在我的基准测试中效果很好,只是无法很好地扩展到更大的data.frames。其他三个答案与此较大的data.frame一起成功运行。
data.table
语法,所以我不应该作为判断答案的人。
另一种dplyr
选择是slice
,我们将每行重复freq
多次
library(dplyr)
df %>%
slice(rep(seq_len(n()), freq)) %>%
select(-freq)
# var1 var2
#1 a d
#2 b e
#3 b e
#4 c f
#5 c f
#6 c f
seq_len(n())
可以用以下任何一种代替。
df %>% slice(rep(1:nrow(df), freq)) %>% select(-freq)
#Or
df %>% slice(rep(row_number(), freq)) %>% select(-freq)
#Or
df %>% slice(rep(seq_len(nrow(.)), freq)) %>% select(-freq)
另一种可能性是使用tidyr::expand
:
library(dplyr)
library(tidyr)
df %>% group_by_at(vars(-freq)) %>% expand(temp = 1:freq) %>% select(-temp)
#> # A tibble: 6 x 2
#> # Groups: var1, var2 [3]
#> var1 var2
#> <fct> <fct>
#> 1 a d
#> 2 b e
#> 3 b e
#> 4 c f
#> 5 c f
#> 6 c f
library(data.table)
setDT(df)[ ,list(freq=rep(1,freq)),by=c("var1","var2")][ ,freq := NULL][]
#> var1 var2
#> 1: a d
#> 2: b e
#> 3: b e
#> 4: c f
#> 5: c f
#> 6: c f
由reprex软件包(v0.2.1)创建于2019-05-21
我知道不是这种情况,但是如果您需要保留原始的freq列,则可以tidyverse
与rep
以下方法一起使用:
library(purrr)
df <- data.frame(var1 = c('a', 'b', 'c'), var2 = c('d', 'e', 'f'), freq = 1:3)
df %>%
map_df(., rep, .$freq)
#> # A tibble: 6 x 3
#> var1 var2 freq
#> <fct> <fct> <int>
#> 1 a d 1
#> 2 b e 2
#> 3 b e 2
#> 4 c f 3
#> 5 c f 3
#> 6 c f 3
由reprex软件包(v0.3.0)创建于2019-12-21
.remove = FALSE
在uncount()