데이터 프레임 목록을 하나의 데이터 프레임으로 변환


336

한곳에서 하나의 빅 데이터 프레임으로 변환하려는 데이터 프레임 목록으로 끝나는 코드가 있습니다.

비슷한 질문 이지만 복잡한 것을 시도 하는 이전 질문 에서 몇 가지 조언을 얻었습니다 .

다음은 내가 시작하는 것의 예입니다 (이는 설명을 위해 크게 단순화되었습니다).

listOfDataFrames <- vector(mode = "list", length = 100)

for (i in 1:100) {
    listOfDataFrames[[i]] <- data.frame(a=sample(letters, 500, rep=T),
                             b=rnorm(500), c=rnorm(500))
}

나는 현재 이것을 사용하고있다 :

  df <- do.call("rbind", listOfDataFrames)

또한이 질문을보십시오 : stackoverflow.com/questions/2209258/…
Shane

27
do.call("rbind", list)관용구 나뿐만 아니라 전에 사용했던 것입니다. 왜 초기가 필요 unlist합니까?
Dirk Eddelbuettel

5
누군가 나에게 do.call ( "rbind", list)와 rbind (list)의 차이점을 설명 할 수 있습니까? 왜 출력이 동일하지 않습니까?
user6571411

1
@ user6571411 do.call ()은 인수를 하나씩 리턴하지 않지만 목록을 사용하여 함수의 인수를 보유합니다. 참조 https://www.stat.berkeley.edu/~s133/Docall.html
Marjolein Fokkema

답변:


130

dplyr 패키지에서 bind_rows ()를 사용하십시오.

bind_rows(list_of_dataframes, .id = "column_label")

5
좋은 해결책. .id = "column_label"목록 요소 이름을 기반으로 고유 한 행 이름을 추가합니다.
Sibo Jiang

10
2018 년 이래 dplyr빠르고 사용하기 쉬운 도구 이므로이 답변을 수락 된 답변으로 변경했습니다. 몇 년 동안, 그들은 날아간다!
JD Long

186

다른 옵션은 plyr 함수를 사용하는 것입니다.

df <- ldply(listOfDataFrames, data.frame)

원본보다 약간 느립니다.

> system.time({ df <- do.call("rbind", listOfDataFrames) })
   user  system elapsed 
   0.25    0.00    0.25 
> system.time({ df2 <- ldply(listOfDataFrames, data.frame) })
   user  system elapsed 
   0.30    0.00    0.29
> identical(df, df2)
[1] TRUE

내 생각에 do.call("rbind", ...)(a) data.frames 대신 행렬을 사용하고 (b) 최종 행렬을 사전 할당하고 그것을 늘리지 않고 할당하는 것과 같은 작업을 수행 할 수 없다면 사용하는 것이 가장 빠른 접근 방법이 될 것입니다. .

편집 1 :

Hadley의 의견을 바탕으로 rbind.fillCRAN 의 최신 버전은 다음 과 같습니다.

> system.time({ df3 <- rbind.fill(listOfDataFrames) })
   user  system elapsed 
   0.24    0.00    0.23 
> identical(df, df3)
[1] TRUE

이것은 rbind보다 쉽고, 조금 더 빠릅니다 (이러한 타이밍은 여러 번의 실행을 유지합니다). 그리고 내가 이해하는 한, github 의 버전plyr 은 이것보다 훨씬 빠릅니다.


28
최신 버전의 plyr에서 rbind.fill은 do.call 및 rbind
hadley

1
흥미 롭군 나를 위해 rbind.fill이 가장 빠릅니다. 이상하게도, 차이를 찾을 수 있더라도 do.call / rbind는 동일한 TRUE를 반환하지 않았습니다. 다른 두 개는 같지만 plyr이 느 렸습니다.
Matt Bannert

I()data.frame당신의 ldply전화에 대체 할 수 있습니다
baptiste

4
또한 형태가 변경 melt.list되었습니다 (2)
baptiste

do.call(function(...) rbind(..., make.row.names=F), df)자동으로 생성 된 고유 한 행 이름을 원하지 않는 경우에 유용합니다.
smci

111

완전성을 기하기 위해이 질문에 대한 답변을 업데이트해야한다고 생각했습니다. "제 생각에 사용하는 do.call("rbind", ...)것이 가장 빠른 접근 방법이 될 것입니다 ..."아마도 2010 년 5 월과 얼마 후에는 사실 이었지만 2011 년 9 월쯤에 패키지 버전 1.8.2 rbindlist에 새로운 기능 이 도입되었습니다. data.table, "와 동일 do.call("rbind",l)하지만 훨씬 더 빠릅니다"라는 설명이 포함되어 있습니다. 얼마나 빨리?

library(rbenchmark)
benchmark(
  do.call = do.call("rbind", listOfDataFrames),
  plyr_rbind.fill = plyr::rbind.fill(listOfDataFrames), 
  plyr_ldply = plyr::ldply(listOfDataFrames, data.frame),
  data.table_rbindlist = as.data.frame(data.table::rbindlist(listOfDataFrames)),
  replications = 100, order = "relative", 
  columns=c('test','replications', 'elapsed','relative')
  ) 

                  test replications elapsed relative
4 data.table_rbindlist          100    0.11    1.000
1              do.call          100    9.39   85.364
2      plyr_rbind.fill          100   12.08  109.818
3           plyr_ldply          100   15.14  137.636

3
너무 고마워요. 데이터 세트가 ldply길고 녹은 데이터 프레임 을 묶기에는 너무 커져서 머리카락을 뽑았습니다. 어쨌든, 나는 당신의 rbindlist제안 을 사용하여 놀라운 속도를 얻었습니다 .
KarateSnowMachine

11
그리고 완전성을 위해 하나 더 : dplyr::rbind_all(listOfDataFrames)트릭도 할 것입니다.
andyteucher

2
rbindlist열별로 데이터 프레임을 추가 하는 것과 동등한 것이 있습니까? cbindlist와 같은 것?
rafa.pereira

2
@ rafa.pereira 최근 기능 요청이 있습니다 : 함수 cbindlist 추가
Henrik

나는 또한 do.call()18 시간 동안 데이터 프레임 목록에서 실행되었지만 여전히 끝나지 않았기 때문에 머리카락 을 뽑았습니다. 감사합니다 !!!
Graeme Frost

74

바인드 플롯

암호:

library(microbenchmark)

dflist <- vector(length=10,mode="list")
for(i in 1:100)
{
  dflist[[i]] <- data.frame(a=runif(n=260),b=runif(n=260),
                            c=rep(LETTERS,10),d=rep(LETTERS,10))
}


mb <- microbenchmark(
plyr::rbind.fill(dflist),
dplyr::bind_rows(dflist),
data.table::rbindlist(dflist),
plyr::ldply(dflist,data.frame),
do.call("rbind",dflist),
times=1000)

ggplot2::autoplot(mb)

세션:

R version 3.3.0 (2016-05-03)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 7 x64 (build 7601) Service Pack 1

> packageVersion("plyr")
[1]1.8.4> packageVersion("dplyr")
[1]0.5.0> packageVersion("data.table")
[1]1.9.6

업데이트 : 2018 년 1 월 31 일 다시 실행하십시오. 같은 컴퓨터에서 실행했습니다. 새로운 버전의 패키지. 씨앗 애호가를위한 씨앗을 추가했습니다.

여기에 이미지 설명을 입력하십시오

set.seed(21)
library(microbenchmark)

dflist <- vector(length=10,mode="list")
for(i in 1:100)
{
  dflist[[i]] <- data.frame(a=runif(n=260),b=runif(n=260),
                            c=rep(LETTERS,10),d=rep(LETTERS,10))
}


mb <- microbenchmark(
  plyr::rbind.fill(dflist),
  dplyr::bind_rows(dflist),
  data.table::rbindlist(dflist),
  plyr::ldply(dflist,data.frame),
  do.call("rbind",dflist),
  times=1000)

ggplot2::autoplot(mb)+theme_bw()


R version 3.4.0 (2017-04-21)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 7 x64 (build 7601) Service Pack 1

> packageVersion("plyr")
[1]1.8.4> packageVersion("dplyr")
[1]0.7.2> packageVersion("data.table")
[1]1.10.4

업데이트 : 2019 년 8 월 6 일 다시 실행하십시오.

여기에 이미지 설명을 입력하십시오

set.seed(21)
library(microbenchmark)

dflist <- vector(length=10,mode="list")
for(i in 1:100)
{
  dflist[[i]] <- data.frame(a=runif(n=260),b=runif(n=260),
                            c=rep(LETTERS,10),d=rep(LETTERS,10))
}


mb <- microbenchmark(
  plyr::rbind.fill(dflist),
  dplyr::bind_rows(dflist),
  data.table::rbindlist(dflist),
  plyr::ldply(dflist,data.frame),
  do.call("rbind",dflist),
  purrr::map_df(dflist,dplyr::bind_rows),
  times=1000)

ggplot2::autoplot(mb)+theme_bw()

R version 3.6.0 (2019-04-26)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 18.04.2 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/openblas/libblas.so.3
LAPACK: /usr/lib/x86_64-linux-gnu/libopenblasp-r0.2.20.so

packageVersion("plyr")
packageVersion("dplyr")
packageVersion("data.table")
packageVersion("purrr")

>> packageVersion("plyr")
[1]1.8.4>> packageVersion("dplyr")
[1]0.8.3>> packageVersion("data.table")
[1]1.12.2>> packageVersion("purrr")
[1]0.3.2

2
이것은 좋은 대답입니다. 나는 같은 것을 (같은 OS, 동일한 패키지, 그렇지 않은 다른 무작위 화 set.seed) 실행했지만 최악의 성능에서 약간의 차이를 보았습니다. rbindlist실제로 내 결과에서 최고의 최악의 경우뿐만 아니라 가장 대표적인 케이스가 있었다
C8H10N4O2

48

도 있습니다 bind_rows(x, ...)에서 dplyr.

> system.time({ df.Base <- do.call("rbind", listOfDataFrames) })
   user  system elapsed 
   0.08    0.00    0.07 
> 
> system.time({ df.dplyr <- as.data.frame(bind_rows(listOfDataFrames)) })
   user  system elapsed 
   0.01    0.00    0.02 
> 
> identical(df.Base, df.dplyr)
[1] TRUE

기술적으로 말하면 as.data.frame이 필요하지 않습니다-table_df (deplyr의)와는 달리 data.frame을 독점적으로 만드는 모든 것
user1617979

14

여기에 또 다른 방법이 있습니다 ( reduce루프를 대체하는 것으로 종종 간과되는 매우 효과적인 기능 도구 이기 때문에 답변에 추가하기 만하면 됩니다.이 경우에는이 둘 중 어느 것도 do.call보다 훨씬 빠르지 않습니다).

기본 R을 사용하는 경우 :

df <- Reduce(rbind, listOfDataFrames)

또는 tidyverse를 사용하여 :

library(tidyverse) # or, library(dplyr); library(purrr)
df <- listOfDataFrames %>% reduce(bind_rows)

11

tidyverse에서 어떻게 수행해야합니까?

df.dplyr.purrr <- listOfDataFrames %>% map_df(bind_rows)

3
데이터 프레임 목록을 가져올 수 map있다면 왜 사용 bind_rows하시겠습니까?
초에 14

9

최근 답변 중 일부를 비교하고 싶은 사람들을 위해 업데이트 된 시각 자료 (나는 purrr와 dplyr 솔루션을 비교하고 싶었습니다). 기본적으로 @TheVTM과 @rmf의 답변을 결합했습니다.

여기에 이미지 설명을 입력하십시오

암호:

library(microbenchmark)
library(data.table)
library(tidyverse)

dflist <- vector(length=10,mode="list")
for(i in 1:100)
{
  dflist[[i]] <- data.frame(a=runif(n=260),b=runif(n=260),
                            c=rep(LETTERS,10),d=rep(LETTERS,10))
}


mb <- microbenchmark(
  dplyr::bind_rows(dflist),
  data.table::rbindlist(dflist),
  purrr::map_df(dflist, bind_rows),
  do.call("rbind",dflist),
  times=500)

ggplot2::autoplot(mb)

세션 정보 :

sessionInfo()
R version 3.4.1 (2017-06-30)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 7 x64 (build 7601) Service Pack 1

패키지 버전 :

> packageVersion("tidyverse")
[1]1.1.1> packageVersion("data.table")
[1]1.10.0

7

해결책이있는 유일한 것 data.table 이 누락 된 데이터가 목록의 어떤 데이터 프레임에서 나오는지 식별하는 식별자 열입니다.

이 같은:

df_id <- data.table::rbindlist(listOfDataFrames, idcol = TRUE)

idcol매개 변수는 .id목록에 포함 된 데이터 프레임의 원점을 식별 하는 열 ( )을 추가 합니다. 결과는 다음과 같습니다.

.id a         b           c
1   u   -0.05315128 -1.31975849 
1   b   -1.00404849 1.15257952  
1   y   1.17478229  -0.91043925 
1   q   -1.65488899 0.05846295  
1   c   -1.43730524 0.95245909  
1   b   0.56434313  0.93813197  
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.