使用 purrr::possibly 捕捉动态错误信息
Using purrr::possibly to catch dynamic error messages
我编写了一个自定义函数,该函数执行多项检查并在检查失败时抛出不同的错误。
下面是一个简单的示例函数,它接受一个 data.frame 和一个列名,并简单地输出该列的总和。我正在使用 purrr::possibly() 创建该函数的保存版本,以便我可以遍历列名向量。
foo <- function(df, var){
#check 1
if(var %in% names(df) == FALSE){
stop(paste0("No column with name ", var, " found."))}
#check 2
if(all(is.na(dplyr::select(df, {{var}})))) {
stop(paste0("All values of column ", var, " are missing."))}
# main function
result <- df %>%
dplyr::rename(var = {{var}}) %>%
dplyr::summarise(sum = sum(var))
#print(result) printing shows the correct error messages
}
safer_foo <- purrr::possibly(.f = foo, otherwise = "error", quiet = FALSE)
我使用 purrr::map 遍历列向量并将输出存储在列表中。但是,对于函数失败的元素,我想存储特定的错误消息,而不是 purrr::possibly 要求的“否则”参数的静态输入。
将 purrr::possibly 替换为 purrr::safely 实际上会捕获列表的 $error 元素中预期的特定错误消息,但我想避免安全创建的额外嵌套级别。
test_df <- tibble(A = 1:10, C = NA)
input <- c("A", "B", "C")
output_list <- map(input, ~safer_foo(test_df, .x)) %>% set_names(input)
输出
> output_list
sum
<int>
1 55
$B
[1] "error"
$C
[1] "error"
期望的输出
> output_list
sum
<int>
$A 55
$B
[1] "Error: No column with name B found."
$C
[1] "Error: All values of column C are missing."
您可以将 purrr::possibly()
从其原始代码调整为 return 而不是 message 错误。
原代码:
## > possibly
## function (.f, otherwise, quiet = TRUE)
## {
## .f <- as_mapper(.f)
## force(otherwise)
## function(...) {
## tryCatch(.f(...), error = function(e) {
## if (!quiet)
## message("Error: ", e$message) ## <--- tweak
## otherwise
## }, interrupt = function(e) {
## stop("Terminated by user", call. = FALSE)
## })
## }
## }
调整函数:
possibly2 <- function (.f, otherwise, quiet = TRUE) {
.f <- as_mapper(.f)
force(otherwise)
function(...) {
tryCatch(.f(...), error = function(e) {
if (!quiet)
return(e$message) ## <-- tweaked
otherwise
}, interrupt = function(e) {
stop("Terminated by user", call. = FALSE)
})
}
}
示例:
safer_foo <- possibly2(.f = foo, otherwise = "error",
quiet = FALSE ## don't forget to "unquiet"
)
## all other objects / code as in your example
输出:
## > output_list
## $A
## # A tibble: 1 x 1
## sum
## <int>
## 1 55
##
## $B
## [1] "No column with name B found."
##
## $C
## [1] "All values of column C are missing."
编辑
实际上,possibly2
继承了不再需要的代码。省略
不需要的静态参数 otherwise
和 quiet
,并跳过用户中断的处理程序,所需代码缩减为:
possibly2 <- function (.f) {
.f <- as_mapper(.f)
function(...) {
tryCatch(.f(...), error = function(e) e$message)
}
}
我编写了一个自定义函数,该函数执行多项检查并在检查失败时抛出不同的错误。 下面是一个简单的示例函数,它接受一个 data.frame 和一个列名,并简单地输出该列的总和。我正在使用 purrr::possibly() 创建该函数的保存版本,以便我可以遍历列名向量。
foo <- function(df, var){
#check 1
if(var %in% names(df) == FALSE){
stop(paste0("No column with name ", var, " found."))}
#check 2
if(all(is.na(dplyr::select(df, {{var}})))) {
stop(paste0("All values of column ", var, " are missing."))}
# main function
result <- df %>%
dplyr::rename(var = {{var}}) %>%
dplyr::summarise(sum = sum(var))
#print(result) printing shows the correct error messages
}
safer_foo <- purrr::possibly(.f = foo, otherwise = "error", quiet = FALSE)
我使用 purrr::map 遍历列向量并将输出存储在列表中。但是,对于函数失败的元素,我想存储特定的错误消息,而不是 purrr::possibly 要求的“否则”参数的静态输入。 将 purrr::possibly 替换为 purrr::safely 实际上会捕获列表的 $error 元素中预期的特定错误消息,但我想避免安全创建的额外嵌套级别。
test_df <- tibble(A = 1:10, C = NA)
input <- c("A", "B", "C")
output_list <- map(input, ~safer_foo(test_df, .x)) %>% set_names(input)
输出
> output_list
sum
<int>
1 55
$B
[1] "error"
$C
[1] "error"
期望的输出
> output_list
sum
<int>
$A 55
$B
[1] "Error: No column with name B found."
$C
[1] "Error: All values of column C are missing."
您可以将 purrr::possibly()
从其原始代码调整为 return 而不是 message 错误。
原代码:
## > possibly
## function (.f, otherwise, quiet = TRUE)
## {
## .f <- as_mapper(.f)
## force(otherwise)
## function(...) {
## tryCatch(.f(...), error = function(e) {
## if (!quiet)
## message("Error: ", e$message) ## <--- tweak
## otherwise
## }, interrupt = function(e) {
## stop("Terminated by user", call. = FALSE)
## })
## }
## }
调整函数:
possibly2 <- function (.f, otherwise, quiet = TRUE) {
.f <- as_mapper(.f)
force(otherwise)
function(...) {
tryCatch(.f(...), error = function(e) {
if (!quiet)
return(e$message) ## <-- tweaked
otherwise
}, interrupt = function(e) {
stop("Terminated by user", call. = FALSE)
})
}
}
示例:
safer_foo <- possibly2(.f = foo, otherwise = "error",
quiet = FALSE ## don't forget to "unquiet"
)
## all other objects / code as in your example
输出:
## > output_list
## $A
## # A tibble: 1 x 1
## sum
## <int>
## 1 55
##
## $B
## [1] "No column with name B found."
##
## $C
## [1] "All values of column C are missing."
编辑
实际上,possibly2
继承了不再需要的代码。省略
不需要的静态参数 otherwise
和 quiet
,并跳过用户中断的处理程序,所需代码缩减为:
possibly2 <- function (.f) {
.f <- as_mapper(.f)
function(...) {
tryCatch(.f(...), error = function(e) e$message)
}
}