Как определить разницу между переменной и лагом, определяемую датой месяца для каждой группы?

По сути, у меня есть набор данных с переменными, указывающими группу, дату и значение переменной. Мне нужно взять разницу между значением и значением на конец прошлого года для каждой группы. Поскольку данные сбалансированы, я пытался сделать это с помощью dplyr::lag, вставив задержку с учетом месяца наблюдения:

x <- x %>% group_by(g) %>% mutate(y = v - lag(v, n=month(d))

Однако это не работает.

Результат должен быть:

Набор данных макета:

x <- data.frame('g'=c('B','B','B','C','A','A','A','A','A','A'),'d'=c('2018-11-30', '2018-12-31','2019-01-31','2019-12-31','2016-12-31','2017-11-30','2017-12-31','2018-12-31','2019-01-31','2019-02-28'),'v'=c(300,200,250,100,400,150,200,500,400,500))

Желаемая переменная:

y <- c(NA,NA,-50,NA,NA,-250,-200,300,-100,0)

Новый набор данных:

cbind(x,y)

person Ramiro    schedule 04.12.2019    source источник
comment
В вашем фиктивном наборе данных есть только 1 группа: A и 2 года: 2018 и 2019, тогда 2018-12-31 будет единственным концом предыдущего года для каждой группы. Я предполагаю, что для каждой группы не существует 3 последовательных лет (в противном случае на группу приходилось бы 2 года на конец предыдущего года). Затем вы можете 1) извлечь year component of the date - 1, чтобы получить предыдущий год, и 2) использовать max(), чтобы получить конец года.   -  person FannieY    schedule 05.12.2019
comment
Извините, я сделаю макет набора данных более полным. В самом деле, это то, к чему я стремлюсь. Тем не менее, в пайпе dplyr как можно взять значение той же группы с годом = год-1 и максимальным месяцем? Другими словами, создайте переменную y = x - x [year == year-1 & month = max (месяц этого года)]?   -  person Ramiro    schedule 05.12.2019
comment
Боюсь, я не могу получить значения вашей желаемой переменной (NA, NA, -50, NA, 500, 100, 0). Если введены данные data.frame ('g' = c ('B', 'B', 'B', 'C', 'A', 'A', 'A'), 'd' = c (' 2018-11-30 ',' 2018-12-31 ',' 2019-01-31 ',' 2017-12-31 ',' 2018-12-31 ',' 2019-01-31 ',' 2019- 02-28 '),' v '= c (300,200,250,400,500,400,500)), мой ожидаемый результат y: (NA, NA, 50, NA, NA, -100, 0).   -  person FannieY    schedule 05.12.2019
comment
Действительно, моя ошибка (на последнем этапе я хочу, чтобы в конце года извлекались не НО, а само значение, хотя это можно легко сделать с помощью предложения ifelse).   -  person Ramiro    schedule 05.12.2019


Ответы (2)


Идея через dplyr может заключаться в том, чтобы найти последний день, получить индекс и использовать его для вычитания, а затем преобразовать в NA, т.е.

library(dplyr)

x %>% 
 group_by(g) %>% 
 mutate(new = which(sub('^[0-9]+-([0-9]+-[0-9]+)$', '\\1', d) == '12-31'), 
        y = v - v[new], 
        y = replace(y, row_number() <= new, NA)) %>% 
 select(-new)

который дает,

# A tibble: 7 x 4
# Groups:   g [3]
  g     d              v     y
  <fct> <fct>      <dbl> <dbl>
1 B     2018-11-30   300    NA
2 B     2018-12-31   200    NA
3 B     2019-01-31   250    50
4 C     2017-12-31   400    NA
5 A     2018-12-31   500    NA
6 A     2019-01-31   400  -100
7 A     2019-02-28   500     0
person Sotos    schedule 05.12.2019
comment
Это не работает, потому что в моем наборе данных более двух лет на группу. Как я могу настроить синтаксический анализ так, чтобы он искал значения, которые имеют год = год-1 и «12-31», как в этом подходе? Я не знаком с регулярными выражениями - person Ramiro; 05.12.2019
comment
Это важная деталь, которую следует не учитывать. Пожалуйста, обновите свой набор данных и ожидаемый результат в вашем вопросе - person Sotos; 05.12.2019
comment
Ваш подход - это именно то, что я хочу, но я бы хотел, чтобы новое относилось к% y-1 + '- 12-31' - person Ramiro; 05.12.2019
comment
Добавил в набор данных - person Ramiro; 05.12.2019

В конце концов, я решил создать вспомогательную переменную («eoy»), чтобы указать строку соответствующего конца года для каждой группы для каждой строки. Это требует цикла и неэффективно, но облегчает оставшиеся вычисления, которые будут зависеть от этого. Желаемое вычисление будет выглядеть следующим образом:

мутировать ('y' = x - x [eoy])

person Ramiro    schedule 05.12.2019