Kann die Mutation verwendet werden, wenn die Mutation bedingt ist (abhängig von den Werten bestimmter Spaltenwerte)?
Dieses Beispiel zeigt, was ich meine.
structure(list(a = c(1, 3, 4, 6, 3, 2, 5, 1), b = c(1, 3, 4,
2, 6, 7, 2, 6), c = c(6, 3, 6, 5, 3, 6, 5, 3), d = c(6, 2, 4,
5, 3, 7, 2, 6), e = c(1, 2, 4, 5, 6, 7, 6, 3), f = c(2, 3, 4,
2, 2, 7, 5, 2)), .Names = c("a", "b", "c", "d", "e", "f"), row.names = c(NA,
8L), class = "data.frame")
a b c d e f
1 1 1 6 6 1 2
2 3 3 3 2 2 3
3 4 4 6 4 4 4
4 6 2 5 5 5 2
5 3 6 3 3 6 2
6 2 7 6 7 7 7
7 5 2 5 2 6 5
8 1 6 3 6 3 2
Ich hatte gehofft, mit dem Paket dplyr eine Lösung für mein Problem zu finden (und ja, ich weiß, dass dieser Code nicht funktionieren sollte, aber ich denke, er macht den Zweck klar), um eine neue Spalte g zu erstellen:
library(dplyr)
df <- mutate(df,
if (a == 2 | a == 5 | a == 7 | (a == 1 & b == 4)){g = 2},
if (a == 0 | a == 1 | a == 4 | a == 3 | c == 4) {g = 3})
Das Ergebnis des gesuchten Codes sollte dieses Ergebnis in diesem speziellen Beispiel haben:
a b c d e f g
1 1 1 6 6 1 2 3
2 3 3 3 2 2 3 3
3 4 4 6 4 4 4 3
4 6 2 5 5 5 2 NA
5 3 6 3 3 6 2 NA
6 2 7 6 7 7 7 2
7 5 2 5 2 6 5 2
8 1 6 3 6 3 2 3
Hat jemand eine Idee, wie man das in dplyr macht? Dieser Datenrahmen ist nur ein Beispiel, die Datenrahmen, mit denen ich es zu tun habe, sind viel größer. Aufgrund seiner Geschwindigkeit habe ich versucht, dplyr zu verwenden, aber vielleicht gibt es andere, bessere Möglichkeiten, um dieses Problem zu lösen?
dplyr::case_when()
ist viel klarer als einifelse
,Antworten:
Verwenden
ifelse
Hinzugefügt - if_else: Beachten Sie, dass in dplyr 0,5 gibt es eine ist
if_else
Funktion definiert , um eine Alternative zu ersetzen wäreifelse
mitif_else
; Beachten Sie jedoch, dass daif_else
strenger ist alsifelse
(beide Beine der Bedingung müssen den gleichen Typ haben), so dass dasNA
in diesem Fall durch ersetzt werden müssteNA_real_
.Hinzugefügt - case_when Da diese Frage gestellt wurde, hat dplyr hinzugefügt,
case_when
sodass eine andere Alternative wäre:Hinzugefügt - arithmetic / na_if Wenn die Werte numerisch sind und sich die Bedingungen (mit Ausnahme des Standardwerts von NA am Ende) gegenseitig ausschließen, wie dies in der Frage der Fall ist, können wir einen arithmetischen Ausdruck verwenden, sodass jeder Term multipliziert wird durch das gewünschte Ergebnis mit
na_if
am Ende verwenden, um 0 durch NA zu ersetzen.quelle
NA
die Zeilen, die die Bedingungen nicht erfüllen, einfach gleich bleiben sollen?mutate(g = ifelse(condition1, 2, ifelse(condition2, 3, g))
Da Sie nach anderen besseren Möglichkeiten zur Lösung des Problems fragen, verwenden Sie eine andere Möglichkeit
data.table
:Beachten Sie, dass die Reihenfolge der bedingten Anweisungen umgekehrt ist, um
g
korrekt zu sein.g
Selbst während der zweiten Aufgabe wird keine Kopie erstellt - sie wird an Ort und Stelle ersetzt .Bei größeren Daten hat dies eine bessere Leistung als die Verwendung von verschachtelten Daten
if-else
, da sowohl Ja- als auch Nein-Fälle ausgewertet werden können und das Verschachteln IMHO schwieriger zu lesen / zu warten ist.Hier ist ein Benchmark für relativ große Datenmengen:
Ich bin mir nicht sicher, ob dies eine Alternative ist, nach der Sie gefragt haben, aber ich hoffe, es hilft.
quelle
DT_fun
die Eingabe an Ort und Stelle geändert wird, ist der Benchmark möglicherweise nicht ganz fair. Zusätzlich zum Erhalt derselben Eingabe ab der 2. Iteration vorwärts (was sich möglicherweise auf das Timing auswirkt, daDT$g
bereits zugewiesen?), Wird das Ergebnis auch zurück zuans1
und daher möglicherweise ( wenn R Optimierer dies für erforderlich hält? Nicht sicher , auf diese ...) vermeiden eine weitere Kopie , dassDPLYR_fun
undBASE_fun
Notwendigkeit zu machen?data.table
Lösung großartig und verwende siedata.table
überall dort , wo ich wirklich Geschwindigkeit für Operationen an Tabellen benötige und nicht bis zu C ++ gehen möchte. Es ist jedoch sehr vorsichtig, wenn Änderungen vorgenommen werden!dplyr hat jetzt eine Funktion
case_when
, die ein vektorisiertes if bietet. Die Syntax ist etwas seltsam im Vergleich zu,mosaic:::derivedFactor
da Sie nicht auf Standard-Dplyr-Weise auf Variablen zugreifen können und den Modus von NA deklarieren müssen, aber sie ist erheblich schneller alsmosaic:::derivedFactor
.BEARBEITEN: Wenn Sie
dplyr::case_when()
vor Version 0.7.0 des Pakets verwenden, müssen Sie Variablennamen mit '.$
' voranstellen (z. B..$a == 1
innen schreiben)case_when
. ).Benchmark : Für den Benchmark (Wiederverwendung von Funktionen aus Aruns Beitrag) und Reduzierung der Stichprobengröße:
Das gibt:
quelle
case_when
könnte auch geschrieben werden als:df %>% mutate(g = with(., case_when(a %in% c(2,5,7) | (a==1 & b==4) ~ 2L, a %in% c(0,1,3,4) | c==4 ~ 3L, TRUE ~ NA_integer_)))
.$
nicht mehr in der neuen Version von dplyrDie
derivedFactor
Funktion aus demmosaic
Paket scheint darauf ausgelegt zu sein. In diesem Beispiel würde es so aussehen:(Wenn das Ergebnis anstelle eines Faktors numerisch sein soll, können Sie
derivedFactor
einenas.numeric
Anruf einschließen.)derivedFactor
kann auch für eine beliebige Anzahl von Bedingungen verwendet werden.quelle
.asFactor = F
Option oder die (ähnliche)derivedVariable
Funktion im selben Paket verwenden.recode
aus, als würde ab dplyr 0.5 dies geschehen. Ich habe es aber noch nicht untersucht. Siehe blog.rstudio.org/2016/06/27/dplyr-0-5-0case_when
ist jetzt eine ziemlich saubere Implementierung des SQL-Falls, wenn:Verwenden von dplyr 0.7.4
Das Handbuch: http://dplyr.tidyverse.org/reference/case_when.html
quelle