Je passe en data.table
documentation de data.table
et data.table
également remarqué, dans certaines conversations ici sur SO, que rbindlist
est censé être meilleur que rbind
.
Je voudrais savoir pourquoi rbindlist
est meilleur que rbind
et dans quels scénarios rbindlist
excelle vraiment sur 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
Certaines questions montrent où rbindlist
brille sont
Fusion vectorisée rapide de la liste de data.frames par ligne
Problème lors de la conversion de la longue liste de data.frames (~ 1 million) en simple data.frame en utilisant do.call et ldply
Ceux-ci ont des repères qui montrent à quelle vitesse il peut être.
rbind.data.frame
fait beaucoup de vérifications et correspondra par nom. (c.-à-d. que rbind.data.frame tiendra compte du fait que les colonnes peuvent être dans des ordres différents et correspondent par nom), rbindlist
ne fait pas ce genre de vérification et se joindra par position
par exemple
do.call(rbind, list(data.frame(a = 1:2, b = 2:3), data.frame(b = 1:2, a = 2:3))) ## ab ## 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))) ## ab ## 1: 1 2 ## 2: 2 3 ## 3: 1 2 ## 4: 2 3
Il avait l’ habitude de lutter contre les factors
, à cause d’un bug qui a depuis été corrigé:
rbindlist deux data.tables où l’un a un facteur et l’autre un type de caractère pour une colonne ( bogue n ° 2650 )
Il a des problèmes avec les noms de colonnes en double
voir Message d’avertissement: dans rbindlist (allargs): NA introduits par coercition: bogue possible dans data.table? ( Bogue n ° 2384 )
rbindlist
peut gérer les lists
data.frames
et data.tables
, et renverra un data.table sans nom de domaine
vous pouvez entrer dans un mélange de noms de domaine en utilisant do.call(rbind, list(...))
see
Comment éviter de renommer des lignes lors de l’utilisation de rbind dans do.call?
En termes de mémoire, rbindlist
est implémenté en C
, donc efficace en mémoire, il utilise setattr
pour définir les atsortingbuts par référence
rbind.data.frame
est implémenté dans R
, il fait beaucoup d’atsortingbutions et utilise attr<-
(et class<-
et rownames<-
qui créeront (en interne) des copies du data.frame créé.
En v1.9.2
, rbindlist
avait beaucoup évolué, mettant en œuvre de nombreuses fonctionnalités, notamment:
- Choisir le plus haut
SEXPTYPE
de colonnes lors de la liaison – implémenté dans lav1.9.2
fermant FR # 2456 et le bogue # 4981 .- Traitement correct des colonnes de
factor
– implémentées pour la première fois dans lav1.8.10
fermant le bogue n ° 2650 et en étendant soigneusement les facteurs ordonnés à lav1.9.2
dans lav1.9.2
, en fermant les n ° 4856 et 5019 .
De plus, dans v1.9.2
, rbind.data.table
également obtenu un argument de fill
, qui permet de se lier en remplissant les colonnes manquantes, implémentées dans R.
Maintenant dans la 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 rétrocompatibilité.rbindlist
également unfill
argument, qui est également par défautFALSE
pour la compatibilité ascendante.- 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.
- Comme
rbindlist
peut maintenant 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
, pour une compatibilité ascendante.
rbind.data.frame
ralentit un peu, principalement à cause des copies (que @mnel indique également) qui pourraient être évitées (en passant à C). Je pense que ce n’est pas la seule raison. L’implémentation de la vérification / correspondance des noms de colonne dans rbind.data.frame
pourrait aussi être plus lente lorsqu’il y a beaucoup de colonnes par data.frame et que beaucoup de ces data.frames sont liés (comme indiqué dans le benchmark ci-dessous).
Cependant, cette rbindlist
manque (ed) de certaines fonctionnalités (comme la vérification des niveaux de facteurs ou des noms correspondants) qui pèsent très peu (ou pas) rbind.data.frame
elle est plus rapide que rbind.data.frame
. C’est parce qu’ils ont été soigneusement implémentés en C, optimisés pour la vitesse et la mémoire.
Voici un test qui met en évidence l’efficacité de la liaison lors de la mise en correspondance avec les noms de colonnes, en utilisant la fonctionnalité v1.9.3
de v1.9.3
de la version v1.9.3
. Le jeu de données comprend 10000 data.frames de 10 * 500 chacun.
NB: ce benchmark a été mis à jour pour inclure une comparaison avec dplyr
de 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
Les colonnes de liaison en tant que telles sans vérification des noms ne prenaient que 1,3, car la vérification des noms de colonnes et de la liaison ne prenait que 1,5 seconde de plus. Par rapport à la solution de base, cela est 14 fois plus rapide et 18 fois plus rapide que la dplyr
de dplyr
.