tutorial - rbind data frame r
¿Por qué rbindlist es "mejor" que rbind? (2)
Por v1.9.2
, rbindlist
había evolucionado bastante, implementando muchas características, incluyendo:
- Elegir el
SEXPTYPE
másSEXPTYPE
de columnas durante el enlace: implementado env1.9.2
cerrando FR # 2456 y Bug # 4981 .- Manejo de las columnas de
factor
correctamente: primero implementado env1.8.10
cerrando el Bug # 2650 y ampliado a los factores ordenados de enlace cuidadosamente también env1.9.2
, cerrando FR # 4856 y Bug # 5019 .
Además, en v1.9.2
, rbind.data.table
también ganó un argumento de fill
, que permite enlazar completando columnas faltantes, implementado en R.
Ahora en v1.9.3
, hay incluso 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 unfill
argumento, que por defecto también esFALSE
para compatibilidad con versiones anteriores.- Todas estas características se implementan en C y se escriben cuidadosamente para no comprometer la velocidad al agregar funcionalidades.
- Como
rbindlist
ahora puede coincidir por nombres y completar las columnas que faltan,rbind.data.table
simplemente llama arbindlist
ahora. La única diferencia es queuse.names=TRUE
por defecto pararbind.data.table
, por compatibilidad con versiones anteriores.
rbind.data.frame
ralentiza bastante debido principalmente a las copias (que @mnel señala también) que podrían evitarse (moviéndose a C). Creo que esa no es la única razón. La implementación para verificar / encontrar nombres de columna en rbind.data.frame
también podría ser más lenta cuando hay muchas columnas por data.frame y hay muchos tales data.frames para vincular (como se muestra en el benchmark a continuación).
Sin embargo, esa lista de rbindlist
(ed) ciertas características (como verificar los niveles de factores o los nombres que coinciden) tiene un peso muy pequeño (o nulo) para que sea más rápido que rbind.data.frame
. Es porque fueron implementados cuidadosamente en C, optimizados para velocidad y memoria.
Aquí hay un punto de referencia que resalta el enlace eficiente al mismo tiempo que coincide con los nombres de las columnas utilizando la función v1.9.3
de v1.9.3
de v1.9.3
. El conjunto de datos consta de 10000 marcos de datos de tamaño 10 * 500 cada uno.
require(data.table)
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
# 3.419 0.278 3.718
system.time(ans2 <- rbindlist(ll, use.names=TRUE))
# user system elapsed
# 5.311 0.471 5.914
system.time(ans3 <- do.call("rbind", ll))
# user system elapsed
# 1097.895 1209.823 2438.452
identical(ans2, setDT(ans3)) # [1] TRUE
La vinculación de las columnas como tal sin verificar los nombres tomó 3,7 segundos, mientras que la verificación de los nombres de las columnas y la vinculación de manera apropiada tomaron solo 1,2 segundos más. Comparado con la solución base, esto es> 400x más rápido.
Estoy revisando la documentación de data.table
y también me di cuenta de algunas de las conversaciones aquí en SO que se supone que rbindlist
es mejor que rbind
.
Me gustaría saber por qué rbindlist
es mejor que rbind
y en qué escenarios rbindlist
realmente sobresale sobre rbind
.
¿Hay alguna ventaja en términos de utilización de la memoria?
rbindlist
es una versión optimizada de do.call(rbind, list(...))
, que es conocida por ser lenta cuando se usa rbind.data.frame
¿Dónde realmente sobresale?
Algunas preguntas que muestran dónde brilla rbindlist
son
Fusión vectorizada rápida de la lista de data.frames por fila
Estos tienen puntos de referencia que muestran qué tan rápido puede ser.
rbind.data.frame es lento, por una razón
rbind.data.frame
realiza muchas comprobaciones e rbind.data.frame
por 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 hace este tipo de comprobació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
Solía tener problemas para lidiar con los factors
, debido a un error que desde entonces se ha solucionado:
rbindlist dos data.tables donde uno tiene un factor y otro tiene un tipo de carácter para una columna ( Bug # 2650 )
Tiene problemas con los nombres de columna duplicados
ver Mensaje de advertencia: en rbindlist (allargs): NA introducida por coerción: posible error en data.table? ( Bug # 2384 )
Los nombres de fila rbind.data.frame pueden ser frustrantes
rbindlist
puede manejar las lists
data.frames
y data.tables
, y devolverá una data.table sin rownames
puede obtener un embrollo de nombres de filas usando do.call(rbind, list(...))
ver
¿Cómo evitar el cambio de nombre de filas al usar rbind dentro de do.call?
Eficiencia de memoria
En términos de memoria rbindlist
se implementa en C
, por lo que es eficiente desde el punto de vista de la memoria, usa setattr
para establecer atributos por referencia
rbind.data.frame
se implementa en R
, realiza muchas asignaciones y usa attr<-
(y class<-
y rownames<-
todos los cuales (internamente) crearán copias del data.frame creado.