#r #tidyverse #purrr
#r #tidyverse #purrr
Вопрос:
Я ищу эквивалент next в циклах для вызова purrr::map_df.
map_df прекрасно работает с фреймами данных, которые равны НУЛЮ (как в примере ниже), поэтому он работает, когда я задаю Result <- NULL
в своем примере ниже.
Может ли кто-нибудь предложить общее решение для моей иллюстрации ниже, которое не требовало бы от меня настройки Result <- NULL
, а сразу переходило бы к «далее».
library(tidyverse)
set.seed(1000)
df <- data.frame(x = rnorm(100), y = rnorm(100), z = rep(LETTERS, 100))
Map_Func <- function(df) {
Sum_Num <- suppressWarnings(sqrt(sum(df$y)))
if( Sum_Num == "NaN" ) {
Result <- NULL
# I would like to have an equivalent to "next" here...
} else {
Result <- df %>% filter(y == max(y)) %>% mutate(Result = x*y)
}
Result
}
Test <- split(df, df$z) %>% map_df(~Map_Func(.))
В приведенном выше коде, что я могу использовать вместо Result <- NULL
уродливого оператора if (т. Е. Я хочу просто проверить условие и эффективно выполнить «next»).
Комментарии:
1.
group_split
из какого пакета? этого нет в стандартном dplyr2.
group_split
Функцияdplyr
включена, только только в самой новой версии. dplyr.tidyverse.org/reference/group_split.html Но вы можете захотеть изменить пример, поскольку большинство людей, вероятно, не имеют последней версии и, следовательно, не могут протестировать этот код. Не обязательно, просто к вашему сведению3. @IceCreamToucan спасибо — я скорректировал код, чтобы он не зависел от использования последней терминологии dplyr.
4. В функции, которую использует map, вы должны что-то вернуть. Вместо того, чтобы делать это предложение else, вы могли
return(NULL)
бы использовать предложение if, которое было бы эквивалентно next .5. К вашему сведению, есть
is.nan
функция
Ответ №1:
Для выхода из функции вы можете использовать return(<output>)
команду. Это немедленно завершает работу функции с определенным вами выводом. Следующий вывод дает тот же результат, который вы получали с вашим примером кода.
library(tidyverse)
set.seed(1000)
df <- data.frame(x = rnorm(100), y = rnorm(100), z = rep(LETTERS, 100))
Map_Func <- function(df) {
Sum_Num <- suppressWarnings(sqrt(sum(df$y)))
if( Sum_Num == "NaN" ) {
return(NULL)
}
Result <- df %>% filter(y == max(y)) %>% mutate(Result = x*y)
}
Test <- split(df, df$z) %>% map_df(~Map_Func(.))
Комментарии:
1. это именно то, что я искал, спасибо. Действительно классный способ добавления остановок в map_df, поскольку он учитывает нули.
Ответ №2:
Логически решение не сильно отличается от OP, но пытается сохранить его в чистоте, используя отдельные функции. custom_check
функция заключается в проверке условия для каждой группы. Используя map_if
, мы применяем функцию Map_Func_true
только при custom_check
возврате TRUE
или иначе применяем Map_Func_false
, который возвращает NULL
и, наконец, связывает строки.
library(tidyverse)
Map_Func_true <- function(df) {
df %>% filter(y == max(y)) %>% mutate(Result = x*y)
}
Map_Func_false <- function(df) { return(NULL) }
custom_check <- function(df) {
!is.nan(suppressWarnings(sqrt(sum(df$y))))
}
df %>%
group_split(z) %>%
map_if(., custom_check, Map_Func_true, .else = Map_Func_false) %>%
bind_rows()
# A tibble: 26 x 4
# x y z Result
# <dbl> <dbl> <fct> <dbl>
# 1 1.24 2.00 A 2.47
# 2 1.24 2.00 A 2.47
# 3 1.24 2.00 C 2.47
# 4 1.24 2.00 C 2.47
# 5 1.24 2.00 E 2.47
# 6 1.24 2.00 E 2.47
# 7 1.24 2.00 G 2.47
# 8 1.24 2.00 G 2.47
# 9 1.24 2.00 I 2.47
#10 1.24 2.00 I 2.47
# … with 16 more rows
Комментарии:
1. Ваше решение слишком специфично (функция — просто иллюстрация). Идея заключается в том, чтобы заставить вызов map_df остановиться и перейти к следующему. решение @adam обеспечивает более чистый способ сделать это.
2. Ваше решение интересно в общих чертах — никогда не думайте об объединении map_if таким образом…
Ответ №3:
Вот еще один способ взглянуть на это с помощью purrr::safely
Map_Func <- function(df) {
Sum_Num <- suppressWarnings(sqrt(sum(df$y)))
df %>% filter(y == max(y)) %>% mutate(Result = x*y)
}
Test <- split(df, df$z) %>%
map(safely(~Map_Func(.))) %>%
transpose() %>%
pluck("result") %>% # use 'error' here to get the error log
bind_rows()
Таким образом, функция становится чище, и вы также получаете хороший журнал ошибок