df <- data.frame(var1=c('a', 'b', 'c'), var2=c('d', 'e', 'f'), freq=1:3)
上記のdata.frameの最初の2列を拡張して、各行が 'freq'列で指定された回数だけ表示されるようにする最も簡単な方法は何ですか?
言い換えれば、これから行く:
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
1つのソリューションを次に示します。
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
splitstackshape
パッケージのexpandRows()
を使用します。
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
古い質問、整頓された新しい動詞:
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)
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
プロパティがないため、row.names
sには適していません。このアプローチは両方で機能します:
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"]
非常に大きな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
別の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
vonjd's answerのワンライナーバージョン:
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に作成