return 映射的 object if purrr:possibly() 内的表达式失败

return the mapped object if expression inside of purrr:possibly() fails

我有一个数据框,其中一列包含更多数据框。其中一个数据框缺少一列。我想从其他两个数据框中删除该列(如果存在)。

这是一个例子:

library(tidyverse)

mtcars %>%
group_by(cyl) %>%
nest -> tmp
tmp[3,'data'][[1]][[1]] <- dplyr::select(tmp[3,'data'][[1]][[1]], -mpg)

print(tmp)
# A tibble: 3 x 2
    cyl data              
  <dbl> <list>            
1    6. <tibble [7 × 10]> 
2    4. <tibble [11 × 10]>
3    8. <tibble [14 × 9]>

所以在这里,data 列包含三个小标题,最后一个不包含 mpg 列。我可以将 dplyr::select 映射到数据列上,并通过 returning NA 捕获错误,如下所示:

 tmp %>% mutate(data2 = map(data, possibly(~dplyr::select(.,-mpg), otherwise = NA)))
# A tibble: 3 x 3
    cyl data               data2            
  <dbl> <list>             <list>           
1    6. <tibble [7 × 10]>  <tibble [7 × 9]> 
2    4. <tibble [11 × 10]> <tibble [11 × 9]>
3    8. <tibble [14 × 9]>  <lgl [1]>

但我真正想做的是 return 输入数据。类似于:

 tmp %>% mutate(data2 = map(data, possibly(~dplyr::select(.,-mpg), otherwise = function(x){x})))
# A tibble: 3 x 3
    cyl data               data2            
  <dbl> <list>             <list>           
1    6. <tibble [7 × 10]>  <tibble [7 × 9]> 
2    4. <tibble [11 × 10]> <tibble [11 × 9]>
3    8. <tibble [14 × 9]>  <fn>

当然这只是 returns function(x){x} 作为 data2 的最后一行。

有什么妙招吗?或者在这种情况下我只需要使用 tryCatch 或更明确地处理错误?

possibly中的otherwise参数是一个常量,所以不会随着包装函数的输入而改变;你可能做的是将 possibly 包装在另一个可以从 data 访问元素的函数中,将元素设置为 otherwise:

my_select <- function(x) {
    f = possibly(function() select(x, -mpg), otherwise = x)
    f()
}

tmp %>% mutate(data2 = map(data, my_select))
# A tibble: 3 x 3
#    cyl data               data2            
#  <dbl> <list>             <list>           
#1  6.00 <tibble [7 x 10]>  <tibble [7 x 9]> 
#2  4.00 <tibble [11 x 10]> <tibble [11 x 9]>
#3  8.00 <tibble [14 x 9]>  <tibble [14 x 9]>

或采用公式形式:

tmp %>% 
    mutate(data2 = map(data, ~ (invoke(possibly(function() select(.,-mpg), otherwise = .)))))

# A tibble: 3 x 3
#    cyl data               data2            
#  <dbl> <list>             <list>           
#1     6 <tibble [7 × 10]>  <tibble [7 × 9]> 
#2     4 <tibble [11 × 10]> <tibble [11 × 9]>
#3     8 <tibble [14 × 9]>  <tibble [14 × 9]>