Konvertieren Sie einen Datenrahmen in eine data.table ohne Kopie

81

Ich habe einen großen Datenrahmen (in der Größenordnung von mehreren GB), den ich in einen konvertieren möchte data.table. Mit using as.data.tablewird eine Kopie des Datenrahmens erstellt. Dies bedeutet, dass der verfügbare Speicher mindestens doppelt so groß wie die Daten sein muss. Gibt es eine Möglichkeit, die Konvertierung ohne Kopie durchzuführen?

Hier ist ein einfaches Beispiel, um zu demonstrieren:

library(data.table)
N <- 1e6
K <- 1e2
data <- as.data.frame(rep(data.frame(rnorm(N)), K))

gc(reset=TRUE)
tracemem(data)
data <- as.data.table(data)
gc()

Mit Ausgabe:

library(data.table)
# data.table 1.8.10  For help type: help("data.table")
N <- 1e6
K <- 1e2
data <- as.data.frame(rep(data.frame(rnorm(N)), K))

gc(reset=TRUE)
# used  (Mb) gc trigger   (Mb)  max used  (Mb)
# Ncells    303759  16.3     597831   32.0    303759  16.3
# Vcells 100442572 766.4  402928632 3074.2 100442572 766.4
tracemem(data)
# [1] "<0x363fda0>"
data <- as.data.table(data)
# tracemem[0x363fda0 -> 0x31e4260]: copy as.data.table.data.frame as.data.table 
gc()
# used  (Mb) gc trigger   (Mb)  max used   (Mb)
# Ncells    304519  16.3     597831   32.0    306162   16.4
# Vcells 100444242 766.4  322342905 2459.3 200933219 1533.0
ytsaig
quelle

Antworten:

92

Dies ist ab Version 1.9.0 verfügbar . Aus NEWS :

o Nach diesem SO-BeitragsetDT wird nun eine Funktion implementiert, die ein list(benanntes und / oder unbenanntes) data.frame(oder data.table) als Eingabe verwendet und dasselbe Objekt als data.table Referenz zurückgibt (ohne Kopie). Weitere ?setDTBeispiele finden Sie in den Beispielen.

Dies entspricht der data.tableNamenskonvention - alle set*Funktionen werden durch Referenz geändert. :=ist die einzige andere, die ebenfalls durch Bezugnahme geändert wird.

require(data.table) # v1.9.0+
setDT(data) # converts data which is a data.frame to data.table *by reference*

In der Historie finden Sie ältere (jetzt veraltete) Antworten.

Arun
quelle
@Arun: Danke für eine ausführliche Antwort. Ich habe tatsächlich gefragt, wie ein Datenrahmen in eine data.table konvertiert werden soll, war aber beim Erstellen des Spielzeugbeispiels schlampig. Ich werde meine Frage aktualisieren, um daraus einen Datenrahmen zu machen. Funktioniert die gleiche Idee dann für einen Datenrahmen, z. B. die ersten beiden Setattr zu entfernen, da ein Datenrahmen diese bereits hat, und den Rest beizubehalten?
Ytsaig
@YT, wenn Sie meinen, einen "data.frame" in eine "data.table" zu bekommen, dann ist das, was Sie sagen, natürlich richtig. Wenn Sie eine Liste von data.frames meinen, müssen Sie diese (spalten- oder zeilenweise) binden, bevor Sie die Klasse festlegen und zuweisen können.
Arun
@Arun, ich meinte das erstere, einen einzelnen Datenrahmen zu einer Datentabelle, ich habe die Frage bearbeitet, um sie hoffentlich besser wiederzugeben. Nochmals vielen Dank für eine clevere Lösung. Ich kann die Antwort unverändert akzeptieren oder warten, wenn Sie sie bearbeiten möchten, um sie an die überarbeitete Frage anzupassen.
Ytsaig
2
Vielleicht hilft dieser Beitrag von Matthew dabei, mehr Licht ins Dunkel zu bringen truelength.
Arun
3
@eddi Vor R2.14.0 wurde das truelengthMitglied des Vektorkopfs von R nicht von R initialisiert. Wenn Sie in C keine Variable initialisieren, hat sie undefinierten Inhalt (was auch immer sich zuvor in diesem RAM-Block befindet). data.table()und ähnliche Ersteller werden truelengthauf 0 initialisiert , bevor alloc.colKompatibilität mit Pre R 2.14.0 gefordert wird. alloc.colwird truelengthals Eingabe betrachtet (0 bedeutet Kraftlänge == Länge). Irgendwann dachte ich, dass data.table aus diesem Grund von R> = 2.14.0 abhängen müsste, schaffte es aber, R> = 2.12.0 beizubehalten. Ich teste mit R2.12.0 vor jeder Veröffentlichung auf CRAN.
Matt Dowle