4

我正在处理我在数据框中收集的一些数据,我想在其中将函数应用于列的所有元素。通常我用purrr::map()这个。但是,如果函数为列的元素之一返回错误,有时这将不起作用:

f <- function(x) {
  if(x==2) stop("I hate 2") else x
}

library(dplyr)
dd <- data.frame(x = c(1:2))
dd2 <- dd %>% 
  mutate(fx = purrr::map(.x = x, .f = ~f(.)))
Error: I hate 2

所以我可以用 包装我的函数ftry()并获得一列结果:

> dd2 <- dd %>% 
+   mutate(fx = purrr::map(.x = x, .f = ~try(f(.))))
Error in f(.) : I hate 2
> dd2
  x                         fx
1 1                          1
2 2 Error in f(.) : I hate 2\n

现在,我理想情况下想用它filter()来过滤掉有错误的行,但我似乎无法做到这一点。这些都不会产生只有第一行的数据框:

dd2 %>% filter(is.integer(fx) )
dd2 %>% filter(is.integer(.$fx) )

dd2 %>% filter(class(fx) != "try-error")
dd2 %>% filter(class(.$fx) != "try-error")

lapply(dd2, is.numeric)

我正在考虑的一个肮脏的技巧是try_catch()改用它,并使其返回与f()错误情况相同类型的对象,例如-99999此处,然后将其过滤掉,但我正在寻找更清洁的解决方案。

4

1 回答 1

8

因为您已经在使用 purrr,所以您可能会尝试使用safely. 此函数包装一个函数并使其返回一个包含两个元素resulterror. 其中之一总是NULL.

这是数据设置,类似于原始帖子。

library(dplyr)
df <- data.frame(x = c(1:2, 1))

f <- function(x) {
  if (x == 2) stop("I hate 2") else x
}

我们用包装函数safely并调用它。

f_safe <- purrr::safely(f)

df2 <- df %>% mutate(fxx = x %>% purrr::map(.f = f_safe))
df2
#>   x               fxx
#> 1 1                 1
#> 2 2 I hate 2, .f(...)
#> 3 1                 1

我们可以确认这fxx是一个列表列,每个列表中都有resulterror元素。

str(df2$fxx)
#> List of 3
#>  $ :List of 2
#>   ..$ result: num 1
#>   ..$ error : NULL
#>  $ :List of 2
#>   ..$ result: NULL
#>   ..$ error :List of 2
#>   .. ..$ message: chr "I hate 2"
#>   .. ..$ call   : language .f(...)
#>   .. ..- attr(*, "class")= chr [1:3] "simpleError" "error" "condition"
#>  $ :List of 2
#>   ..$ result: num 1
#>   ..$ error : NULL

现在,我们只需询问列表列中的每个元素是否error为空。

df2 <- df2 %>% 
  mutate(no_error = fxx %>% purrr::map_lgl(.f = ~ is.null(.x$error)))
df2
#>   x               fxx no_error
#> 1 1                 1     TRUE
#> 2 2 I hate 2, .f(...)    FALSE
#> 3 1                 1     TRUE

我使用map_lgl结果不是一个列表列,而是一个filter布尔值向量。

df2 %>% filter(no_error)
#>   x fxx no_error
#> 1 1   1     TRUE
#> 2 1   1     TRUE

如果我们想像使用fxx常规向量一样使用列,我们必须mutate(fxx = fxx %>% purrr::map_dbl("result"))首先将其从列表列转换为简单向量。

编辑:另一种解决方案是dplyr::failwith使用类似NAerror错误的标记值进行包装和使用,然后过滤与标记值匹配的元素。

于 2016-08-23T21:27:39.947 回答