(убрать, взглянуть, дополнить) с помощью exec - PullRequest
1 голос
/ 26 мая 2020

Из документации purrr я вижу, что должна быть возможность сопоставить список функций с аргументами, используя синтаксис map(list(fn1, fn2, fn3), exec, !!!args) или что-то подобное. Как это будет работать для broom функций, tidy, glance и augment, которые обычно необходимо дополнять 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)

, но мне кажется, что я не понимаю синтаксис !!! должным образом.

Есть ли компактная идиома для вызова этих трех функций метлы в одной модели и данные ?

1 Ответ

1 голос
/ 28 мая 2020

Это можно сделать в две строки с простым перефакторингом. Не требуется do или !!!.

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

Если вы действительно хотите свести sh его в одну строку, используйте {, чтобы направить ввод трубы в правильное место в 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
...