열에 지정된 횟수만큼 data.frame의 각 행을 반복합니다.


150
df <- data.frame(var1 = c('a', 'b', 'c'), var2 = c('d', 'e', 'f'),
                 freq = 1:3)

각 행이 'freq'열에 지정된 횟수만큼 반복되도록 위의 data.frame의 처음 두 열을 각 행으로 확장하는 가장 간단한 방법은 무엇입니까?

다시 말해, 이것에서 가십시오 :

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

답변:


169

해결책은 다음과 같습니다.

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

큰! 항상 대괄호를 사용하는 것을 잊어 버립니다. 서브 셋팅 또는 재정렬을 위해 인덱싱을 계속 생각합니다. 나는 훨씬 덜 우아하고 의심 할 여지가없는 다른 솔루션을 가지고있었습니다. 어쨌든 다른 사람들이 비교할 수 있도록 게시 할 수 있습니다.
wkmor1

22
대형의 경우 data.frame보다 효율적으로 교체하는 것입니다 row.names(df)seq.int(1,nrow(df))seq_len(nrow(df)).
Marek

이것은 150 만 행, 5 열로 큰 데이터 프레임에서 환상적으로 작동했습니다. 감사!
gabe

4
이 예제에 대한 솔루션을 1 : 2 하드 코딩하면 1 : ncol (df)가 임의의 데이터 프레임에 적용됩니다.
vladiim

71

오래된 질문, tidyverse의 새로운 동사 :

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

2
깔끔한 솔루션에 감사드립니다. 이러한 솔루션은 일반적으로 "간단하고 읽기 쉬운"기준을 충족합니다.
D. 우즈

45

패키지 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

23

@neilfws의 솔루션은 data.frames에는 훌륭하게 작동 하지만 속성이 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"]

4
다른 대안 :df[rep(seq(.N), freq)][, freq := NULL]
Jaap

다른 대안df[rep(1:.N, freq)][, freq:=NULL]
Dale Kube

4

매우 큰 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 답변보다 나은 방법을 설명 할 수 있습니다. 또는 큰 차이가없는 경우 기존 답변에 주석으로 추가 할 수 있습니다.
Sam Firke

@ SamFirke : 귀하의 의견에 감사드립니다. 이상한, 방금 다시 시도했는데 그런 오류가 발생하지 않습니다. dfOP의 질문에서 원본을 사용 합니까? 다른 대답은 구문 data.table을 사용하여 패키지 를 잘못 사용하기 때문에 더 좋습니다 . "일반적으로 이름이 아닌 숫자로 열을 참조하는 것은 좋지 않습니다." data.frame의 FAQ data.table를 참조하십시오.
vonjd

1
설명 주셔서 감사합니다. 귀하의 코드 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으로 성공적으로 실행되었습니다.
Sam Firke

@ SamFirke : 이것은 실제로 이상합니다. 여기에서도 작동해야하며 왜 그렇지 않은지 모르겠습니다. 질문을 하시겠습니까? 아니면 질문을 하시겠습니까?
vonjd

좋은 생각. 너는 할수 있니? 나는 data.table구문을 모르기 때문에 대답을 판단하는 사람이되어서는 안됩니다.
Sam Firke

4

각 행을 여러 번 반복하는 또 다른 dplyr대안slicefreq

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)

2

또 다른 가능성은 다음을 사용하는 것입니다 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에 작성


1

나는 이것이 사실이 아니라는 것을 알고 있지만 원래 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 = FALSEuncount()
아담
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.