tabla - Convertir una lista de marcos de datos en un marco de datos
ver mapa en arcmap (9)
Cómo se debe hacer en el tidyverse:
df.dplyr.purrr <- listOfDataFrames %>% map_df(bind_rows)
Tengo un código que en un lugar termina con una lista de marcos de datos que realmente quiero convertir en un único marco de datos grandes.
Recibí 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 se simplifica enormemente 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)
Con el propósito de ser completo, pensé que las respuestas a esta pregunta requerían una actualización. "Supongo que usar do.call("rbind", ...)
será el enfoque más rápido que encontrará ..." Probablemente fue cierto en mayo de 2010 y algún tiempo después, pero aproximadamente en septiembre de 2011 se introdujo una nueva función rbindlist
en el paquete data.table
versión 1.8.2, con la observación de 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
Esta es otra manera de hacer esto (solo agregándolo a las respuestas porque reduce
es una herramienta funcional muy efectiva que a menudo se pasa por alto como un reemplazo de los bucles. En este caso particular, ninguno de estos es significativamente más rápido que hacer).
utilizando la base R:
df <- Reduce(rbind, listOfDataFrames)
o, usando el tidyverse:
library(tidyverse) # or, library(dplyr); library(purrr)
df <- listOfDataFrames %>% reduce(bind_rows)
Lo único que faltan las soluciones con data.table
es la columna de identificación para saber de qué marco de datos 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 marco de datos contenido en la lista. El resultado se vería en algo como esto:
.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
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 conjetura es que usar do.call("rbind", ...)
será el enfoque más rápido que encontrará a menos que pueda hacer algo como (a) usar matrices en lugar de data.frames y (b) preasignar la matriz final y asignarla a ella en lugar de ampliarla.
Edición 1 :
Basado en 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 ligeramente más rápido (estos tiempos se mantienen durante varias ejecuciones). Y por lo que yo entiendo, la versión de plyr
en github es incluso más rápida que esto.
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
Una imagen visual actualizada para aquellos que desean comparar algunas de las respuestas recientes (yo quería comparar la solución purrr con dplyr). Básicamente combiné respuestas de @TheVTM y @rmf.
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 del paquete:
> packageVersion("tidyverse")
[1] ‘1.1.1’
> packageVersion("data.table")
[1] ‘1.10.0’
Use bind_rows () del paquete dplyr:
bind_rows(list_of_dataframes, .id = "column_label")
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 : Rerun 31-Ene-2018. Corrió en la misma computadora. Nuevas versiones de paquetes. Semillas añadidas para los amantes de las semillas.
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’