R: расчет отсутствующих ежемесячных значений

У меня есть набор данных с ежемесячными значениями, за исключением конца каждого квартала, где есть квартальные агрегированные данные. Меня также интересуют ежемесячные значения для этих месяцев, но их нужно рассчитать. Таким образом, для 3-го, 6-го, 9-го и 12-го месяца должен быть расчет, который вычитает значения предыдущих двух месяцев.

df <- data.frame(Name = c('AAA', 'AAA', 'AAA', 'AAA', 'AAA', 'AAA',
                          'BBB', 'BBB', 'BBB', 'BBB', 'BBB', 'BBB'),
                 Month = c('1', '2', '3', '4', '5', '6',
                           '1', '2', '3', '4', '5', '6'),
                 Year = c(2017, 2017, 2017, 2017, 2017, 2017, 
                          2017, 2017, 2017, 2017, 2017, 2017),
                 Value = c(100, 105, 315, 115, 120, 360,
                           100, 110, 330, 130, 140, 420))

В этом примере с игрушкой значение AAA в 3-м месяце 2017 года равно 110, и это значение должно заменить 315. Я пытаюсь создать код, который будет делать это для всех имен, всех лет, всех кварталов, но я могу ' Кажется, я не нашел способ автоматизировать это.

Можно попробовать require(dplyr) ; df %>% group_by(Name) %>% mutate(value2 = ifelse(Month%in%c(3,6,9,12),Value-(lag(Value,1)+lag(Value,2)‌​),Value))

count 11.04.2018 14:19

Всегда ли ваш data.frame полный (т.е. все месяцы до квартала)?

digEmAll 11.04.2018 14:21

Вы также можете добавить Year к вашему group_by, если в наборе данных больше одного года.

iod 11.04.2018 14:22

@digEmAll Да, верно

pkg 11.04.2018 14:28
0
4
74
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Вы можете попробовать это

library(dplyr)
df %>% mutate(Value = ifelse(as.numeric(Month) %% 3 == 0, 
                             Value - lag(Value,1) - lag(Value, 2), 
                             Value)) 

Это дает сообщение об ошибке «попытка использовать имя переменной нулевой длины».

pkg 11.04.2018 14:42

Извините, в коде произошла ошибка, теперь он должен работать

whalea 11.04.2018 14:44

Используя ave:

df$Value <- ave(1:nrow(df),df$Name,df$Year,
                FUN = function(x){
                  w <- which(df$Month[x] %in% c('3','6','9','12'))
                  v <- df$Value[x]
                  v[w] <- v[w] - v[w-1] - v[w-2]
                  v
                })

> df
   Name Month Year Value
1   AAA     1 2017   100
2   AAA     2 2017   105
3   AAA     3 2017   110
4   AAA     4 2017   115
5   AAA     5 2017   120
6   AAA     6 2017   125
7   BBB     1 2017   100
8   BBB     2 2017   110
9   BBB     3 2017   120
10  BBB     4 2017   130
11  BBB     5 2017   140
12  BBB     6 2017   150

Примечание: df необходимо отсортировать как минимум по возрастанию Month.

Немного другой подход, создание манекенов четверти и группировка.

Последняя строка определяет, какие месяцы делятся на 3, и вычисляет предполагаемое значение.

Чтобы использовать его в течение всего года, просто измените команду replicate на rep(1:4, each = 3).

library(dplyr)
df %>% 
  group_by(Name, Year) %>%
  mutate(quarter = rep(1:2, each = 3)) %>%
  group_by(Name, Year, quarter) %>%
  mutate(Value = ifelse(Month %% 3 == 0, 2*Value - sum(Value), Value))

# A tibble: 12 x 5
# Groups:   Name, Year, quarter [4]
   Name  Month  Year Value quarter
   <fct> <dbl> <dbl> <dbl>   <int>
 1 AAA      1. 2017.  100.       1
 2 AAA      2. 2017.  105.       1
 3 AAA      3. 2017.  110.       1
 4 AAA      4. 2017.  115.       2
 5 AAA      5. 2017.  120.       2
 6 AAA      6. 2017.  125.       2
 7 BBB      1. 2017.  100.       1
 8 BBB      2. 2017.  110.       1
 9 BBB      3. 2017.  120.       1
10 BBB      4. 2017.  130.       2
11 BBB      5. 2017.  140.       2
12 BBB      6. 2017.  150.       2

Возможность с data.table, если он отсортирован по Name, Year, Month, как в примере:

library(data.table)
setDT(df)

df[, Month := as.numeric(Month)]
df[Month %% 3 == 0,
   Value := Value - df[Month %% 3 != 0,Value][c(T,F)] - df[Month %% 3 != 0,Value][c(F,T)]]

Другие вопросы по теме