Фон
У меня есть вычислительно дорогая (и SLOW ) функция, которая вызывается из другой функции, которая является частью конвейера dplyr:
dat %>%
mutate_at(.vars = vars(dplyr::intersect(starts_with("locale"), ends_with("last_name"))),
.funs = funs(native_last_name_alpha(., Type))) %>%
{.} -> dat
Функция выполняет одно из двух действий, в зависимости от того, совпадает ли переменная Type
(строка символов) для "мужской" или "женский". Если есть совпадение, native_last_name_alpha
запустит вычислительно дорогую и медленную функцию, которая выполняет некоторые другие вещи. Если совпадений нет, native_last_name_alpha
вернет NA
. В настоящее время, поскольку это векторизация, я использую if_else
и case_when
, чтобы определить, что должно произойти, например:
native_last_name_alpha <- function(locale, type) {
case_when(
type == "male" ~ stringi::stri_trans_toupper(
fake_single_alpha(locale = locale,
request = "last_name_male",
provider = "faker.providers.person")
),
type == "female" ~ stringi::stri_trans_toupper(
fake_single_alpha(locale = locale,
request = "last_name_female",
provider = "faker.providers.person")
),
TRUE ~ NA_character_
)
}
Проблема в том, что дорогая функция запускается независимо от того, оценивается ли условие как TRUE
или FALSE
, и это делает мой скрипт чрезвычайно медленным для запуска.
Копание глубже в if_else, ifelse и case_when
Я понимаю, что векторизованные операторы if / else if_else
и ifelse
(и case_when
) не работают как традиционные операторы if ... else; все части оператора оцениваются, а затем условие используется для объединения результатов, которые должны быть возвращены. Например, этот код выдает следующие выходные данные и предупреждения:
v <- c(-100, -10, 10, 100)
ifelse(v > 0, log10(v), log10(-v))
[1] 2 1 1 2
Предупреждающие сообщения:
1: In ifse (v> 0, log10 (v), log10 (-v)): произведено NaN
2: In ifse (v> 0, log10 (v), log10 (-v)): произведено NaN
Как возвращаемое значение, если условие истинно, так и возвращаемое значение, если условие ложно, оцениваются, и условие используется для соединения вектора результатов.
Следовательно, моя дорогая и медленная функция работает намного больше, чем требуется.
Как мне избежать этого?
Что бы я хотел
Я ищу альтернативные векторизованные реализации if_else
и case_when
, которые оценивают результат result-if-true, когда условие истинно.
Что я пробовал до сих пор
Я пытался написать свои собственные векторизованные реализации if_else
/ ifelse
, но безуспешно. Я также экспериментировал с нестандартной оценкой, но я не знаю достаточно, чтобы сделать эту работу. Я предполагаю, что если я смогу получить if_else
, чтобы возвратить неоцененное выражение, которое я затем вычислю позже в соответствующее время (вроде как вызов функции сублимационной сушкой), это может быть частью решение. Но пока радости нет.
Я что-то упустил, чтобы легко делать то, что я хочу? Или кто-то может предложить некоторые советы по реализации? Спасибо!