Изменить метод суммирования () для конкретной группы - PullRequest
0 голосов
/ 04 мая 2018

Рассмотрим следующий фиктивный набор данных:

library(dplyr)
df <- structure(list(x = structure(c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 7L, 
                                     1L, 2L, 3L, 4L, 5L, 6L, 7L, 7L), 
                                   .Label = c("1", "2", "3", "4", 
                                              "5", "6", "Total"), class = "factor"), 
                     y = structure(c(1L, 1L, 
                                     2L, 2L, 3L, 3L, 4L, 4L, 1L, 1L, 2L, 2L, 3L, 3L, 4L, 4L), 
                                   .Label = c("7", "8", "9", "Total"), class = "factor"), 
                     z = structure(c(1L, 2L, 
                                     1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L), 
                                   .Label = c("10", "11"), class = "factor"), 
                     count = c(56, 89, 12, 119, 3, 2, 71, 
                               210, 22, 64, 53, 0, 136, 11, 211, 75), 
                     date = structure(c(17866, 
                                        17866, 17866, 17866, 17866, 17866, 17866, 17866, 17501, 17501, 
                                        17501, 17501, 17501, 17501, 17501, 17501), class = "Date")), 
                class = "data.frame", 
                row.names = c(NA, -16L), 
                .Names = c("x", "y", "z", "count", "date")) %>%
  filter(count != 0)

> df
       x     y  z count       date
1      1     7 10    56 2018-12-01
2      2     7 11    89 2018-12-01
3      3     8 10    12 2018-12-01
4      4     8 11   119 2018-12-01
5      5     9 10     3 2018-12-01
6      6     9 11     2 2018-12-01
7  Total Total 10    71 2018-12-01
8  Total Total 11   210 2018-12-01
9      1     7 10    22 2017-12-01
10     2     7 11    64 2017-12-01
11     3     8 10    53 2017-12-01
12     5     9 10   136 2017-12-01
13     6     9 11    11 2017-12-01
14 Total Total 10   211 2017-12-01
15 Total Total 11    75 2017-12-01

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

Вот неизмененная версия (что я не хочу, но уже близко):

df_yoy <- df %>%
  group_by(x, y, z) %>%
  summarize(YoY = count[date == max(date)]/count[date == min(date)] - 1) %>%
  as.data.frame()

> df_yoy
      x     y  z        YoY
1     1     7 10  1.5454545
2     2     7 11  0.3906250
3     3     8 10 -0.7735849
4     4     8 11  0.0000000
5     5     9 10 -0.9779412
6     6     9 11 -0.8181818
7 Total Total 10 -0.6635071
8 Total Total 11  1.8000000 <-- obtained by doing 210/75-1

Обратите внимание, как я конкретно называю последний ряд. Вот требования того, что я хочу:

  1. Значения count должны оставаться неизменными.
  2. count, когда x == 4 & y == 8 & z == 11 не было измерено на 2017-12-01. Таким образом, при расчете процентного изменения по сравнению с прошлым годом для общего количества строк означает, что в числителе count[date == max(date)].

Таким образом, вот вывод, который я ищу :

> df_yoy
      x     y  z        YoY
1     1     7 10  1.5454545
2     2     7 11  0.3906250
3     3     8 10 -0.7735849
4     4     8 11  0.0000000
5     5     9 10 -0.9779412
6     6     9 11 -0.8181818
7 Total Total 10 -0.6635071
8 Total Total 11  0.2133333 <-- obtained by doing (210-119)/75-1

Обратите внимание, что вычитание 119 из 210 является значением count, когда x == 4 & y == 8 & z == 11.

Есть ли способ изменить summarize() для выполнения этого изменения? Я уже пробовал играть с ifelse() и case_when(), но безуспешно.

1 Ответ

0 голосов
/ 05 мая 2018

Решение можно получить с помощью ungroup и перегруппировать, чтобы выполнить преобразование, используя dplyr.

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

library(dplyr)
df %>% mutate(count = ifelse(count==0, NA, count)) %>%
  group_by(x, y, z) %>%
  summarize(YoYNume = count[date == max(date)], YoYDeno = count[date == min(date)]) %>%
  group_by(z) %>%
  mutate(valueToDiscard = sum(ifelse(is.na(YoYDeno),YoYNume,0))) %>%
  mutate(YoYNume = ifelse(x=="Total", YoYNume - valueToDiscard, valueToDiscard)) %>%
  group_by(x,y,z) %>%
  summarise(YoY = YoYNume/YoYDeno - 1) %>%
  as.data.frame()

#       x     y  z        YoY
# 1     1     7 10 -1.0000000
# 2     2     7 11  0.8593750
# 3     3     8 10 -1.0000000
# 4     4     8 11         NA
# 5     5     9 10 -1.0000000
# 6     6     9 11  9.8181818
# 7 Total Total 10 -0.6635071
# 8 Total Total 11  0.2133333
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...