Posteriormente a consultar con expertos en la materia, programadores de diversas ramas y maestros dimos con la solución a la interrogande y la plasmamos en esta publicación.
Solución:
rbindlist
es una versión optimizada de do.call(rbind, list(...))
, que es conocido por ser lento al usar rbind.data.frame
¿Dónde realmente se destaca?
Algunas preguntas que muestran dónde rbindlist
brilla son
Fusión rápida vectorizada de la lista de datos fotogramas por fila
Problemas para convertir una lista larga de data.frames (~ 1 millón) a un solo data.frame usando do.call y ldply
Estos tienen puntos de referencia que muestran lo rápido que puede ser.
rbind.data.frame es lento, por una razón
rbind.data.frame
realiza muchas comprobaciones y coincidirá con el nombre. (es decir, rbind.data.frame tendrá en cuenta el hecho de que las columnas pueden estar en diferentes órdenes y coincidir por nombre), rbindlist
no realiza este tipo de verificación y se unirá por posición
p.ej
do.call(rbind, list(data.frame(a = 1:2, b = 2:3), data.frame(b = 1:2, a = 2:3)))
## a b
## 1 1 2
## 2 2 3
## 3 2 1
## 4 3 2
rbindlist(list(data.frame(a = 1:5, b = 2:6), data.frame(b = 1:5, a = 2:6)))
## a b
## 1: 1 2
## 2: 2 3
## 3: 1 2
## 4: 2 3
Algunas otras limitaciones de rbindlist
Eso solía hacerlo lucha para lidiar con factors
, debido a un error que se ha solucionado desde entonces:
rbindlist two data.tables donde uno tiene factor y otro tiene tipo de carácter para una columna (error # 2650)
Tiene problemas con los nombres de columna duplicados.
ver Mensaje de advertencia: en rbindlist (allargs): NA introducidas por coerción: ¿posible error en data.table? (Error # 2384)
Los nombres de fila de rbind.data.frame pueden ser frustrantes
rbindlist
puede manejar lists
data.frames
y data.tables
, y devolverá una tabla de datos sin nombres de fila
puedes meterte en un lío de nombres de filas usando do.call(rbind, list(...))
ver
¿Cómo evitar el cambio de nombre de las filas cuando se usa rbind dentro de do.call?
Eficiencia de la memoria
En términos de memoria rbindlist
se implementa en C
, por lo que la memoria es eficiente, utiliza setattr
para establecer attributes por referencia
rbind.data.frame
se implementa en R
, realiza muchas asignaciones y utiliza attr<-
(y class<-
y rownames<-
todo lo cual (internamente) creará copias del data.frame creado.
Por v1.9.2
, rbindlist
había evolucionado bastante, implementando muchas características que incluyen:
- Elegir el más alto
SEXPTYPE
de columnas mientras se vincula - implementado env1.9.2
cerrando FR # 2456 y Bug # 4981.- Manejo
factor
columnas correctamente - implementado por primera vez env1.8.10
cerrando Bug # 2650 y extendido a vinculante ordenado factores cuidadosamente env1.9.2
también, cerrando FR # 4856 y Bug # 5019.
Además, en v1.9.2
, rbind.data.table
también ganó un fill
argumento, que permite enlazar llenando columnas faltantes, implementado en R.
Ahora en v1.9.3
, hay aún más mejoras en estas características existentes:
rbindlist
gana un argumentouse.names
, que por defecto esFALSE
para compatibilidad con versiones anteriores.rbindlist
también gana un argumentofill
, que por defecto también esFALSE
para compatibilidad con versiones anteriores.- Todas estas características están implementadas en C y escritas cuidadosamente para no comprometer la velocidad al agregar funcionalidades.
- Ya que
rbindlist
ahora puede hacer coincidir por nombres y completar las columnas que faltan,rbind.data.table
solo llamarbindlist
ahora. La única diferencia es queuse.names=TRUE
por defecto pararbind.data.table
, para compatibilidad con versiones anteriores.
rbind.data.frame
se ralentiza bastante principalmente debido a las copias (que @mnel también señala) que podrían evitarse (moviéndose a C). Creo que esa no es la única razón. La implementación para verificar / hacer coincidir los nombres de las columnas en rbind.data.frame
también podría volverse más lento cuando hay muchas columnas por data.frame y hay muchos data.frames para enlazar (como se muestra en el punto de referencia a continuación).
Sin embargo, eso rbindlist
la falta (ed) de ciertas características (como verificar los niveles de los factores o los nombres coincidentes) tiene un peso muy pequeño (o nulo) para que sea más rápido que rbind.data.frame
. Es porque se implementaron cuidadosamente en C, optimizados para velocidad y memoria.
Aquí hay un punto de referencia que destaca el enlace eficiente al mismo tiempo que coincide con los nombres de las columnas y se usa rbindlist
's use.names
característica de v1.9.3
. El conjunto de datos consta de 10000 marcos de datos, cada uno de los cuales tiene un tamaño de 10 * 500.
NB: este punto de referencia se ha actualizado para incluir una comparación con dplyr
's bind_rows
library(data.table) # 1.11.5, 2018-06-02 00:09:06 UTC
library(dplyr) # 0.7.5.9000, 2018-06-12 01:41:40 UTC
set.seed(1L)
names = paste0("V", 1:500)
cols = 500L
foo <- function()
data = as.data.frame(setDT(lapply(1:cols, function(x) sample(10))))
setnames(data, sample(names))
n = 10e3L
ll = vector("list", n)
for (i in 1:n)
.Call("Csetlistelt", ll, i, foo())
system.time(ans1 <- rbindlist(ll))
# user system elapsed
# 1.226 0.070 1.296
system.time(ans2 <- rbindlist(ll, use.names=TRUE))
# user system elapsed
# 2.635 0.129 2.772
system.time(ans3 <- do.call("rbind", ll))
# user system elapsed
# 36.932 1.628 38.594
system.time(ans4 <- bind_rows(ll))
# user system elapsed
# 48.754 0.384 49.224
identical(ans2, setDT(ans3))
# [1] TRUE
identical(ans2, setDT(ans4))
# [1] TRUE
La vinculación de columnas como tal sin verificar los nombres tomó solo 1.3, mientras que la verificación de los nombres de las columnas y la vinculación adecuada tomó solo 1.5 segundos más. En comparación con la solución base, es 14 veces más rápido y 18 veces más rápido que dplyr
versión de.
Eres capaz de sustentar nuestro ensayo añadiendo un comentario o dejando una valoración te estamos agradecidos.