source

데이터 프레임 목록을 한 행씩 하나의 데이터 프레임으로 결합

nicesource 2023. 4. 24. 23:30
반응형

데이터 프레임 목록을 한 행씩 하나의 데이터 프레임으로 결합

하나의 빅 데이터 프레임으로 변환하고 싶은 데이터 프레임의 리스트가 되는 코드가 있습니다.

나는 비슷하지만 더 복잡한 무언가를 하려고 하는 이전 질문에서 몇 가지 힌트를 얻었다.

다음으로 예를 제시하겠습니다(이것은 일러스트레이션용으로 대폭 간략화되어 있습니다).

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)

사용하다bind_rows()dplyr 패키지:

bind_rows(list_of_dataframes, .id = "column_label")

또 하나의 옵션은 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) 데이터 대신 매트릭스를 사용하고 (b) 최종 매트릭스를 미리 할당하여 할당하지 않고 할당하지 않는 한 가장 빠른 접근법이 됩니다.

편집 1:

해들리의 코멘트를 바탕으로, 여기 최신 버전이 있습니다.rbind.fillCRAN에서:

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

이는 rbind보다 쉽고 약간 더 빠릅니다(이러한 타이밍은 여러 번의 실행에 걸쳐 유지됨).그리고 제가 알기론 on github 버전은 보다 더 빠릅니다.

완성도를 높이기 위해 이 질문에 대한 답변은 업데이트가 필요하다고 생각했습니다."내 추측으로는do.call("rbind", ...)아마 2010년 5월에도 그랬을 것이고, 그 후 얼마 지나지 않아 2011년 9월에 새로운 기능이 등장했습니다.rbindlist에 도입되었습니다.data.table패키지 버전 1.8.2에는 다음과 같은 설명이 붙어 있습니다.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

바인드 플롯

코드:

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’

업데이트: 2021년 11월 18일 재실행.

여기에 이미지 설명 입력

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),
  Reduce("rbind",dflist),
  purrr::map_df(dflist,dplyr::bind_rows),
  times=1000)

ggplot2::autoplot(mb)+theme_bw()

R version 4.1.2 (2021-11-01)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 19043)

>packageVersion("plyr")
[1] ‘1.8.6’
> packageVersion("dplyr")
[1] ‘1.0.7’
> packageVersion("data.table")
[1] ‘1.14.2’
> packageVersion("purrr")
[1] ‘0.3.4’

또 있다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

여기 다른 방법이 있습니다(답장에 추가하는 것만으로 가능).reduce는 매우 효과적인 기능 툴로, 루프를 대체하는 것으로서 자주 간과됩니다.이 경우 어느 쪽도 do.call보다 훨씬 빠르지 않습니다.)

베이스 R 사용:

df <- Reduce(rbind, listOfDataFrames)

또는 tidyverse를 사용하여 다음을 수행합니다.

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

깔끔하게 하는 방법:

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

솔루션이 가지고 있는 유일한 것은data.tableare missing은 데이터가 목록 내의 어느 데이터 프레임에서 왔는지 알기 위한 식별자 컬럼입니다.

다음과 같은 경우:

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  

최근 답변의 일부를 비교하고 싶은 사용자를 위한 최신 비주얼(purr과 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’

★★purrr 1.0.0 는 , 입니다.list_rbind:

library(purrr)
list_rbind(listOfDataFrames, names_to = "column_label")

언급URL : https://stackoverflow.com/questions/2851327/combine-a-list-of-data-frames-into-one-data-frame-by-row

반응형