dplyr::group_by() с несколькими переменными, но НЕ пересечением

Когда вы group_by используете несколько переменных, dplyr помогает найти пересечение этих групп.

Например,

mtcars %>% 
  group_by(cyl, am) %>%
  summarise(mean(disp))

урожаи

Source: local data frame [6 x 3]
Groups: cyl [?]

    cyl    am `mean(disp)`
  <dbl> <dbl>        <dbl>
1     4     0     135.8667
2     4     1      93.6125
3     6     0     204.5500
4     6     1     155.0000
5     8     0     357.6167
6     8     1     326.0000

Мой вопрос: есть ли способ предоставить несколько переменных, но обобщить их маргинально? Я хочу, чтобы результат был таким же, как если бы вы делали это вручную, переменная за переменной.

df_1 <- 
  mtcars %>% 
  group_by(cyl) %>%
  summarise(est = mean(disp)) %>%
  transmute(group = paste0("cyl_", cyl), est)

df_2 <- 
  mtcars %>% 
  group_by(am) %>%
  summarise(est = mean(disp)) %>%
  transmute(group = paste0("am_", am), est)

bind_rows(df_1, df_2)

Приведенный выше код дает

# A tibble: 5 × 2
  group      est
  <chr>    <dbl>
1 cyl_4 105.1364
2 cyl_6 183.3143
3 cyl_8 353.1000
4  am_0 290.3789
5  am_1 143.5308

в идеале синтаксис должен быть примерно таким

mtcars %>%
group_by(cyl, am, intersection = FALSE) %>%
summarise(est = mean(disp))

Есть ли что-то подобное в tidyverse?

(p.s., я понимаю, что моя переменная group в таблице выше не является аккуратной в том смысле, что она содержит две переменные в одной, но я обещаю, что для моей цели она будет аккуратной, хорошо? :) )


person Alex Coppock    schedule 28.11.2016    source источник


Ответы (2)


Я предполагаю, что вы ищете пакет tidyr...

gather сначала дублирует набор данных, чтобы для каждого фактора было n строк, по которым будет происходить группировка; mutate затем создает группирующую переменную.

library(dplyr)
library(tidyr)

mtcars %>%
  gather(col, value, cyl, am) %>% 
  mutate(group = paste(col, value, sep = "_")) %>%
  group_by(group) %>% 
  summarise(est = mean(disp))
person denrou    schedule 28.11.2016
comment
Это отличное решение. Небольшое редактирование, чтобы сделать более общий df - person Alex Coppock; 29.11.2016

Альтернатива purrr:

library(tidyverse)

map(c('cyl', 'am'), 
    ~ mtcars %>% 
      group_by_(.x) %>%
      summarise(est = mean(disp)) %>%
      transmute_(group = lazyeval::interp(~paste0(.x, '_', y), y = as.name(.x)),
                 ~est)) %>% 
  bind_rows()
# A tibble: 5 × 2
  group      est
  <chr>    <dbl>
1 cyl_4 105.1364
2 cyl_6 183.3143
3 cyl_8 353.1000
4  am_0 290.3789
5  am_1 143.5308
person Axeman    schedule 28.11.2016