【问题标题】:Use a function name that's a string in map loop?在地图循环中使用作为字符串的函数名称?
【发布时间】:2021-03-26 14:07:00
【问题描述】:

一些代码:

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中调用,然后在上面的块中调用?

【问题讨论】:

    标签: r purrr


    【解决方案1】:

    可能在 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  
    

    【讨论】:

      【解决方案2】:

      我也发现可以用get:

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

      不确定何时使用其中一个。

      【讨论】:

        【解决方案3】:

        一个不同的选项可能是:

        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>  
        

        【讨论】:

        • 这看起来很有趣。我阅读了 exec 的文档,但并没有真正遵循或理解它?它是简单地将一个字符串翻译成它的等效函数,就像上面读到的那样,还是比这更微妙?
        【解决方案4】:

        由于 {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 年 8 月 28 日创建

        【讨论】:

          猜你喜欢
          • 2019-11-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-07-16
          • 1970-01-01
          相关资源
          最近更新 更多