Convierta una lista de marcos de datos en un dataframe

Tengo un código que en un lugar termina con una lista de marcos de datos que realmente quiero convertir a un solo gran dataframe.

Obtuve algunos consejos de una pregunta anterior que intentaba hacer algo similar pero más complejo.

Aquí hay un ejemplo de lo que estoy empezando (esto está muy simplificado para la ilustración):

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)) } 

Actualmente estoy usando esto:

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

Otra opción es usar una función plyr:

 df <- ldply(listOfDataFrames, data.frame) 

Esto es un poco más lento que el original:

 > 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 

Mi suposición es que usar do.call("rbind", ...) va a ser el enfoque más rápido que encontrarás a menos que puedas hacer algo como (a) usar matrices en lugar de data.frames y (b) preasignar la matriz final y asignarla en lugar de hacerla crecer.

Editar 1 :

Según el comentario de Hadley, aquí está la última versión de rbind.fill de CRAN:

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

Esto es más fácil que rbind, y marginalmente más rápido (estos tiempos se mantienen en varias ejecuciones). Y por lo que yo entiendo, la versión de plyr en github es incluso más rápida que esto.

A los fines de completar, pensé que las respuestas a esta pregunta requerían una actualización. ” do.call("rbind", ...) que usar do.call("rbind", ...) va a ser el enfoque más rápido que encontrarás …” Probablemente fue cierto para mayo de 2010 y un tiempo después, pero en septiembre de 2011 se introdujo una nueva lista de funciones en el paquete data.table versión 1.8.2, con un comentario que “Esto hace lo mismo que do.call("rbind",l) , pero mucho más rápido”. ¿Cuanto más rápido?

 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 

También hay bind_rows(x, ...) en 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 

bind-plot

Código:

 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) 

Sesión:

 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' 

ACTUALIZACIÓN : Vuelta 31-ene-2018. Corrió en la misma computadora. Nuevas versiones de paquetes. Se agregó semilla para los amantes de las semillas.

enter image description here

 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' 

Cómo se debe hacer en el tidyverse:

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

Aquí hay otra forma en que esto se puede hacer (solo agregarlo a las respuestas porque reduce es una herramienta funcional muy efectiva que a menudo se pasa por alto como reemplazo de los bucles. En este caso particular, ninguno de estos es significativamente más rápido que do.call)

utilizando la base R:

 df <- Reduce(rbind, listOfDataFrames) 

o, usando el tidyverse:

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

Use bind_rows () del paquete dplyr:

 bind_rows(list_of_dataframes, .id = "column_label") 

Lo único que faltan las soluciones con data.table es la columna del identificador para saber de qué dataframe en la lista provienen los datos.

Algo como esto:

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

El parámetro idcol agrega una columna ( .id ) que identifica el origen del dataframe contenido en la lista. El resultado sería similar a esto:

 .id abc 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 

Un visual actualizado para aquellos que quieran comparar algunas de las respuestas recientes (quería comparar la solución de purrr con dplyr). Básicamente, combiné las respuestas de @TheVTM y @rmf.

enter image description here

Código:

 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) 

Información de la sesión:

 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 

Versiones de paquete:

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