Wie behandelt R Objekt im Funktionsaufruf?

8

Ich habe Hintergrund von Java und Python und lerne in letzter Zeit R.

Heute habe ich herausgefunden, dass R Objekte anders als Java und Python zu behandeln scheint.

Zum Beispiel der folgende Code:

%Vor%

Der Code gibt das folgende Ergebnis:

%Vor%

Aber ich erwarte, dass die zweite Ausgabezeile "4" ist, da ich den Vektor in der Sapply-Funktion geändert habe.

Bedeutet dies, dass R Kopien von Objekten im Funktionsaufruf anstelle von Referenz auf die Objekte erstellt?

    
Spirit Zhang 24.09.2011, 05:37
quelle

5 Antworten

18

x ist in der globalen Umgebung definiert, nicht in Ihrer Funktion.

Wenn Sie versuchen, ein nicht-lokales Objekt wie x in einer Funktion zu ändern, erstellt R eine Kopie des Objekts und ändert die Kopie so, dass jedes Mal, wenn Sie Ihre anonyme Funktion ausführen, eine Kopie von x erstellt wird Ihre i-te Komponente wird auf 4 gesetzt. Wenn die Funktion beendet wird, verschwindet die erstellte Kopie für immer. Das ursprüngliche x wird nicht geändert.

Wenn wir x[i] <<- i schreiben oder wenn wir x[i] <- 4; assign("x", x, .GlobalEnv) schreiben würden, würde R es zurückschreiben. Eine andere Möglichkeit, es zurückzuschreiben, wäre, e auf die Umgebung zu setzen, in der x gespeichert ist, und dies zu tun:

%Vor%

oder möglicherweise das:

%Vor%

Normalerweise schreibt man solchen Code nicht in R. Stattdessen erzeugt man das Ergebnis als Ausgabe der Funktion wie folgt:

%Vor%

(Eigentlich könnte man in diesem Fall x[] <- 4 schreiben.)

HINZUGEFÜGT:

Wenn Sie das -Protopaket verwenden, können Sie dies tun, wenn die Methode f die i-te Komponente der Eigenschaft x auf 4 setzt .

%Vor%

HINZUGEFÜGT:

Oben wurde eine weitere Option hinzugefügt, in der explizit die Umgebung übergeben wird, in der x gespeichert ist.

    
G. Grothendieck 24.09.2011, 11:47
quelle
7

Ja, du hast Recht. Überprüfen Sie die R-Sprachdefinition: 4.3.3 Bewertung der Argumente

>

AFAIK, R kopiert die Daten nicht wirklich, bis Sie versuchen, sie zu modifizieren, und folgen dabei der Kopie -on-write Semantik.

    
Anatoliy 24.09.2011 06:09
quelle
3

Das x innerhalb der anonymen Funktion ist nicht das x in der globalen Umgebung (Ihr Arbeitsbereich). Es ist eine Kopie von x , lokal für die anonyme Funktion. Es ist nicht so einfach zu sagen, dass R Objekte in Funktionsaufrufen kopiert; R wird versuchen, nicht zu kopieren, wenn es möglich ist, obwohl, sobald Sie etwas geändert haben, R das Objekt kopieren muss.

Da @DWin darauf hinweist, dass diese kopierte Version von x , die geändert wurde ist , wird vom sapply() -Aufruf zurückgegeben, Ihre angegebene Ausgabe ist nicht das, was ich bekomme:

%Vor%

Natürlich hat der Code fast das getan, was Sie dachten. Das Problem ist, dass die Ausgabe von sapply() keinem Objekt zugewiesen wurde und daher gedruckt und daher verworfen wird.

Der Grund, warum der Code funktioniert, liegt an den Scoping-Regeln von R. Sie sollten wirklich alle Objekte, die die Funktion benötigt, als Argumente übergeben. Wenn R jedoch kein lokales Objekt für die Funktion finden kann, durchsucht es die übergeordnete Umgebung nach einem Objekt, das mit dem Namen übereinstimmt, und gegebenenfalls mit dem übergeordneten Element dieser Umgebung, um schließlich die globale Umgebung, den Arbeitsbereich, zu treffen. Ihr Code funktioniert also, weil er schließlich ein x gefunden hat, mit dem gearbeitet wurde, aber er wurde sofort kopiert, und diese Kopie wurde am Ende des sapply() -Aufrufs zurückgegeben.

Dieser Kopiervorgang benötigt in vielen Fällen Zeit und Speicher. Dies ist einer der Gründe, warum Leute denken, dass for -Schleifen in R langsam sind; Sie reservieren keinen Speicher für ein Objekt, bevor sie mit einer Schleife gefüllt werden. Wenn Sie keinen Speicher zuweisen, muss R das Objekt ändern / kopieren, um das nächste Ergebnis der Schleife hinzuzufügen.

Auch hier ist es nicht immer so einfach, überall in R, zum Beispiel in Umgebungen, in denen eine Kopie einer Umgebung wirklich nur auf die ursprüngliche Version verweist:

%Vor%

Wenn Sie diese Dinge verstehen, lesen Sie das Handbuch zur R-Definition deckt viele der Details ab, was in R unter der Haube passiert.

    
Gavin Simpson 24.09.2011 18:09
quelle
0

Sie müssen die Ausgabe von sapply einem Objekt zuweisen, andernfalls verschwindet es einfach. (Tatsächlich können Sie es wiederherstellen, da es auch .Last.value zugewiesen wird)

%Vor%     
42- 24.09.2011 06:44
quelle
0

Wenn Sie ein "globales" Objekt innerhalb einer Funktion ändern möchten, können Sie eine nicht-lokale Zuweisung verwenden.

%Vor%

Obwohl in diesem speziellen Fall Sie es kompakter als x[]<-4

haben könnten

Das ist übrigens eine der netten Eigenschaften von R - anstelle von sapply(1:10,function(i) x[i] <<- 4 oder for(i in 1:10) x[i]<-4 ( for ist keine Funktion, also brauchst du <<- hier nicht) kannst du schreibe einfach x[]<-4 :)

    
lebatsnok 19.09.2013 20:50
quelle

Tags und Links