【问题标题】:(tidy, glance, augment) with exec(整洁,一目了然,增强)与 exec
【发布时间】:2020-05-26 14:14:56
【问题描述】:

我从purrr 文档中看到,应该可以使用map(list(fn1, fn2, fn3), exec, !!!args) 语法或类似的东西将函数列表映射到参数上。对于broom 函数tidyglanceaugment,这将如何工作,通常必须用do 进行补充?这是我几乎总是喜欢在相同的数据和模型上同时执行的三个功能。当然我可以明确地这样做:

# works but is repetitive
MY_MODEL <- hp ~ cyl
my_glance <- mtcars %>% do(glance(lm(data = ., formula = MY_MODEL)))
my_tidy <- mtcars %>% do(tidy(lm(data = ., formula = MY_MODEL)))
my_augment <- mtcars %>% do(augment(lm(data = ., formula = MY_MODEL)))

我怀疑有一种更好、更紧凑的方法可以做到这一点,而不必每次都重新输入...lm(data = ., formula = MY_MODEL...,但我想不通。我试过了

# doesn't work
omnibroom <- function(df, model){
    map(list(glance, tidy, augment),
        exec,
        ~{(do(.x(lm(data = df, formula = model))))}
        )
    }

omnibroom(mtcars, MY_MODEL)

但我认为我没有正确理解 !!! 语法。

在同一个模型和数据上调用这三个 broom 函数是否有一个简洁的习惯用法

【问题讨论】:

    标签: r dplyr purrr rlang broom


    【解决方案1】:

    可以通过简单的重构在两行中完成此操作。不需要do!!!

    mdl <- mtcars %>% lm(data=., formula=MY_MODEL)
    res1 <- map( list(glance, tidy, augment), exec, mdl )
    

    如果您真的想将其压缩成一行,请使用{ 帮助将管道输入引导到lm 中的正确位置:

    res2 <- mtcars %>% 
        {map( list(glance, tidy, augment), exec, lm(data=., formula=MY_MODEL) )}
    

    验证:

    identical( res1, list(my_glance, my_tidy, my_augment) )    # TRUE
    identical( res1, res2 )                                    # TRUE
    

    编辑地址分组

    lm 等任意函数不尊重数据帧组。虽然do 是在这种情况下处理分组的一种流行方法,但我个人认为tidyr::nest() 更直观,因为它将所有中间体和结果与数据放在一起:

    ## "Listify" broom functions: f -> map( ..., f )
    omnibroom <- map( list(glance, tidy, augment), ~function(l) map(l, .x) ) %>%
        set_names( c("glance","tidy","augment") )
    
    result <- mtcars %>% nest( data = -gear ) %>%
        mutate( model = map(data, lm, formula=MY_MODEL) ) %>%
        mutate_at( "model", omnibroom )
    
    #  # A tibble: 3 x 6
    #     gear data              model  glance           tidy           augment
    #    <dbl> <list>            <list> <list>           <list>         <list>
    #  1     4 <tibble [12 × 10… <lm>   <tibble [1 × 11… <tibble [2 × … <tibble [12 × …
    #  2     3 <tibble [15 × 10… <lm>   <tibble [1 × 11… <tibble [2 × … <tibble [15 × …
    #  3     5 <tibble [5 × 10]> <lm>   <tibble [1 × 11… <tibble [2 × … <tibble [5 × 9…
    
    

    这种格式自然也适合取消嵌套,因为broom 函数会产生数据帧:

    result %>% select( gear, tidy ) %>% unnest( tidy )
    
    #  # A tibble: 6 x 6
    #     gear term        estimate std.error statistic p.value
    #    <dbl> <chr>          <dbl>     <dbl>     <dbl>   <dbl>
    #  1     4 (Intercept)    -5.00     25.3     -0.198 0.847
    #  2     4 cyl            20.2       5.30     3.82  0.00339
    #  3     3 (Intercept)   -47.5      56.1     -0.847 0.412
    #  4     3 cyl            30.0       7.42     4.04  0.00142
    #  5     5 (Intercept)  -101.       51.9     -1.94  0.148
    #  6     5 cyl            49.4       8.28     5.96  0.00944
    

    【讨论】:

    • 哇,比我想象的要简单得多。谢谢你。
    • 刚刚意识到这个解决方案不尊重数据框的分组,这是使用扫帚的主要原因之一。即这些给出相同的输出:out &lt;- mtcars %&gt;% {map( list(glance, tidy), exec, lm(data=., formula=MY_FORMULA) )}; out2 &lt;- mtcars %&gt;% group_by(gear) %&gt;% {map( list(glance, tidy), exec, lm(data=., formula=MY_FORMULA) )}
    • 嗨@CurtF。请查看我的编辑以解决分组问题。
    • 哦,哇,感谢您的编辑。如果可以的话,我会投票并接受第二次......
    猜你喜欢
    • 1970-01-01
    • 2017-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-19
    • 1970-01-01
    • 2023-02-08
    • 1970-01-01
    相关资源
    最近更新 更多