values - rbindlist package




Warum ist rbindlist "besser" als rbind? (2)

Ich gehe durch die Dokumentation von data.table und data.table auch von einigen Gesprächen hier auf SO, dass rbindlist besser sein soll als rbind .

Ich würde gerne wissen, warum rbindlist besser ist als rbind und in welchen Szenarien rbindlist wirklich über rbind ?

Gibt es einen Vorteil in Bezug auf die Speichernutzung?


Bis v1.9.2 rbindlist hat sich rbindlist ziemlich weiterentwickelt und viele Funktionen implementiert, darunter:

  • Auswahl der höchsten SEXPTYPE von Spalten beim Binden - implementiert in v1.9.2 Schließen von FR # 2456 und Bug # 4981 .
  • Handling factor Spalten richtig - zuerst in v1.8.10 implementiert Schließen Bug # 2650 und erweitert, um geordnete Faktoren sorgfältig in v1.9.2 sowie schließen FR # 4856 und Bug # 5019 .

Darüber hinaus hat v1.9.2 in rbind.data.table auch ein rbind.data.table , das es ermöglicht, durch Füllen fehlender Spalten, die in R implementiert sind, zu binden.

Jetzt in v1.9.3 gibt es noch mehr Verbesserungen für diese bestehenden Funktionen:

  • rbindlist erhält ein Argument use.names , das aus use.names der Abwärtskompatibilität standardmäßig FALSE ist.
  • rbindlist erhält auch eine argument fill , die aus rbindlist Abwärtskompatibilität ebenfalls FALSE ist.
  • Diese Funktionen sind alle in C implementiert und sorgfältig geschrieben, um die Geschwindigkeit beim Hinzufügen von Funktionen nicht zu beeinträchtigen.
  • Da rbindlist jetzt nach Namen rbindlist und fehlende Spalten füllen kann, ruft rbindlist jetzt nur noch rbindlist . Der einzige Unterschied ist, dass use.names=TRUE standardmäßig für rbind.data.table , aus rbind.data.table Abwärtskompatibilität.

rbind.data.frame verlangsamt sich ziemlich rbind.data.frame , hauptsächlich aufgrund von Kopien (was @mnel ebenfalls hervorhebt), die vermieden werden könnten (durch Verschieben nach C). Ich denke, das ist nicht der einzige Grund. Die Implementierung zum Überprüfen / rbind.data.frame Spaltennamen in rbind.data.frame könnte auch langsamer werden, wenn es viele Spalten pro data.frame gibt und viele solcher data.frames zu binden sind (wie im Benchmark unten gezeigt).

Allerdings hat diese rbindlist bestimmte Eigenschaften (wie das Überprüfen von Faktorstufen oder übereinstimmenden Namen) nicht oder nur sehr rbind.data.frame da sie schneller als rbind.data.frame . Weil sie sorgfältig in C implementiert wurden, optimiert für Geschwindigkeit und Speicher.

Hier ist ein Benchmark, der die effiziente Bindung hervorhebt, während die rbindlist nach rbindlist auch mit der Verwendung von rbindlist ' use.names Feature ab v1.9.3 . Der Datensatz besteht aus 10000 Datenfeldern mit jeweils der Größe 10 * 500.

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

Das Binden von Spalten als solche, ohne nach Namen zu suchen, dauerte 3,7 Sekunden, wobei das Prüfen auf Spaltennamen und das Binden in geeigneter Weise nur 1,2 Sekunden länger dauerte. Im Vergleich zur Basislösung ist dies> 400x schneller.


rbindlist ist eine optimierte Version von do.call(rbind, list(...)) , die dafür bekannt ist, dass sie langsam ist, wenn sie rbind.data.frame

Wo ist es wirklich herausragend?

Einige Fragen, die zeigen, wo rbindlist glänzt, sind

Schnelle vektorisierte Zusammenführung der Liste von data.frames nach Zeile

Fehler beim Konvertieren einer langen Liste von data.frames (~ 1 Million) in einzelne data.frame mit do.call und ldply

Diese haben Benchmarks, die zeigen, wie schnell es sein kann.

rbind.data.frame ist langsam, aus einem Grund

rbind.data.frame prüft und rbind.data.frame nach dem Namen. (dh rbind.data.frame wird dafür verantwortlich sein, dass die Spalten in verschiedenen Reihenfolgen stehen und mit dem Namen rbindlist ), rbindlist führt diese Art der Überprüfung nicht durch und wird nach Position beitreten

z.B

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

Einige andere Einschränkungen von rbindlist

Aufgrund eines Fehlers, der seither behoben wurde, hatte es früher mit dem Umgang mit factors zu kämpfen:

rbindlist zwei data.tables, wobei einer einen Faktor hat und der andere einen Zeichentyp für eine Spalte hat ( Bug # 2650 )

Es hat Probleme mit doppelten Spaltennamen

siehe Warnmeldung: in rbindlist (allargs): Durch Zwang eingeführte NAs: möglicher Fehler in data.table? ( Fehler # 2384 )

rbind.data.frame rownames kann frustrierend sein

rbindlist kann die lists data.frames und data.tables und gibt eine data.table ohne rownames zurück

Mit do.call(rbind, list(...)) siehst du eine Mischung aus do.call(rbind, list(...))

Wie vermeidet man das Umbenennen von Zeilen bei der Verwendung von rbind in do.call?

Speichereffizienz

In Bezug auf Speicher ist rbindlist in C implementiert, also ist Speicher effizient, es verwendet setattr , um Attribute durch Referenz zu setzen

rbind.data.frame ist in R implementiert, führt viele Zuweisungen aus und verwendet attr<- (und class<- und rownames<- alle werden Kopien des erstellten data.frame (intern) erstellen.





rbindlist