Saltar al contenido

¿Por qué rbindlist es “mejor” que rbind?

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 listsdata.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 en v1.9.2 cerrando FR # 2456 y Bug # 4981.
  • Manejo factor columnas correctamente - implementado por primera vez en v1.8.10 cerrando Bug # 2650 y extendido a vinculante ordenado factores cuidadosamente en v1.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 argumento use.names, que por defecto es FALSE para compatibilidad con versiones anteriores.
  • rbindlist también gana un argumento fill, que por defecto también es FALSE 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 llama rbindlist ahora. La única diferencia es que use.names=TRUE por defecto para rbind.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 dplyrversión de.

Eres capaz de sustentar nuestro ensayo añadiendo un comentario o dejando una valoración te estamos agradecidos.

¡Haz clic para puntuar esta entrada!
(Votos: 2 Promedio: 4)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *