"update by reference" vs flache Kopie

8

Die Funktion set oder der Ausdruck := in [.data.table bedeutet, dass die data.table durch Verweis aktualisiert wird. Was ich nicht gut verstehe, ist, wie sich dieses Verhalten von der Neuzuweisung des Ergebnisses einer Operation zum ursprünglichen data.frame unterscheidet.

%Vor%

Da die RHS in dem Ausdruck <- eine flache Kopie des ursprünglichen Datenrahmens in neueren Versionen von R ist, scheinen diese Funktionen ziemlich effizient zu sein. Wie unterscheidet sich diese Basis-R-Methode von der data.table-Entsprechung? Bezieht sich der Unterschied nur auf die Geschwindigkeit oder auch auf den Speicher? Wann ist der Unterschied am größten?

Einige (Geschwindigkeits-) Benchmarks. Es scheint, dass der Geschwindigkeitsunterschied vernachlässigbar ist, wenn das Dataset nur zwei Variablen hat und mit mehr Variablen größer wird.

%Vor%

Nun verstehe ich, dass setkey oder X[Y,:= ] nicht in flachen Kopien ausgedrückt werden kann - also frage ich nur nach dem Erstellen / Löschen neuer Spalten oder Zeilen.

    
Matthew 20.09.2014, 04:56
quelle

1 Antwort

12

In data.table , := und alle set* Funktionen aktualisieren Objekte als Referenz. Dies wurde irgendwann um 2012 IIRC eingeführt. Und zu diesem Zeitpunkt wurde Base R nicht flach kopiert, sondern tief kopiert. Shallow Kopie wurde seit 3.1.0 eingeführt.

Es ist eine wortreiche / langatmige Antwort, aber ich denke, das beantwortet Ihre ersten zwei Fragen:

  

Wie unterscheidet sich diese Basis-R-Methode von der data.table-Entsprechung? Bezieht sich der Unterschied nur auf die Geschwindigkeit oder auch auf den Speicher?

In der Basis R v3.1.0 + wenn wir tun:

%Vor%
  1. Von DF1 bis DF2 werden beide Spalten nur flach kopiert.
  2. Von DF2 bis DF3 musste die Spalte y alleine kopiert / neu zugewiesen werden, aber x wird flach erneut kopiert.
  3. Von DF2 bis DF4 , wie (2).

Das bedeutet, dass Spalten flach kopiert werden, solange die Spalte unverändert bleibt - in gewisser Weise wird die Kopie verzögert, sofern nicht unbedingt erforderlich.

In data.table ändern wir direkt . Das heißt, auch während DF3 und DF4 spalte y wird nicht kopiert.

%Vor%

Da y bereits eine Integer-Spalte ist, und wir sie durch Integer ändern, wird hier keine neue Speicherzuweisung vorgenommen.

Dies ist auch besonders nützlich, wenn Sie Unterverweisen durch Verweis (markiert als (a) oben) möchten. Dies ist eine praktische Funktion, die wir in data.table wirklich mögen.

Ein weiterer Vorteil, den ich aus unseren Interaktionen kennengelernt habe, ist, dass wir alle Spalten einer data.table in einen numeric -Typ konvertieren müssen, zB character Geben Sie Folgendes ein:

%Vor%

Hier, da wir per Referenz aktualisieren, wird jede Zeichenspalte durch den Verweis mit ihrem numerischen Gegenstück ersetzt . Und nach dieser Ersetzung wird die frühere Zeichenspalte nicht mehr benötigt und steht für die Garbage-Collection zur Verfügung. Aber wenn Sie dies mit der Basis R tun würden:

%Vor%

Alle Spalten müssen in numerisch konvertiert werden, und das muss in einer temporären Variable gehalten werden, und schließlich wird wieder DF zugewiesen. Das heißt, wenn Sie 10 Spalten mit jeweils 100 Millionen Zeilen haben, nimmt Ihr DF ein Leerzeichen von:

%Vor%

Und da numeric type doppelt so groß ist, benötigen wir insgesamt 7.4GB + 3.7GB des Platzes, um die Konvertierung mit der Basis R durchzuführen.

Beachten Sie jedoch, dass data.table während DF1 bis DF2 kopiert. Das ist:

%Vor%

führt zu einer Kopie, weil wir nicht durch Verweis auf eine flache Kopie zuordnen können. Es aktualisiert alle Klone.

Was wäre toll, wenn wir nahtlos die flache Kopierfunktion integrieren könnten, aber verfolgen würden, ob die Spalten eines bestimmten Objekts mehrere Referenzen haben, und wo immer möglich durch Referenz aktualisieren. Die verbesserte Referenzzählfunktion von R könnte in dieser Hinsicht sehr nützlich sein. Auf jeden Fall arbeiten wir daran.

Für Ihre letzte Frage:

  

"Wann ist der Unterschied am größten?"

  1. Es gibt immer noch Leute, die ältere Versionen von R benutzen müssen, wo tiefe Kopien nicht vermieden werden können.

  2. Es hängt davon ab, wie viele Spalten kopiert werden, weil die Operationen ausgeführt werden. Worst-Case-Szenario wäre natürlich, dass Sie alle Spalten kopiert haben.

  3. Es gibt Fälle wie diese , bei denen das flache Kopieren nicht von Vorteil ist.

  4. Wenn Sie Spalten einer data.frame für jede -Gruppe aktualisieren möchten und es zu viele Gruppen gibt.

  5. Wenn Sie eine Spalte von say, data.table DT1 basierend auf einem Join mit einer anderen data.table DT2 aktualisieren möchten, können Sie dies wie folgt tun:

    %Vor%

    Dabei steht i. für den Wert aus der Spalte val von DT2 (das Argument i ) für übereinstimmende Zeilen. Diese Syntax ermöglicht die Durchführung dieser Operation sehr effizient, anstatt zuerst das gesamte Ergebnis zu verbinden und dann die erforderliche Spalte zu aktualisieren.

Alles in allem gibt es starke Argumente dafür, dass eine Aktualisierung per Referenz viel Zeit sparen und schnell sein würde. Aber manchmal möchten die Leute Objekte nicht direkt aktualisieren und sind bereit, dafür Geschwindigkeit / Speicher zu opfern. Wir versuchen herauszufinden, wie diese Funktionalität zusätzlich zum bereits vorhandenen Update per Referenz bereitgestellt werden kann.

Hoffe, das hilft. Das ist schon eine ziemlich lange Antwort. Ich hinterlasse alle Fragen, die Sie anderen hinterlassen oder die Sie herausfinden müssen (abgesehen von offensichtlichen Missverständnissen in dieser Antwort).

    
Arun 21.09.2014, 18:25
quelle

Tags und Links