R - Erstellen Sie mehrere neue Spalten mit bedingten Anweisungen
Ich frage mich, ob es eine Möglichkeit gibt, mehrere Spalten basierend auf einer Bedingung (en) zu erstellen.
Zum Beispiel habe ich unten einen Datenrahmen mit Daten und möchte zwei Spalten basierend auf der Basis von ccy erstellen. Eine Spalte ist eine gbp-Konvertierungsrate des ccy und die andere ist eine cad-Konvertierungsrate.
Wenn ich die Mutaten weitergebe, kann ich sie zum Laufen bringen, aber es gibt Wiederholungen (und in meinem eigentlichen Problem habe ich eine komplexe Liste von ifelse, so dass das Wiederholen des Codes für jede Spalte viel Wiederholung verursachen würde).
df <- structure(list(product = c('option', 'forward', 'forward', 'option'),
ccy = c('usd', 'usd', 'eur', 'usd'),
amount = c(1000, 2000, 1000, 5000)),
.Names = c('product', 'ccy', 'amount'),
row.names = c(NA, 4L),
class = "data.frame")
df
product ccy amount
1 option usd 1000
2 forward usd 2000
3 forward eur 1000
4 option usd 5000
df %>% mutate(gbp_amount =
ifelse(ccy == 'usd', round(amount / 1.8, 2),
ifelse(ccy == 'eur', round(amount / 1.3, 2),
'not_converted'))) %>%
mutate(cad_amount =
ifelse(ccy == 'usd', round(amount / 0.85, 2),
ifelse(ccy == 'eur', round(amount / .7, 2),
'not_converted')))
product ccy amount gbp_amount cad_amount
1 option usd 1000 555.56 1176.47
2 forward usd 2000 1111.11 2352.94
3 forward eur 1000 769.23 1428.57
4 option usd 5000 2777.78 5882.35
Gibt es eine Möglichkeit, mehrere Spalten basierend auf einer einzelnen if-Bedingung zu erstellen?
Zum Beispiel so etwas wie dieser Pseudocode ...
df %>% ifelse(df$ccy == 'usd',
(mutate(gbp_amount = round(amount / 1.8, 2)),
mutate(cad_amount = round(amount / 0.85, 2))),
ifelse(df$ccy == 'eur',
(mutate(gbp_amount = round(amount / 1.3, 2)),
mutate(cad_amount = round(amount / 0.7, 2))),
'not_converted'))
3 Antworten
Sie können SQL-ähnliche Verknüpfungen verwenden, wenn Sie viele "gleiche" Bedingungen haben.
Ich verwende die data.table
-Syntax, aber Sie können dies auch dplyr
tun:
library(data.table)
setDT(df)
# add a row which cannot be found ("joined") to demonstrate missing rates
df <- rbind(df, data.table(product = "option", ccy = "aud", amount = 3000))
df
lookup <- data.table(ccy = c("usd", "eur"),
gbp_rate = c( 1.8, 1.3),
cad_rate = c( 0.85, 0.7))
lookup
# ccy gbp_rate cad_rate
# 1: usd 1.8 0.85
# 2: eur 1.3 0.70
df[lookup, `:=`(gbp_amount = round(amount / gbp_rate, 2),
cad_amount = round(amount / cad_rate, 2)),
on = "ccy"]
df
# product ccy amount gbp_amount cad_amount
# 1: option usd 1000 555.56 1176.47
# 2: forward usd 2000 1111.11 2352.94
# 3: forward eur 1000 769.23 1428.57
# 4: option usd 5000 2777.78 5882.35
# 5: option aud 3000 NA NA
Sie müssen das Ergebnis nach Belieben sortieren und die Suchfehler (fehlende Conversion-Raten) mit einem anderen Wert als NA
markieren, wenn Sie möchten (jedoch nicht mit der Zeichenfolge "not_converted"
wie in Ihrer Frage, da sich diese mischen würde den Datentyp der Spalte erhöhen (doppelt gegen Zeichen).
Erwägen Sie, einen Raten -Datensatz zu erstellen und mit Ihrem Original zusammenzuführen, um verschachtelte ifelse
zu vermeiden:
rates_df <- data.frame(ccy = c('usd', 'eur'),
type = c('gbp', 'gbp', 'cad', 'cad'),
rate = c(1.8, 1.3, 0.85, 0.7),
stringsAsFactors = FALSE)
rates_df
df %>%
inner_join(rates_df, by="ccy") %>%
mutate(gbp_amount = ifelse(type=="gbp", round(amount / rate, 2), 0),
cad_amount = ifelse(type=="cad", round(amount / rate, 2), 0)) %>%
select(product, ccy, matches("amount")) %>%
group_by(product, ccy, amount) %>%
summarise_all(sum)
# # A tibble: 4 x 5
# # Groups: product, ccy [?]
# product ccy amount gbp_amount cad_amount
# <chr> <chr> <dbl> <dbl> <dbl>
# 1 forward eur 1000 769.23 1428.57
# 2 forward usd 2000 1111.11 2352.94
# 3 option usd 1000 555.56 1176.47
# 4 option usd 5000 2777.78 5882.35
Sie müssen ein for-loop
verwenden, wenn Sie mehrere Aktionen ausführen möchten. Die Lösung von @R Yoda ist wahrscheinlich besser. Wie er sagte, würde ich NA anstelle einer Zeichenfolge verwenden, damit Sie keine Datentypen in einem Vektor mischen, da sonst standardmäßig Zeichen verwendet werden.
for (i in 1:nrow(df)) {
if(df$ccy[i] == "usd") {
df$gbp_amount[i] <- round(df$amount[i] / 1.8, 2);
df$cad_amount[i] <- round(df$amount[i] / 0.85, 2);
} else {
NA
}
if(df$ccy[i] == "eur") {
df$gbp_amount[i] <- round(df$amount[i] / 1.3, 2);
df$cad_amount[i] <- round(df$amount[i] / 0.7, 2);
} else {
NA
}
}
Neue Fragen
r
R ist eine kostenlose Open-Source-Programmiersprache und Softwareumgebung für statistisches Rechnen, Bioinformatik, Visualisierung und allgemeines Rechnen. Bitte geben Sie minimale und reproduzierbare Beispiele zusammen mit der gewünschten Ausgabe an. Verwenden Sie dput () für Daten und geben Sie alle Nicht-Basispakete mit library () -Aufrufen an. Betten Sie keine Bilder für Daten oder Code ein, sondern verwenden Sie stattdessen eingerückte Codeblöcke. Verwenden Sie für statistische Fragen https://stats.stackexchange.com.