У меня есть набор данных, в котором есть группы «gr1», «gr2» и «оба». По сути, я хотел бы сгруппировать столбец «gr» по c("gr1", "both") и c("gr2", "both").

Здесь я предлагаю решение с простым фреймом данных, но я хотел бы знать, есть ли способ сделать «сложную» группировку, такую ​​как group_by(gr ''using c("gr1", "both") and c("gr2", "both") as groups'' ). Есть ли способ указать, что группировать вместе в dplyr, вместо того, чтобы делать кожуру, как показано ниже?

library(tidyverse)
set.seed(1234)

df = data.frame(x = 1:10, id = sample(LETTERS[1:3], size = 10, replace = TRUE),
           gr = c(rep("gr1",3), rep("gr2",4),rep("both",3)))

df
    x id   gr
1   1  B  gr1
2   2  B  gr1
3   3  A  gr1
4   4  C  gr2
5   5  A  gr2
6   6  A  gr2
7   7  B  gr2
8   8  B both
9   9  C both
10 10  B both

sum.gr1 = df %>% 
  filter(gr %in% c("gr1", "both")) %>% 
  group_by(id) %>% 
  summarize(x.sum = sum(x)) %>% 
  mutate(gr.filt = "gr1.both")

sum.gr2 = df %>% 
  filter(gr %in% c("gr2", "both")) %>% 
  group_by(id) %>% 
  summarize(x.sum = sum(x))%>% 
  mutate(gr.filt = "gr2.both")

df.gr = rbind(sum.gr1, sum.gr2)
df.gr

# A tibble: 6 × 3
id    x.sum gr.filt 
<chr> <int> <chr>   
1 A         3 gr1.both
2 B        21 gr1.both
3 C         9 gr1.both
4 A        11 gr2.both
5 B        25 gr2.both
6 C        13 gr2.both
1
M. Beausoleil 24 Май 2023 в 21:37

2 ответа

Лучший ответ

Здесь я комбинирую «не оба» данных с версией «обоих» данных, где каждая строка была скопирована в каждую из «не обоих» групп.

library(dplyr)
bind_rows(
  df |> filter(gr != "both"),
  df |> filter(gr == "both") |> select(-gr) |>
    tidyr::crossing(gr = unique(df$gr[df$gr != "both"]))
) |>
  count(gr = paste0(gr, ".both"), id, wt = x)

Результат

        gr id  n
1 gr1.both  A  3
2 gr1.both  B 21
3 gr1.both  C  9
4 gr2.both  A 11
5 gr2.both  B 25
6 gr2.both  C 13
2
Jon Spring 24 Май 2023 в 21:53

Обновление после уточнения:

Вот версия с использованием map_df:

library(dplyr)
library(purrr)

map_df(list(c("gr1", "both"), c("gr2", "both")), ~df %>% 
                        filter(gr %in% .x) %>% 
                        group_by(id) %>% 
                        summarize(x.sum = sum(x)) %>% 
                        mutate(gr.filt = paste(.x, collapse = ".")))
 id    x.sum gr.filt 
  <chr> <int> <chr>   
1 A         3 gr1.both
2 B        21 gr1.both
3 C         9 gr1.both
4 A        11 gr2.both
5 B        25 gr2.both
6 C        13 gr2.both
2
TarJae 24 Май 2023 в 22:13
Пожалуйста, посмотрите мое обновление!
 – 
TarJae
24 Май 2023 в 22:14