Вычислите количество случаев в течение определенного периода времени

#r #frequency

Вопрос:

У меня есть следующие данные, где идентификатор означает физическое лицо, Дата для даты и Куплено для того, совершил ли кто-то покупку (я сделал это в последний раз, чтобы я мог подсчитать случаи):

    ID       Date Purchased
1   1 2017-01-01         1
2   1 2017-08-03         1
3   1 2017-09-02         1
4   2 2017-09-04         1
5   2 2018-07-12         1
6   2 2018-11-03         1
7   2 2018-12-05         1
8   2 2019-01-01         1
9   3 2018-02-03         1
10  3 2020-02-03         1
11  3 2020-03-01         1
 

Я хотел бы создать переменную под названием «Частота», которая вычисляет количество раз, когда человек совершал покупку в прошлом году, суммируя все «Купленные» до определенной даты, которую вы видите во фрейме данных.

Так, например, для строки 3 это приведет к «Частоте» 2, так 2017-01-01 2017-08-03 как и то, и другое в течение одного года 2017-09-02 (то есть в интервале 2016-09-02 и 2017-09-01 ).
См. Желаемый результат:

    ID       Date Purchased Frequency
1   1 2017-01-01         1         0
2   1 2017-08-03         1         1
3   1 2017-09-02         1         2
4   2 2017-09-04         1         0
5   2 2018-07-12         1         1
6   2 2018-11-03         1         1
7   2 2018-12-05         1         2
8   2 2019-01-01         1         3
9   3 2018-02-03         1         0
10  3 2020-02-03         1         0
11  3 2020-03-01         1         1
 

Для воспроизведения кадра данных:

 df <- data.frame(ID = c(1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3), Date = as.Date(c('2017-01-01', '2017-08-03', '2017-09-02', '2017-09-04', '2018-07-12', '2018-11-03', '2018-12-05', '2019-01-01', '2018-02-03', '2020-02-03', '2020-03-01')), Purchased = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ))
 

Я искал в stackoverlow, но пока не смог найти ответа, который я мог бы применить к своей ситуации и получить желаемые результаты. Одна из вещей, которую я нашел и попробовал, заключалась в следующем:

 df$frequency <-
sapply(df$Date, function(x){
sum(df$Date < x amp; df$Date >= x - 365)
})
 

Я считаю, что это может дать мне желаемые результаты, если я смогу найти способ включить, что он группируется по идентификатору (таким образом, он суммируется по идентификатору, а не в целом). Конечно, не могу сказать наверняка, так как я не смог это проверить. Мы очень ценим любую помощь.

Ответ №1:

Вот tidyverse решение :

 library(dplyr)
library(purrr)
library(lubridate)

df %>%
  group_by(ID) %>%
  mutate(Frequency = map_dbl(Date, 
                     ~sum(Purchased[between(Date, .x - years(1), .x - 1)]))) %>%
  ungroup

#      ID Date       Purchased Frequency
#   <dbl> <date>         <dbl>     <dbl>
# 1     1 2017-01-01         1         0
# 2     1 2017-08-03         1         1
# 3     1 2017-09-02         1         2
# 4     2 2017-09-04         1         0
# 5     2 2018-07-12         1         1
# 6     2 2018-11-03         1         1
# 7     2 2018-12-05         1         2
# 8     2 2019-01-01         1         3
# 9     3 2018-02-03         1         0
#10     3 2020-02-03         1         0
#11     3 2020-03-01         1         1
 

Логика кода заключается в том, что для каждого Date в каждом ID это sum Purchased значение между текущей датой — 1 год и текущей датой — 1 день.

Комментарии:

1. Уважаемый Ронак Шах, могу ли я попросить краткого объяснения механизма вашего кода. Это блестящая идея, но я не могу обмозговать ее и не могу понять, как она обрабатывает итерацию в столбце Даты. Заранее большое вам спасибо.

2. На самом деле, это просто. Для каждого date из них суммируется Purchased значение между прошлым годом и текущей датой.

Ответ №2:

Вы можете использовать неэквивалентные соединения с data.table :

 library(data.table)

setDT(df)
df[,c("Date","Before"):=.(as.Date(Date),as.Date(Date)-365)]
df[df,.(ID, Date),on=.(ID=ID, Date>=Before, Date<=Date)][,.N-1,by=.(ID,Date)]

   ID       Date V1
 1:  1 2017-01-01  0
 2:  1 2017-08-03  1
 3:  1 2017-09-02  2
 4:  2 2017-09-04  0
 5:  2 2018-07-12  1
 6:  2 2018-11-03  1
 7:  2 2018-12-05  2
 8:  2 2019-01-01  3
 9:  3 2018-02-03  0
10:  3 2020-02-03  0
11:  3 2020-03-01  1