通过根据条目和变量值之间传递的时间量创建唯一 ID 列来对数据帧行进行分组

Group dataframe rows by creating a unique ID column based on the amount of time passed between entries and variable values

当相同的变量以固定的日期间隔出现时,我试图将我的数据框的行分组到“课程”中。当时间频率出现差距或其中一个变量发生变化时,我想给它一个新的课程 ID。

举个例子,我的数据是这样的:

         Date     Name   Item
1  2018-06-02    Johan  Apple
2  2018-07-05    Johan  Apple
3  2018-08-02    Johan  Apple
4  2019-04-15    Johan  Apple
5  2019-05-15    Johan  Apple
6  2019-05-30 Samantha Orange
7  2019-06-12 Samantha Orange
8  2019-06-27 Samantha Orange
9  2018-02-15     Mary  Lemon
10 2018-04-10     Mary  Lemon
11 2018-06-12     Mary  Lemon
12 2018-08-13     Mary   Lime
13 2018-08-27     Mary   Lime
14 2017-03-09   George   Kiwi

NameItem 的每个不同组合都应该生成一个新的课程 ID。

但是(棘手的部分)如果两个交易之间存在显着的时间差距,而其他变量是常数,则定义为:超过 6月 对于 ItemName 那么应该给它一个新的 CourseID

在我的例子中:

  • 因为 Johan 在 2018 年 8 月之后休息,之后的交易应该有一个新的 CourseID。理想情况下,检查未来休息时间的间隔将基于这个新组的平均值。
  • 萨曼莎每两周购买一次橙子,没有明显的缺口,因此她的所有交易都会有一个 CourseID
  • Mary 定期购买柠檬,但随后转为定期购买酸橙,因此这些有两个 CourseIDs。
  • George 刚买了一个 Kiwi,所以一个 CourseID

重现代码:

data.frame(Date = as.Date(c("2018-06-02", "2018-07-05", "2018-08-02", "2019-04-15", "2019-05-15", "2019-05-30", "2019-06-12", "2019-06-27", "2018-02-15", "2018-04-10", "2018-06-12", "2018-08-13", "2018-08-27", "2017-03-09")),
           Name = c(rep("Johan", 5), rep("Samantha", 3), rep("Mary", 5), "George"),
           Item = c(rep("Apple", 5), rep("Orange", 3), rep("Lemon", 3), rep("Lime",2), "Kiwi"))

我想创建一个额外的列,为每门课程提供唯一标识符 - 即使用 stringi 或类似的。

理想情况下输出应该是这样的:

         Date     Name   Item CourseID
1  2018-06-02    Johan  Apple      q3J
2  2018-07-05    Johan  Apple      q3J
3  2018-08-02    Johan  Apple      q3J
4  2019-04-15    Johan  Apple      f8j
5  2019-05-15    Johan  Apple      f8j
6  2019-05-30 Samantha Orange      p8U
7  2019-06-12 Samantha Orange      p8U
8  2019-06-27 Samantha Orange      p8U
9  2018-02-15     Mary  Lemon      wi9
10 2018-04-10     Mary  Lemon      wi9
11 2018-06-12     Mary  Lemon      wi9
12 2018-08-13     Mary   Lime      q8U
13 2018-08-27     Mary   Lime      q8U
14 2017-03-09   George   Kiwi      jJ0

我试过使用 max/min 日期变量来解决这个问题,但是当我根据之前的购买模式识别中断时,我感到很困惑。

可能有一个我不知道哪个包有这方面的东西,但是到目前为止我一直在尝试使用 Tidyverse。

这是一种 dplyr 方法,它计算每个 Name/Item 组内的差距和滚动平均差距,然后标记较大的差距,并为每个较大的差距或名称或项目的变化分配一个新组。

df1 %>%
  group_by(Name,Item) %>%
  mutate(purch_num = row_number(),
         time_since_first = Date - first(Date),
         gap = Date - lag(Date, default = as.Date(-Inf)),
         avg_gap = time_since_first / (purch_num-1),
         new_grp_flag = gap > 180 | gap > 3*avg_gap) %>%
  ungroup() %>%
  mutate(group = cumsum(new_grp_flag))