在地图循环中使用作为字符串的函数名称?

Use a function name that's a string in map loop?

一些代码:

mymtcars <- mtcars %>% head %>% rownames_to_column('model') %>% group_by(vs) %>% nest
mymtcars
     vs data             
  <dbl> <list>           
1     0 <tibble [3 × 11]>
2     1 <tibble [3 × 11]>

我可以像这样在此列表列 df 上拟合线性模型:

mymtcars %>% 
+   mutate(mod = map(.x = data, ~ lm(.x$mpg ~ .x$cyl)))
# A tibble: 2 x 3
# Groups:   vs [2]
     vs data              mod   
  <dbl> <list>            <list>
1     0 <tibble [3 × 11]> <lm>  
2     1 <tibble [3 × 11]> <lm>  

如果我的函数名称是一个字段怎么办?

mymtcars2 <- mtcars %>% head %>% rownames_to_column('model') %>% group_by(vs) %>% nest %>% crossing(func = c('lm'))
> mymtcars2
# A tibble: 2 x 3
     vs data              func 
  <dbl> <list>            <chr>
1     0 <tibble [3 × 11]> lm   
2     1 <tibble [3 × 11]> lm

我试了一下:

mymtcars2 %>% 
+   mutate(mod = map2(.x = data, .y = func, ~ .y(.x$mpg ~ .x$cyl)))
Error: Problem with `mutate()` input `mod`.
x could not find function ".y"
ℹ Input `mod` is `map2(.x = data, .y = func, ~.y(.x$mpg ~ .x$cyl))`.

如何将函数传到map中调用,然后在上面的block中调用?

可能在 map2 中使用 match.fun,如下所示:

   models <-  mymtcars2 %>% 
       mutate(mod = map2(.x = data, .y = func, ~ match.fun(.y)(.x$mpg ~ .x$cyl)))

输出:

[[1]]

Call:
match.fun(.y)(formula = .x$mpg ~ .x$cyl)

Coefficients:
(Intercept)       .x$cyl  
  36.926733    -2.728218  


[[2]]

Call:
match.fun(.y)(formula = .x$mpg ~ .x$cyl)

Coefficients:
(Intercept)       .x$cyl  
    41.9400      -3.8025  

我还发现我可以使用 get:

mymtcars2 %>% 
  mutate(mod = map2(.x = data, .y = func, ~ get(.y)(.x$mpg ~ .x$cyl)))

我不确定什么时候该用一个。

另一个选项可能是:

mymtcars2 %>%
    mutate(mod = map2(.x = data,
                      .y = func,
                      ~ exec(.y, mpg ~ cyl, data = .x)))

     vs data              func  mod   
  <dbl> <list>            <chr> <list>
1     0 <tibble [3 × 11]> lm    <lm>  
2     1 <tibble [3 × 11]> lm    <lm>  

因为 {dplyr} >= 1.0 这种问题可以用 dplyr::rowwise 解决。我们可以将它与经典的 do.call 一起使用,在这种情况下我们必须将参数包装在 list() 中,或者与 rlang::exec 一起使用。使用 dlpyr::rowwise 我们不需要 map2 这使得事情更具可读性,因为 .x .y 没有 lambda 函数。但是,由于输出列存储 lm 个对象(而不是原子向量),因此结果必须包含在 mod = list(...).

library(tidyverse)

mymtcars2 %>% 
  rowwise %>% 
  mutate(mod = list(do.call(func, list(mpg ~ cyl, data = data))))
#> # A tibble: 2 x 4
#> # Rowwise: 
#>      vs data              func  mod   
#>   <dbl> <list>            <chr> <list>
#> 1     0 <tibble [3 × 11]> lm    <lm>  
#> 2     1 <tibble [3 × 11]> lm    <lm>

mymtcars2 %>% 
  rowwise %>% 
  mutate(mod = list(exec(func, mpg ~ cyl, data = data)))
#> # A tibble: 2 x 4
#> # Rowwise: 
#>      vs data              func  mod   
#>   <dbl> <list>            <chr> <list>
#> 1     0 <tibble [3 × 11]> lm    <lm>  
#> 2     1 <tibble [3 × 11]> lm    <lm>

reprex package (v0.3.0)

于 2021-08-28 创建