In einer Antwort auf eine andere Frage hat @Marek die folgende Lösung veröffentlicht: https://stackoverflow.com/a/10432263/636656
dat <- structure(list(product = c(11L, 11L, 9L, 9L, 6L, 1L, 11L, 5L,
7L, 11L, 5L, 11L, 4L, 3L, 10L, 7L, 10L, 5L, 9L, 8L)), .Names = "product", row.names = c(NA, -20L), class = "data.frame")
`levels<-`(
factor(dat$product),
list(Tylenol=1:3, Advil=4:6, Bayer=7:9, Generic=10:12)
)
Was als Ausgabe erzeugt:
[1] Generic Generic Bayer Bayer Advil Tylenol Generic Advil Bayer Generic Advil Generic Advil Tylenol
[15] Generic Bayer Generic Advil Bayer Bayer
Dies ist nur der Ausdruck eines Vektors. Um ihn zu speichern, können Sie das noch verwirrendere tun:
res <- `levels<-`(
factor(dat$product),
list(Tylenol=1:3, Advil=4:6, Bayer=7:9, Generic=10:12)
)
Natürlich ist dies eine Art Aufruf der Level-Funktion, aber ich habe keine Ahnung, was hier gemacht wird. Was ist der Begriff für diese Art von Zauberei und wie erhöhe ich meine magischen Fähigkeiten in diesem Bereich?
names<-
und[<-
.structure(...)
Konstrukt anstatt nurdata.frame(product = c(11L, 11L, ..., 8L))
? (Wenn dort etwas Magisches passiert, würde ich es auch gerne einsetzen!)"levels<-"
Funktion: Einefunction (x, value) .Primitive("levels<-")
Art LikeX %in% Y
ist eine Abkürzung für"%in%"(X, Y)
.Antworten:
Die Antworten hier sind gut, aber es fehlt ein wichtiger Punkt. Lassen Sie mich versuchen, es zu beschreiben.
R ist eine funktionale Sprache und mutiert ihre Objekte nicht gern. Zuweisungsanweisungen mit Ersetzungsfunktionen sind jedoch zulässig:
ist äquivalent zu
Der Trick ist, dass dieses Umschreiben von durchgeführt wird
<-
; es wird nicht von gemachtlevels<-
.levels<-
ist nur eine reguläre Funktion, die eine Eingabe nimmt und eine Ausgabe gibt; es mutiert nichts.Eine Konsequenz davon ist, dass gemäß der obigen Regel
<-
rekursiv sein muss:ist
ist
Es ist schön, dass diese rein funktionale Transformation (bis zum Ende, an dem die Aufgabe stattfindet) dem entspricht, was eine Aufgabe in einer imperativen Sprache wäre. Wenn ich mich richtig erinnere, wird dieses Konstrukt in funktionalen Sprachen als Linse bezeichnet.
Sobald Sie jedoch Ersatzfunktionen wie definiert haben
levels<-
, erhalten Sie einen weiteren, unerwarteten Zufall: Sie können nicht nur Zuweisungen vornehmen, sondern haben auch eine praktische Funktion, die einen Faktor berücksichtigt und einen anderen Faktor mit unterschiedlichen Ebenen ausgibt. Es gibt wirklich nichts "Aufgabe"!Der Code, den Sie beschreiben, verwendet also nur diese andere Interpretation von
levels<-
. Ich gebe zu, dass der Namelevels<-
etwas verwirrend ist, weil er eine Aufgabe nahelegt, aber das ist nicht das, was vor sich geht. Der Code richtet einfach eine Art Pipeline ein:Beginnen mit
dat$product
Wandle es in einen Faktor um
Ändern Sie die Ebenen
Speichern Sie das in
res
Persönlich finde ich diese Codezeile wunderschön;)
quelle
Keine Zauberei, so werden (Unter-) Zuweisungsfunktionen definiert.
levels<-
ist ein wenig anders, weil es ein Grundelement ist, die Attribute eines Faktors (unter) zuzuweisen, nicht die Elemente selbst. Es gibt viele Beispiele für diese Art von Funktion:Andere binäre Operatoren können auch so aufgerufen werden:
Jetzt, wo du das weißt, sollte dich so etwas wirklich umhauen:
quelle
`levels<-`(foo,bar)
es dasselbe ist wielevels(foo) <- bar
. Das Beispiel von @ Marek:`levels<-`(as.factor(foo),bar)
ist dasselbe wiefoo <- as.factor(foo); levels(foo) <- bar
.levels<-
ist wirklich nur eine Abkürzung dafürattr<-(x, "levels") <- value
, oder zumindest war es wahrscheinlich so, bis es in ein Primitiv verwandelt und an C-Code übergeben wurde.Der Grund für diese "Magie" ist, dass das "Zuweisungs" -Formular eine echte Variable haben muss, an der gearbeitet werden kann. Und das
factor(dat$product)
war nichts zugeordnet.quelle
within()
undtransform()
call zu ersetzen, wenn das so modifizierte Objekt zurückgegeben und zugewiesen wird.Für Benutzercode frage ich mich, warum solche Sprachmanipulationen so verwendet werden? Sie fragen, was Magie ist, und andere haben darauf hingewiesen, dass Sie die Ersatzfunktion mit dem Namen aufrufen
levels<-
. Für die meisten Menschen ist dies Magie und wirklich die beabsichtigte Verwendung istlevels(foo) <- bar
.Der angezeigte Anwendungsfall ist anders, da er
product
in der globalen Umgebung nicht vorhanden ist und daher immer nur in der lokalen Umgebung des Aufrufs vorhanden ist.levels<-
Daher bleibt die gewünschte Änderung nicht bestehen - es gab keine Neuzuweisung vondat
.Unter diesen Umständen
within()
ist die ideale Funktion zu verwenden. Sie möchten natürlich schreibenin R existiert aber natürlich
product
nicht als Objekt.within()
Umgeht dies, weil es die Umgebung einrichtet, für die Sie Ihren R-Code ausführen möchten, und Ihren Ausdruck in dieser Umgebung auswertet. Das Zuweisen des Rückgabeobjekts aus dem Aufruf zu istwithin()
somit im ordnungsgemäß geänderten Datenrahmen erfolgreich.Hier ist ein Beispiel (Sie müssen keine neuen erstellen
datX
- ich mache das einfach, damit die Zwischenschritte am Ende bleiben).Welches gibt:
Ich habe Mühe zu sehen, wie Konstrukte wie das von Ihnen gezeigte in den meisten Fällen nützlich sind - wenn Sie die Daten ändern möchten, ändern Sie die Daten, erstellen Sie keine weitere Kopie und ändern Sie diese (was alles ist, was der
levels<-
Aufruf schließlich tut ).quelle