Je suis en train de parcourir la documentation de data.table
et a également remarqué, d'après certaines conversations tenues ici-même sur SO) que rbindlist
est censé être meilleur que rbind
.
J'aimerais savoir pourquoi rbindlist
est-il meilleur que rbind
et dans quels scénarios rbindlist
excelle vraiment par-dessus rbind
?
Y a-t-il un avantage en termes d'utilisation de la mémoire?
rbindlist
est une version optimisée de do.call(rbind, list(...))
, connue pour être lente lors de l'utilisation de rbind.data.frame
Quelques questions qui montrent où rbindlist
brille
Fusion vectorisée rapide de la liste de data.frames par ligne
Ceux-ci ont des repères qui montrent à quelle vitesse il peut être.
rbind.data.frame
Effectue beaucoup de vérifications et correspondra par nom. (c'est-à-dire que rbind.data.frame tiendra compte du fait que les colonnes peuvent être dans des ordres différents et correspondre par nom), rbindlist
ne fait pas ce type de vérification et joint par position.
par exemple
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
Il avait l'habitude de lutter contre factors
, à cause d'un bogue corrigé depuis:
rbindlist deux data.tables où l'un a un facteur et l'autre a un type de caractère pour une colonne ( Bogue n ° 265 )
Il a des problèmes avec les noms de colonnes en double
voir Message d'avertissement: dans rbindlist (allargs): NA introduites par la contrainte: bogue possible dans data.table? ( Bug # 2384 )
rbindlist
peut gérer lists
data.frames
et data.tables
, et renverra un fichier data.table sans noms de domaine
vous pouvez entrer dans une confusion de noms de noms en utilisant do.call(rbind, list(...))
voir
Comment éviter de renommer des lignes lors de l'utilisation de rbind dans do.call?
En termes de mémoire, rbindlist
est implémenté dans C
, la mémoire est donc efficace, elle utilise setattr
pour définir les attributs par référence.
rbind.data.frame
Est implémenté dans R
, il assigne beaucoup et utilise attr<-
(Et class<-
Et rownames<-
, Ce qui va tous ( en interne) créer des copies du fichier data.frame créé.
Par v1.9.2
, rbindlist
a beaucoup évolué, implémentant de nombreuses fonctionnalités, notamment:
- Choisir le
SEXPTYPE
le plus élevé de colonnes lors de la liaison - implémenté dansv1.9.2
fermeture FR # 2456 et Bug # 4981 .- Manipulation correcte des colonnes
factor
- d'abord implémentée dansv1.8.10
fermant Bug # 2650 et étendu à la reliure ordonnée avec soin dansv1.9.2
également, en fermant FR # 4856 et Bug # 5019 .
De plus, dans v1.9.2
, rbind.data.table
a également obtenu un argument fill
, qui permet de lier en remplissant les colonnes manquantes, implémenté dans R.
Maintenant dans v1.9.3
, il y a encore plus d'améliorations sur ces fonctionnalités existantes:
rbindlist
gagne un argumentuse.names
, qui est par défautFALSE
pour la compatibilité avec les versions antérieures.rbindlist
gagne également un argumentfill
, qui par défaut est égalementFALSE
pour la compatibilité avec les versions antérieures.- Ces fonctionnalités sont toutes implémentées en C et écrites avec soin pour ne pas compromettre la vitesse tout en ajoutant des fonctionnalités.
- Étant donné que
rbindlist
peut désormais correspondre aux noms et remplir les colonnes manquantes,rbind.data.table
appelle simplementrbindlist
maintenant. La seule différence est queuse.names=TRUE
par défaut pourrbind.data.table
, par compatibilité avec les versions antérieures.
rbind.data.frame
ralentit un peu, principalement en raison des copies (ce que @mnel indique également) qui pourraient être évitées (en passant en C). Je pense que ce n'est pas la seule raison. L'implémentation pour vérifier/faire correspondre les noms de colonne dans rbind.data.frame
pourrait également devenir plus lente lorsqu'il y a beaucoup de colonnes par data.frame et qu'il y a beaucoup de telles data.frames à lier (comme indiqué dans le repère ci-dessous).
Cependant, rbindlist
manque (certaines fonctionnalités) (comme la vérification des niveaux de facteurs ou les noms correspondants) a très peu de poids (ou aucun) pour que cela soit plus rapide que rbind.data.frame
. C'est parce qu'ils ont été soigneusement mis en œuvre en C, optimisés pour la vitesse et la mémoire.
Voici un point de repère qui met en évidence l'efficacité de la liaison lors de la mise en correspondance par noms de colonnes, en utilisant également rbindlist
'_ use.names
de v1.9.3
. Le jeu de données est constitué de 10000 données.frames de taille 10 * 500.
NB: ce repère a été mis à jour pour inclure une comparaison avec dplyr
'_ 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 liaison des colonnes en tant que telle sans vérification des noms ne prenait que 1,3, tandis que la vérification des noms de colonnes et la liaison appropriée ne prenaient que 1,5 seconde de plus. Comparé à la solution de base, il est 14 fois plus rapide et 18 fois plus rapide que la version de dplyr
.