回答:
これが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
data.frame
、より効率的に交換することであるrow.names(df)
とseq.int(1,nrow(df))
かseq_len(nrow(df))
。
@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"]
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
ますdata.table
。「一般に、名前ではなく番号で列を参照することは悪い習慣です」のFAQ を参照してください。
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.frameにうまくスケーリングできません。他の3つの回答は、このより大きな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
vonjdの回答のワンライナーバージョン:
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()