Дублируйте строки после суммирования с помощью case_when

#r #dplyr

Вопрос:

Я сталкиваюсь со странностью summarise , используя case_when с. Я использую case_when , потому что мне нужно выполнить другой расчет для подмножества моих групп. Но когда я это делаю, группы не распадаются, как ожидалось. Когда я запустил его без case_when , он рухнул. Вот пример.

Вот что я попробовал.

 df %>% 
  group_by(grp) %>% 
  summarize(value = case_when(grp == "g4" ~ sum(x), 
                              T ~ weighted.mean(x, w)), 
            .groups = "keep") %>% 
  ungroup()
## A tibble: 12 x 2
#grp        value
#<chr>      <dbl>
#1 g1        0.466 
#2 g1        0.466 
#3 g1        0.466 
#4 g2        0.439 
#5 g2        0.439 
#6 g2        0.439 
#7 g3        0.0885
#8 g3        0.0885
#9 g3        0.0885
#10 g4    15839     
#11 g4    15839     
#12 g4    15839 
 

Как вы можете видеть, все группы дублируются, а не сворачиваются. Если я выну case_when (или ifelse ) и использую одно вычисление для столбца, то фрейм данных выйдет, как и ожидалось, хотя значение «g4» неверно, так как я не использовал правильную функцию.

 df %>% 
  group_by(grp) %>% 
  summarize(value = weighted.mean(x, w), 
            .groups = "keep") %>% 
  ungroup()
## A tibble: 4 x 2
#grp       value
#<chr>     <dbl>
#1 g1       0.466 
#2 g2       0.439 
#3 g3       0.0885
#4 g4    6726.  
 

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

Данные:

 df <- structure(list(var = c("A", "A", "A", "A", "B", "B", "B", "B", 
                             "C", "C", "C", "C"), grp = c("g1", "g2", "g3", "g4", "g1", "g2", 
                                                          "g3", "g4", "g1", "g2", "g3", "g4"), x = c(0.374, 0.348, 0.067, 
                                                                                                     1531, 0.484, 0.461, 0.088, 8943, 0.47, 0.437, 0.095, 5365), w = c(4300, 
                                                                                                                                                                       4300, 4300, 4300, 19572, 19572, 19572, 19572, 15461, 15461, 15461, 
                                                                                                                                                                       15461)), row.names = c(NA, -12L), class = c("tbl_df", "tbl", 
                                                                                                                                                                                                                   "data.frame"))
 

Ответ №1:

Это связано с тем, что grp == "g4" сравнение возвращает более одного значения в каждой группе. Например, для группы 'g1' он возвращает 3 значения.

 df$grp[df$grp == 'g1'] == "g4"
#[1] FALSE FALSE FALSE
 

Поскольку входным условием является длина 3, выходные данные также будут иметь 3 значения. Чтобы иметь только одно значение в каждой группе, условие также должно возвращать только одно значение. Ты можешь завернуть его внутрь all .

 library(dplyr)

df %>% 
  group_by(grp) %>% 
  summarize(value = case_when(all(grp == "g4") ~ sum(x), 
                              T ~ weighted.mean(x, w)), 
            .groups = "drop") 

# A tibble: 4 x 2
#  grp        value
#  <chr>      <dbl>
#1 g1        0.466 
#2 g2        0.439 
#3 g3        0.0885
#4 g4    15839     
 

Вы также можете использовать if / else , так как здесь есть только 2 результата.

 df %>% 
  group_by(grp) %>% 
  summarize(value = if(all(grp == "g4")) sum(x) else weighted.mean(x, w), .groups = "drop")