Ich versuche zu verstehen, wie man Werte in einem Datenrahmen ohne Verwendung einer Schleife bedingt ersetzt. Mein Datenrahmen ist wie folgt aufgebaut:
> df
a b est
1 11.77000 2 0
2 10.90000 3 0
3 10.32000 2 0
4 10.96000 0 0
5 9.90600 0 0
6 10.70000 0 0
7 11.43000 1 0
8 11.41000 2 0
9 10.48512 4 0
10 11.19000 0 0
und die dput
Ausgabe ist folgende:
structure(list(a = c(11.77, 10.9, 10.32, 10.96, 9.906, 10.7,
11.43, 11.41, 10.48512, 11.19), b = c(2, 3, 2, 0, 0, 0, 1, 2,
4, 0), est = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)), .Names = c("a",
"b", "est"), row.names = c(NA, -10L), class = "data.frame")
Was ich tun möchte, ist den Wert von zu überprüfen b
. Wenn b
0 ist, möchte ich est
einen Wert von setzen a
. Ich verstehe, dass df$est[df$b == 0] <- 23
alle Werte est
auf 23 gesetzt werden, wenn b==0
. Was ich nicht verstehe, ist, wie man est
einen Wert a
festlegt, wenn diese Bedingung erfüllt ist. Zum Beispiel:
df$est[df$b == 0] <- (df$a - 5)/2.533
gibt die folgende Warnung:
Warning message:
In df$est[df$b == 0] <- (df$a - 5)/2.533 :
number of items to replace is not a multiple of replacement length
Gibt es eine Möglichkeit, die relevante Zelle anstelle des Vektors zu übergeben?
Hier ist ein Ansatz.
ifelse
wird vektorisiert und überprüft alle Zeilen auf Nullwerte vonb
und ersetztest
durch,(a - 5)/2.53
wenn dies der Fall ist.df <- transform(df, est = ifelse(b == 0, (a - 5)/2.53, est))
quelle
Eine andere Möglichkeit wäre, case_when zu verwenden
require(dplyr) mutate(df, est = case_when( b == 0 ~ (a - 5)/2.53, TRUE ~ est ))
Diese Lösung ist noch praktischer, wenn mehr als zwei Fälle unterschieden werden müssen, da verschachtelte
if_else
Konstrukte vermieden werden können.quelle
Das R-Inferno oder die grundlegende R-Dokumentation erklären, warum die Verwendung von df $ * hier nicht der beste Ansatz ist. Von der Hilfeseite für "[":
"Die Indizierung nach [ähnelt Atomvektoren und wählt eine Liste der angegebenen Elemente aus. Sowohl [[als auch $ wählen ein einzelnes Element der Liste aus. Der Hauptunterschied besteht darin, dass $ keine berechneten Indizes zulässt, während [[dies tut x $ name entspricht x [["name", exakt = FALSE]]. Außerdem kann das partielle Übereinstimmungsverhalten von [[mit dem exakten Argument gesteuert werden. "
Ich empfehle stattdessen die
[row,col]
Notation. Beispiel:Rgames: foo x y z [1,] 1e+00 1 0 [2,] 2e+00 2 0 [3,] 3e+00 1 0 [4,] 4e+00 2 0 [5,] 5e+00 1 0 [6,] 6e+00 2 0 [7,] 7e+00 1 0 [8,] 8e+00 2 0 [9,] 9e+00 1 0 [10,] 1e+01 2 0 Rgames: foo<-as.data.frame(foo) Rgames: foo[foo$y==2,3]<-foo[foo$y==2,1] Rgames: foo x y z 1 1e+00 1 0e+00 2 2e+00 2 2e+00 3 3e+00 1 0e+00 4 4e+00 2 4e+00 5 5e+00 1 0e+00 6 6e+00 2 6e+00 7 7e+00 1 0e+00 8 8e+00 2 8e+00 9 9e+00 1 0e+00 10 1e+01 2 1e+01
quelle
$
(oder im Idealfall mit beiden) zusammenfassen.$
Operator in diesem Fall vollkommen in Ordnung ist. (Außerdem$