Ich weiß, dass es hier einige ähnliche Fragen gibt, aber keine scheint das genaue Problem anzusprechen, das ich habe.
set.seed(4)
df = data.frame(
Key = c("A", "B", "A", "D", "A"),
Val1 = rnorm(5),
Val2 = runif(5),
Val3 = 1:5
)
Ich möchte die Werte der Wertespalten für die Zeilen auf Null setzen, in denen Key == "A" angegeben ist. Die Spaltennamen werden durch Folgendes referenziert grep
:
cols = grep("Val", names(df), value = TRUE)
Normalerweise würde ich Folgendes verwenden, um das zu erreichen, was ich in diesem Fall möchte data.table
:
library(data.table)
df = as.data.table(df)
df[Key == "A", (cols) := 0]
Und die gewünschte Ausgabe ist wie folgt:
Key Val1 Val2 Val3
1 A 0.000000 0.00000000 0
2 B -1.383814 0.55925762 2
3 A 0.000000 0.00000000 0
4 D 1.437151 0.05632773 4
5 A 0.000000 0.00000000 0
Dieses Mal muss ich es jedoch verwenden, dplyr
da ich an einem Teamprojekt arbeite, in dem jeder es verwendet. Die Daten, die ich gerade bereitgestellt habe, sind illustrativ und meine realen Daten sind> 5 Millionen Zeilen mit 16 zu aktualisierenden Wertespalten. Die einzige Lösung, die ich finden könnte, ist folgende mutate_at
:
df %>% mutate_at(.vars = vars(cols), .funs = function(x) ifelse(df$Key == "A", 0, x))
Dies scheint jedoch bei meinen realen Daten extrem langsam zu sein. Ich hatte gehofft, eine Lösung zu finden, die eleganter und vor allem schneller ist.
Ich habe viele Kombinationen mit map
, ohne Anführungszeichen mit !!
, mit get
und :=
(die ärgerlicherweise durch die :=
in data.table maskiert werden können) usw. ausprobiert, aber ich denke, mein Verständnis, wie diese Arbeit einfach nicht tief genug ist, um eine gültige Lösung zu konstruieren.
quelle
Antworten:
Mit diesem Befehl dplyr
Sie werten tatsächlich die Anweisung df $ Key == "A" n-mal aus, wobei n = die Anzahl der Spalten ist, die Sie haben.
Eine Problemumgehung besteht darin, die Zeilen, die Sie ändern möchten, vorab zu definieren:
Ein sauberer und besserer Weg, auf den @IceCreamToucan richtig hingewiesen hat (siehe Kommentare unten), besteht darin, die Funktion replace zu verwenden und dabei die zusätzlichen Parameter zu übergeben:
Wir können all diese Ansätze testen, und ich denke, dplyr und data.table sind vergleichbar.
quelle
df %>% mutate_at(vars(contains('Val')), replace, df$Key == 'A', 0)
replace
Methode etwas langsamer zu sein als Ihre ursprünglicheidx
Methode.dplyr::if_else()
ist schneller als Basisifelse()
.