【问题标题】:Equivalent of next in purrr::map_df相当于 purrr::map_df 中的 next
【发布时间】:2019-04-16 13:08:30
【问题描述】:

我正在寻找相当于 next 在循环中的 purrr::map_df 调用。

map_df 可以很好地处理 NULL 数据帧(如下例所示),因此当我在下面的示例中设置 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(.))

在上面的代码中,我可以在丑陋的 if 语句中使用什么来代替 Result &lt;- NULL(即我想简单地检查一个条件并有效地执行“下一步”)。

【问题讨论】:

  • group_split 来自哪个包?它不在标准 dplyr 中
  • group_split 函数在dplyr 中,仅在最新版本中。 dplyr.tidyverse.org/reference/group_split.html 但是,您可能想要修改示例,因为大多数人可能不是最新版本,因此无法测试此代码。没必要,仅供参考
  • @IceCreamToucan 谢谢 - 我将代码调整为不依赖于使用最新的 dplyr 术语。
  • 在函数map中使用你必须返回一些东西。你可以在 if 子句中使用 return(NULL) 而不是执行 else 子句,这将等同于 next。
  • 仅供参考,有一个 is.nan 函数

标签: r tidyverse purrr


【解决方案1】:

要退出函数,您可以使用return(&lt;output&gt;) 命令。这会立即以您定义的输出退出函数。下面给出了与示例代码相同的输出。

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(.))

【讨论】:

  • 这正是我想要的,谢谢。在 map_df 中添加停靠点的方式非常酷,因为它尊重 NULL。
【解决方案2】:

从逻辑上讲,它与 OP 的解决方案没有太大的不同,但它试图通过使用单独的函数来保持它的整洁。 custom_check 功能是检查每个组的条件。使用map_if,我们仅在custom_check 返回TRUE 时应用函数Map_Func_true,否则应用返回NULLMap_Func_false,最后绑定行。

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

【讨论】:

  • 你的解决方案太具体了(函数只是一个说明)。想法更多的是让 map_df 调用停止并继续下一步。 @adam 的解决方案提供了一种更简洁的方法。
  • 您的解决方案在一般意义上很有趣 - 虽然从来没有以这种方式组合 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()

通过这种方式,函数变得更简洁,并且您还可以获得很好的错误日志

【讨论】:

    猜你喜欢
    • 2018-07-03
    • 2019-07-06
    • 2018-10-11
    • 2020-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-28
    • 2021-03-21
    相关资源
    最近更新 更多