Вычисление разницы между датами на основе группировки одного или нескольких столбцов

Пример моего набора данных приведен ниже:

| id |       Date | Buyer    |
|:--:|-----------:|----------|
|  9 | 11/29/2018 | Jenny    |
|  9 | 11/29/2018 | Jenny    |
|  9 | 11/29/2018 | Jenny    |
| 4  | 5/30/2018  | Chang    |
| 4  | 7/4/2018   | Chang    |
| 4  | 8/17/2018  | Chang    |
| 5  | 5/25/2018  | Chunfei  |
| 5  | 2/13/2019  | Chunfei  |
| 5  | 2/16/2019  | Chunfei  |
| 5  | 2/16/2019  | Chunfei  |
| 5  | 2/23/2019  | Chunfei  |
| 5  | 2/25/2019  | Chunfei  |
| 8  | 2/28/2019  | Chunfei  |
| 8  | 2/28/2019  | Chunfei  |

У меня есть два блока вопросов по этому набору данных:

  1. Мне нужно рассчитать разницу между датами, но эта разница будет рассчитываться на основе группировки «Покупатель» и «идентификатор», что означает, что разница в датах для покупателя «Дженни» и идентификатора «9» будет одной группой, покупатель «Чанг». 'с идентификатором' 4 'будет другой группой, а покупатель' Chunfei 'с идентификатором' 5 'будет другой группой, а' Chunfei 'с идентификатором' 8 'будет другой группой. Итак, на выходе получится:
| id |       Date | Buyer_id | Diff |
|:--:|-----------:|----------|------|
|  9 | 11/29/2018 | Jenny    | NA   |
|  9 | 11/29/2018 | Jenny    | 0    |
|  9 | 11/29/2018 | Jenny    | 0    |
| 4  | 5/30/2018  | Chang    | NA   |
| 4  | 7/4/2018   | Chang    | 35   |
| 4  | 8/17/2018  | Chang    | 44   |
| 5  | 5/25/2018  | Chunfei  | NA   |
| 5  | 2/13/2019  | Chunfei  | 264  |
| 5  | 2/16/2019  | Chunfei  | 3    |
| 5  | 2/16/2019  | Chunfei  | 0    |
| 5  | 2/23/2019  | Chunfei  | 7    |
| 5  | 2/25/2019  | Chunfei  | 2    |
| 8  | 2/28/2019  | Chunfei  | NA   |
| 8  | 2/28/2019  | Chunfei  | 0    |

Проблема в том, что я не понимаю, почему group_by не работает. Следующий код вычитает последовательные строки, а не группирует их для одного и того же покупателя и идентификатора, а затем вычитает.

df=data.frame(id=c("9","9","9","4","4","4","5","5","5","5","5","5","8","8"), 
              Date=c("11/29/2018","11/29/2018","11/29/2018","5/30/2018","7/4/2018", 
                      "8/17/2018","5/25/2018","2/13/2019","2/16/2019","2/16/2019","2/23/2019",
                      "2/25/2019","2/28/2019","2/28/2019"),Buyer=c("Jenny","Jenny","Jenny",
                      "Chang","Chang","Chang","Chunfei","Chunfei","Chunfei","Chunfei","Chunfei",
                      "Chunfei","Chunfei","Chunfei"))
df$id=as.numeric(as.character(df$id))
df$Date=as.Date(df$Date, "%m/%d/%Y")
df$Buyer=as.character(df$Buyer)

df1=df %>% group_by(Buyer,id) %>%
  mutate(diff=as.numeric(difftime(Date,lag(Date),units='days')))
  1. После вычисления разницы дат мне нужно отфильтровать те записи, разница между датами которых составляет 5 дней. В приведенном выше примере разница дат между "25.05.2018", "13.02.2019", "16.02.2019", "16.02.2019", "23.02.2019", " 25.02.2019 »будет NA, 264,3,0,7,2. Однако, если я предоставлю фильтр для n ‹6, я пропущу даты« 13.02.2019 »и« 23.02.2019 ». Эти даты важно сохранить в окончательном выводе, потому что, хотя разница между датами «13.02.2019» и «25.05.2018» составляет 264, разница между «16.02.2019» и «2» / 13/2019 "равно 3. Точно так же, хотя разница между" 16.02.2019 "и" 23.02.2019 "равна 7, разница между" 23.02.2019 "и" 25.02.2019 " "равно 2. Итак, мне нужно сохранить эти даты. Как этого добиться?

Мы можем замаскировать столбец 'diff' в окончательном выводе, и он должен выглядеть, как показано ниже:

| id |    Date    | Buyer_id |
|----|:----------:|---------:|
| 9  | 11/29/2018 |    Jenny |
| 9  | 11/29/2018 |    Jenny |
| 9  | 11/29/2018 |    Jenny |
| 5  | 2/13/2019  | Chunfei  |
| 5  | 2/16/2019  | Chunfei  |
| 5  | 2/16/2019  | Chunfei  |
| 5  | 2/23/2019  | Chunfei  |
| 5  | 2/25/2019  | Chunfei  |
| 8  | 2/28/2019  | Chunfei  |
| 8  | 2/28/2019  | Chunfei  |

person hk2    schedule 11.09.2019    source источник


Ответы (1)


Мы можем использовать diff для вычитания Date и выбора групп, в которых есть хотя бы одно значение, которое меньше 5 дней.

library(dplyr)

df %>%
  group_by(id, Buyer) %>%
  filter(any(diff(Date) <= 5))

#      id Date       Buyer  
#   <dbl> <date>     <chr>  
# 1     9 2018-11-29 Jenny  
# 2     9 2018-11-29 Jenny  
# 3     9 2018-11-29 Jenny  
# 4     5 2018-05-25 Chunfei
# 5     5 2019-02-13 Chunfei
# 6     5 2019-02-16 Chunfei
# 7     5 2019-02-16 Chunfei
# 8     5 2019-02-23 Chunfei
# 9     5 2019-02-25 Chunfei
#10     8 2019-02-28 Chunfei
#11     8 2019-02-28 Chunfei

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

df %>%
  group_by(id, Buyer) %>%
  mutate(diff = c(NA, diff(Date))) %>%
  slice({i1 <- which(diff <= 5); unique(c(i1, i1-1))}) %>%
  select(-diff)

#      id Date       Buyer  
#   <dbl> <date>     <chr>  
# 1     5 2019-02-16 Chunfei
# 2     5 2019-02-16 Chunfei
# 3     5 2019-02-25 Chunfei
# 4     5 2019-02-13 Chunfei
# 5     5 2019-02-23 Chunfei
# 6     8 2019-02-28 Chunfei
# 7     8 2019-02-28 Chunfei
# 8     9 2018-11-29 Jenny  
# 9     9 2018-11-29 Jenny  
#10     9 2018-11-29 Jenny  

данные

df <- structure(list(id = c(9, 9, 9, 4, 4, 4, 5, 5, 5, 5, 5, 5, 8, 
8), Date = structure(c(17864, 17864, 17864, 17681, 17716, 17760, 
17676, 17940, 17943, 17943, 17950, 17952, 17955, 17955), class = "Date"), 
Buyer = c("Jenny", "Jenny", "Jenny", "Chang", "Chang", "Chang", 
"Chunfei", "Chunfei", "Chunfei", "Chunfei", "Chunfei", "Chunfei", 
"Chunfei", "Chunfei")), row.names = c(NA, -14L), class = "data.frame")
person Ronak Shah    schedule 11.09.2019
comment
Разница по-прежнему не рассчитывается по группам. Из-за этого я упускаю довольно много записей в моем исходном наборе данных. - person hk2; 11.09.2019
comment
Кроме того, когда мы выполняем строку, `` df1 = df% ›% group_by (id, Buyer)%›% mutate (diff = c (NA, diff (Date)))% ›% slice ({i1‹ - который (diff ‹= 5)})` `предполагается отфильтровать все, кроме записей с diff‹ = 5, но на выходе мы видим записи, которые также имеют diff -183 и -84. Почему это так? - person hk2; 11.09.2019
comment
@ hk2 Кажется, это работает с общими данными. Можете ли вы поделиться набором данных, в котором вышеуказанный метод не работает, чтобы его было легче отлаживать и предлагать решение? - person Ronak Shah; 12.09.2019
comment
Приведенный выше набор данных похож на мой исходный набор данных. Мой запрос заключается в том, что для указанного выше набора данных, когда я запускаю только этот набор строк `` df1 = df% ›% group_by (id, Buyer)%›% mutate (diff = c (NA, diff (Date)))% ›% Slice ({i1‹ - which (diff ‹= 5)})` `, почему он выводит записи со значениями -183 и -84 в столбце diff, хотя предполагается, что он отфильтровывает все else и сохранить записи с diff ‹= 5? Не могли бы вы мне это объяснить? - person hk2; 12.09.2019
comment
@ hk2 Для меня он отфильтровывает только те записи, где diff <=5. Можете еще раз проверить? df %>% group_by(id, Buyer) %>% mutate(diff = c(NA, diff(Date))) %>% slice(which(diff <= 5)) - person Ronak Shah; 13.09.2019
comment
Я проверил это еще раз, уменьшив размер своего набора данных. Это сработало. Большое спасибо! - person hk2; 13.09.2019