условная функция суммирования dplyr - PullRequest
0 голосов
/ 25 апреля 2018

У меня есть такая ситуация, когда мне нужна другая сводка функция в зависимости от условия.Например, используя радужную оболочку, скажем, по какой-то причине я хотел получить сумму ширины лепестка, если у вида был setosa, в противном случае я хотел бы получить среднее значение ширины лепестка.

Наивно я написал это с помощью case_when, который не работает:

iris <- tibble::as_tibble(iris)

 iris %>% 
  group_by(Species) %>% 
  summarise(pwz = case_when(
    Species == "setosa" ~ sum(Petal.Width, na.rm = TRUE),
    TRUE                ~ mean(Petal.Width, na.rm = TRUE)))

Ошибка в summarise_impl (.data, dots): столбец pwz должен иметь длину 1 (итоговое значение), а не 50

В конце концов я нашел что-то вроде этого, суммируя, используя каждый метод, а затем в мутировавшем наборе, который я действительно хотел:

iris %>% 
  group_by(Species) %>% 
  summarise(pws = sum(Petal.Width, na.rm = TRUE),
            pwm = mean(Petal.Width, na.rm = TRUE)) %>% 
  mutate(pwz = case_when(
    Species == "setosa" ~ pws,
    TRUE                ~ pwm)) %>% 
  select(-pws, -pwm)

Но это кажется более чем немногоНеловко создавать все эти обобщенные значения и выбирать только одно в конце, особенно когда мой настоящий case_when намного сложнее.Могу ли я не использовать case_when внутри суммирования?У меня неправильный синтаксис?Любая помощь приветствуется!

Редактировать: Полагаю, я должен был указать, что у меня есть несколько условий / функций (просто предположим, что у меня есть, в зависимости от переменной, некоторые из них, которые требуют среднего, суммы, максимума, минимума или другого резюме).

Ответы [ 5 ]

0 голосов
/ 28 апреля 2018

Вы можете разделить ваш data.frame, а затем использовать map2_dfr, чтобы применить разные функции к каждой части и соединить результаты вместе:

library(tidyverse) # purrr & dplyr
iris %>%
  arrange(Species=="setosa") %>%
  split(.,.$Species=="setosa") %>%
  map2_dfr(c(mean,sum),~.x %>% group_by(Species) %>% summarize_at("Petal.Width",.y))

# # A tibble: 3 x 2
# Species Petal.Width
#       <fctr>       <dbl>
# 1 versicolor       1.326
# 2  virginica       2.026
# 3     setosa      12.300
0 голосов
/ 26 апреля 2018
data(iris)
library(dplyr)

sum_species <- c('setosa')

iris %>% 
   group_by(Species) %>% 
   summarise(pwz_sum = sum(Petal.Width, na.rm=T), 
             pwz_mean= mean(Petal.Width, na.rm=T)) %>% 
   ungroup() %>% 
   mutate(pwz = if_else(Species %in% sum_species, pwz_sum, pwz_mean))
0 голосов
/ 25 апреля 2018

Почему бы не рассчитать сначала на уровне строк, а затем суммировать?

iris %>% group_by(Species) %>% mutate(pwz = case_when(
      Species == "setosa" ~ sum(Petal.Width, na.rm = TRUE),
      TRUE                ~ mean(Petal.Width, na.rm = TRUE))) %>% 
      summarize(pwz= first(pwz))

# A tibble: 3 x 2
     Species    pwz
      <fctr>  <dbl>
1     setosa 12.300
2 versicolor  1.326
3  virginica  2.026
0 голосов
/ 25 апреля 2018

Это довольно легко с data.table

library(data.table)
iris2 <- as.data.table(iris)

iris2[, if(Species == 'setosa') sum(Petal.Width) 
        else mean(Petal.Width)
      , by = Species]

Более кратко, но, возможно, не так ясно

iris2[, ifelse(Species == 'setosa', sum, mean)(Petal.Width)
      , by = Species]

С dplyr вы можете сделать

iris %>% 
  group_by(Species) %>% 
  summarise(pwz = if_else(first(Species == "setosa")
                          , sum(Petal.Width)
                          , mean(Petal.Width)))

Примечание:

Я думаю, что, вероятно, имеет больше смысла "распространять" ваши данные с помощью tidyr::spread, чтобы каждый день имел столбец для температуры, осадков и т. Д. Затем вы можете использовать summarise обычным способом.

0 голосов
/ 25 апреля 2018

Вы всегда можете сделать что-то подобное, если хотите поместить все в функцию суммирования.Но это не менее сложно, чем ваш оригинальный обходной путь:

iris %>% 
  group_by(Species) %>% 
  summarise(pwz = 
    sum(Petal.Width, na.rm = TRUE)*
    (1/n()*mean(Species != "setosa") + 
     mean(Species == "setosa")))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...