【问题标题】:tryCatch inside dplyr's mutate?tryCatch 在 dplyr 的变异中?
【发布时间】:2023-03-13 04:37:01
【问题描述】:

dplyr 的mutate() 有异常处理机制吗?我的意思是一种捕获异常并处理它们的方法。

让我们假设我有一个函数在某些情况下会引发错误(在示例中,如果输入为负数),为了简单起见,我定义了该函数,但在现实生活中,它在某些情况下会是一个函数R 包。让我们假设这个函数是矢量化的:

# function throwing an error
my_func <- function(x){
  if(x > 0) return(sqrt(x))
  stop('x must be positive')
}

my_func_vect <- Vectorize(my_func)

现在,假设我想在mutate() 中使用这个函数。

如果在mutate() 中使用此函数,它将在第一个错误处停止并且不返回任何结果:

library(dplyr)
# dummy data
data <- data.frame(x = c(1, -1, 4, 9))
data %>% mutate(y = my_func_vect(x))
# Error in mutate_impl(.data, dots) : Evaluation error: x must be positive.

在这种情况下,有没有办法捕捉错误并执行某些操作(例如返回 NA),同时获取其他元素的结果?

我期望的结果是使用带有tryCatch() 的循环将实现的结果,即类似于以下内容:

y <- rep(NA_real_, length(data$x))
for(i in seq_along(data$x)) {
  tryCatch({
    y[i] <- my_func_vect(data$x[i])
  }, error = function(err){})
}
y
# Result is: 1 NA 2 4

【问题讨论】:

  • 你不是快到了吗?在你的tryCatch 函数中使用error = function(err){NA},我相信它有效。编辑:啊,你当然想在变异中使用它,没关系。
  • 请完整阅读我的问题。当函数抛出错误时,该点不返回 NA 。但是在 dplyr 的 mutate() 中执行 tryCatch 机制。

标签: r exception-handling dplyr


【解决方案1】:

我们也可以使用purrrsafely()possibly()函数。

来自purrr 帮助:

安全地:包装函数返回一个包含组件结果和错误的列表。一个值始终为 NULL。

安静地:包装函数返回一个包含组件结果、输出、消息和警告的列表。

可能:包装函数在发生错误时使用默认值(否则)。

这并没有改变您必须将函数分别应用于每一行的事实。

library(dplyr)
library(purrr)

# function throwing an error
my_func <- function(x){
  if(x > 0) return(sqrt(x))
  stop('x must be positive')
}

my_func_vect <- Vectorize(my_func)

# dummy data
data <- data.frame(x = c(1, -1, 4, 9))

带地图:

data %>% 
  mutate(y = map_dbl(x, ~possibly(my_func_vect, otherwise = NA_real_)(.x)))
#>    x  y
#> 1  1  1
#> 2 -1 NA
#> 3  4  2
#> 4  9  3

使用rowwise():

data %>%
  rowwise() %>% 
  mutate(y = possibly(my_func_vect, otherwise = NA_real_)(x))
#> Source: local data frame [4 x 2]
#> Groups: <by row>
#> 
#> # A tibble: 4 x 2
#>       x     y
#>   <dbl> <dbl>
#> 1     1     1
#> 2    -1    NA
#> 3     4     2
#> 4     9     3

其他函数在“数据框环境”中使用和应用有些困难,因为它们更适合处理列表并返回此类。

reprex package (v0.2.0) 于 2018 年 5 月 15 日创建。

【讨论】:

  • 我很想知道为什么data %&gt;% mutate(y = map(x, ~ possibly(my_func(.), otherwise = NA_real_))) 不起作用?这显然不是tryCatch的直接替代品?
【解决方案2】:

您想单独评估每个发生的错误,也许您不应该使用矢量化函数。而是使用 purrr 包中的 map,这实际上与此处的 lapply 相同。

如果您想要 NA 值以防出现错误,请创建一个函数来捕获错误以供标准使用。

try_my_func <- function(x) {
  tryCatch(my_func(x), error = function(err){NA})
}

然后使用mutatemap

data %>% mutate(y = purrr::map(x, try_my_func))
   x  y
1  1  1
2 -1 NA
3  4  2
4  9  3

或者类似地,如果您不想声明新函数。

data %>% mutate(y = purrr::map(x, ~ tryCatch(my_func(.), error = function(err){NA})))

最后,如果您确实想使用矢量化函数,您可以完全跳过 map 函数。但就我个人而言,我从不使用Vectorize,所以我会使用map

data %>% mutate(y = Vectorize(try_my_func)(x))

【讨论】:

  • 对不起,我的问题不是很清楚。在示例中,我编写了一个已矢量化的函数,但我的问题是该函数由 R 包提供,并且已经矢量化且无法访问标量函数的情况。我编辑了我的问题以反映这一点。
  • 我想您可以使用 map 将矢量化函数应用于单个元素,对吧?如果即使有 1 个值引发错误,矢量化函数也会给出错误,因此您将无法捕获矢量中单个元素的错误 - 我认为。
  • 嗯,我想你是对的......所以,总结一下(1)我必须在 mutate / map 之外进行异常处理,(2)我别无选择,只能使用逐行矢量化函数:(谢谢,我会用这些元素编辑我的问题。我不认为 map 在这里添加任何东西....
猜你喜欢
  • 2018-08-22
  • 2020-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-30
  • 1970-01-01
  • 2017-06-02
相关资源
最近更新 更多