#r #case #r-factor
Вопрос:
Настройка данных
У меня есть набор данных, который выглядит примерно так, как этот простой фрейм данных ниже:
CAD_EXCHANGE lt;- 1.34 EUR_EXCHANGE lt;- 0.88 df lt;- tibble( shipment = c("A", "B", "C", "D", "E"), invoice = c(rep(500, 5)), currency = factor(c("USD", "EUR", "CAD", NA, "SDD")) ) df # A tibble: 5 x 3 shipment invoice currency lt;chrgt; lt;dblgt; lt;fctgt; 1 A 500 USD 2 B 500 EUR 3 C 500 CAD 4 D 500 NA 5 E 500 SDD levels(df$currency) [1] "CAD" "EUR" "SDD" "USD"
Конечная Цель
Я пытаюсь конвертировать счета-фактуры в доллары США для некоторых распространенных других валют (EUR и CAD), но не для всех из них или если данные отсутствуют (т. Е. SDD и NA
). Мой конечный фрейм данных должен выглядеть следующим образом:
# A tibble: 5 x 5 shipment invoice currency invoice_converted currency_converted lt;chrgt; lt;dblgt; lt;fctgt; lt;dblgt; lt;fctgt; 1 A 500 USD 500 USD 2 B 500 EUR 568 USD 3 C 500 CAD 373 USD 4 D 500 NA 500 NA 5 E 500 SDD 500 SDD
Пробная Версия 1 — Не Работает
В будущем у меня может быть больше, чем просто эти несколько валют для конвертации, поэтому я подал case_when()
заявление. Это была моя первая попытка:
df_USD1 lt;- df %gt;% mutate( invoice_converted = case_when( currency == "EUR" ~ round(invoice / EUR_EXCHANGE), currency == "CAD" ~ round(invoice / CAD_EXCHANGE), TRUE ~ invoice ), currency_converted = case_when(currency == "EUR" ~ "USD", currency == "CAD" ~ "USD", TRUE ~ currency) ) Error: Problem with `mutate()` column `currency_converted`. i `currency_converted = case_when(...)`. x must be a character vector, not a `factor` object.
Учитывая вышесказанное, я понимаю, что смешиваю характер и фактор в назначении currency_converted
, потому что у меня есть значение по умолчанию TRUE ~ currency
(и currency
это фактор). Поэтому я попытался использовать для задания только факторы…
Пробная версия 2 — Работает, но ненадежно
df_USD2 lt;- df %gt;% mutate( invoice_converted = case_when( currency == "EUR" ~ round(invoice / EUR_EXCHANGE), currency == "CAD" ~ round(invoice / CAD_EXCHANGE), TRUE ~ invoice ), currency_converted = case_when( currency == "EUR" ~ currency[1], currency == "CAD" ~ currency[1], TRUE ~ currency) )
It works, but only because in my setup for this question, USD is in the first position, and I cannot rely on that.
gt; df$currency [1] USD EUR CAD lt;NAgt; SDD Levels: CAD EUR SDD USD
Trial 3 — Doesn’t work
I thought I could try some other way of getting at the factor with subsetting, but this doesn’t work:
df_USD3 lt;- df %gt;% mutate( invoice_converted = case_when( currency == "EUR" ~ round(invoice / EUR_EXCHANGE), currency == "CAD" ~ round(invoice / CAD_EXCHANGE), TRUE ~ invoice ), currency_converted = case_when( currency == "EUR" ~ df$currency[df$currency == "USD"], currency == "CAD" ~ df$currency[df$currency == "USD"], TRUE ~ currency ) ) Error: Problem with `mutate()` column `currency_converted`. i `currency_converted = factor(...)`. x `currency == "EUR" ~ df$currency[df$currency == "USD"]`, `currency == "CAD" ~ df$currency[df$currency == "USD"]` must be length 5 or one, not 2. Run `rlang::last_error()` to see where the error occurred.
И, похоже, это из NA
-за того, что возвращается…
gt; df$currency[df$currency == "USD"] [1] USD lt;NAgt; Levels: CAD EUR SDD USD
…потому что, если я вернусь к своему оригиналу df
и NA
заменю его какой-нибудь другой валютой, это сработает, но, очевидно, мне нужно быть в состоянии сохранить NA
то, чему оно принадлежит.
Я чувствую, что есть какой-то очень хороший способ сделать это, но мне его не хватает, несмотря на то, что я читаю о факторах и пробую разные вещи. Помочь?
Ответ №1:
case_when
не выполняет преобразование типов автоматически — т. Е. currency
является factor
, в то время как возврат из других условий case_when
является справедливым character
. Таким образом, мы можем принудительно преобразовать currency
в character
, чтобы все возвращаемые значения были одного класса, и это должно сработать
library(dplyr) df %gt;% mutate( invoice_converted = case_when( currency == "EUR" ~ round(invoice / EUR_EXCHANGE), currency == "CAD" ~ round(invoice / CAD_EXCHANGE), TRUE ~ invoice ), currency_converted = case_when(currency == "EUR" ~ "USD", currency == "CAD" ~ "USD", TRUE ~ as.character(currency)))
-выход
# A tibble: 5 × 5 shipment invoice currency invoice_converted currency_converted lt;chrgt; lt;dblgt; lt;fctgt; lt;dblgt; lt;chrgt; 1 A 500 USD 500 USD 2 B 500 EUR 568 USD 3 C 500 CAD 373 USD 4 D 500 lt;NAgt; 500 lt;NAgt; 5 E 500 SDD 500 SDD
Если мы хотим сохранить его как factor
, либо оберните factor
после case_when
, либо непосредственно используйте fct_recode
вместо case_when
library(forcats) df %gt;% mutate( invoice_converted = case_when( currency == "EUR" ~ round(invoice / EUR_EXCHANGE), currency == "CAD" ~ round(invoice / CAD_EXCHANGE), TRUE ~ invoice ), currency_converted = fct_recode(currency, USD = "EUR", USD = "CAD"))
-выход
# A tibble: 5 × 5 shipment invoice currency invoice_converted currency_converted lt;chrgt; lt;dblgt; lt;fctgt; lt;dblgt; lt;fctgt; 1 A 500 USD 500 USD 2 B 500 EUR 568 USD 3 C 500 CAD 373 USD 4 D 500 lt;NAgt; 500 lt;NAgt; 5 E 500 SDD 500 SDD