purrr::possibly 函数可能无法与 map2_chr 函数一起使用

purrr::possibly function possibly not working with map2_chr function

我怀疑这是 purrr 包中的错误,但请先在 Whosebug 中检查我的逻辑。

在我看来,possibly 函数在 map2_chr 函数内部不起作用。我正在使用 purrr 版本 0.2.5

考虑这个例子:

library(dplyr)
library(purrr)

lets <- tibble(posn = 2:0,
               lets_list = list(letters[1:5], letters[1:5], letters[1:5])) %>% 
  glimpse()

returns

Observations: 3
Variables: 2
$ posn      <int> 2, 1, 0
$ lets_list <list> [<"a", "b", "c", "d", "e">, <"a", "b", "c", "d", "e">, <"a", "b", "c", "d", "e">]

在此示例中,我想根据 "posn".

中的值使用 return 列表 "lets_list" 中的元素变异来创建另一列
lets %>% 
  mutate(lets_sel = map2_chr(lets_list, posn, ~.x[.y]))

失败并显示此错误消息,因为第三行的位置 = 0。

> lets %>% 
+   mutate(lets_sel = map2_chr(lets_list, posn, ~.x[.y]))
#    Error in mutate_impl(.data, dots) : 
#      Evaluation error: Result 3 is not a length 1 atomic vector.

possibly 函数与 map2_chr return 一起使用也是一个错误。

lets %>% 
  mutate(lets_sel = map2_chr(lets_list, posn, possibly(~.x[.y], NA_character_)))
# Error in mutate_impl(.data, dots) : 
#  Evaluation error: Result 3 is not a length 1 atomic vector.

但是,map2 函数工作正常:

> lets %>% 
+   mutate(lets_sel = map2(lets_list, posn, possibly(~.x[.y], NA_character_)))
# A tibble: 3 x 3
   posn lets_list lets_sel 
  <int> <list>    <list>   
1     2 <chr [5]> <chr [1]>
2     1 <chr [5]> <chr [1]>
3     0 <chr [5]> <chr [0]>

解决方法是先使用 map2,然后再使用 map_chr,但我怀疑这是一个错误。

> lets %>% 
+   mutate(lets_sel = map2(lets_list, posn, ~.x[.y]),
+          lets_sel = map_chr(lets_sel, possibly(~.x[1], NA_character_)))
    # A tibble: 3 x 3
       posn lets_list lets_sel
      <int> <list>    <chr>   
    1     2 <chr [5]> b       
    2     1 <chr [5]> a       
    3     0 <chr [5]> NA      

我是不是漏掉了什么? 谢谢。

好的,现在我认为这只是一个 "feature"。最优雅的解决方案/解决方法是:

lets %>% 
  mutate(lets_sel = map2(lets_list, posn, ~.x[.y]) %>% 
           map_chr(., possibly(~.x[1], NA_character_)))

帮助屏幕中没有任何地方建议可以安全且可能地与 map2 系列函数一起使用。因此我得出结论,这是 "feature" 而不是 "bug".
谢谢。

possibly() 不起作用,因为使用 0 进行索引不会引发错误; 它只是 returns 一个长度为 0 的向量:

nth_letter <- function(n) letters[n]

possibly(nth_letter, "not returned")(0)
#> character(0)

nth_letter(0)
#> character(0)

在这种情况下,用 NA 替换无效索引可能会更容易 (使用例如 dplyr::na_if(),或者如果真正的问题更复杂,则使用普通的旧 ifelse)得到你想要的:

lets %>% 
  mutate(lets_sel = map2_chr(lets_list, na_if(posn, 0), ~ .x[.y]))
#> # A tibble: 3 x 3
#>    posn lets_list lets_sel
#>   <int> <list>    <chr>   
#> 1     2 <chr [5]> b       
#> 2     1 <chr [5]> a       
#> 3     0 <chr [5]> <NA>

reprex package (v0.2.0.9000) 创建于 2018-08-07。