답변:
해결책은 다음과 같습니다.
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
없기 때문에 s 에는 적합하지 않습니다 row.names
. 이 방법은 두 가지 모두에 적용됩니다.
df.expanded <- df[rep(seq(nrow(df)), df$freq), 1:2]
의 코드 data.table
는 tad cleaner입니다.
# 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.frame으로 확장되지 않습니다. 다른 세 가지 답변은이 더 큰 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()