如何在R中按首个事件后的120天周期分组非重叠事件
按首个事件的120天非重叠周期分组DataFrame事件
核心思路
要实现基于组内首个事件的120天非重叠分组,关键是以每个新组的第一个事件日期为起点,计算120天周期范围,将所有落在该范围内的事件归为一组;超出范围的事件则作为新组的起始点,重复上述逻辑。之前用date < lag(period_end)的方式只依赖前一周期的结束日期,无法满足“以组内首个事件为基准”的需求。
实现步骤(以Pandas为例)
1. 准备并排序数据
首先必须确保数据按事件日期排序,否则分组逻辑会混乱:
import pandas as pd from datetime import timedelta # 示例数据 data = pd.DataFrame({ 'event_id': [1,2,3,4,5,6], 'date': pd.to_datetime([ '1992-05-09', '1992-09-08', '1992-11-15', '1993-01-06', '1993-03-10', '1993-04-20' ]) }) # 按日期排序并重置索引 data = data.sort_values('date').reset_index(drop=True)
2. 循环分组实现(易理解)
通过循环遍历,每次确定新组的起始日期和周期范围,标记对应事件的分组:
# 初始化分组列 data['group'] = None # 第一个组的起始与结束日期 current_group = 'A' current_start = data.loc[0, 'date'] current_end = current_start + timedelta(days=120) # 标记第一个组的事件 data.loc[data['date'] <= current_end, 'group'] = current_group # 处理剩余未分组事件 remaining = data[data['group'].isna()] while not remaining.empty: # 切换到下一个字母分组 current_group = chr(ord(current_group) + 1) # 新组的起始为剩余事件的第一个日期 current_start = remaining.iloc[0]['date'] current_end = current_start + timedelta(days=120) # 标记当前组的事件 data.loc[remaining.index[remaining['date'] <= current_end], 'group'] = current_group # 更新剩余事件列表 remaining = data[data['group'].isna()]
3. 高效矢量化风格实现(性能更优)
用累积标记的方式替代循环赋值,逻辑更紧凑:
data = data.sort_values('date').reset_index(drop=True) # 初始化分组编号,第一个事件归为第0组 group_num = [0] current_start = data['date'].iloc[0] for i in range(1, len(data)): # 若当前事件超出当前组的120天范围,则开启新组 if data['date'].iloc[i] > current_start + timedelta(days=120): group_num.append(group_num[-1] + 1) current_start = data['date'].iloc[i] else: group_num.append(group_num[-1]) # 将数字编号转为A/B/C样式的分组名 data['group'] = [chr(ord('A') + num) for num in group_num]
最终结果
执行后会得到符合预期的分组:
| event_id | date | group |
|---|---|---|
| 1 | 1992-05-09 | A |
| 2 | 1992-09-08 | B |
| 3 | 1992-11-15 | B |
| 4 | 1993-01-06 | C |
| 5 | 1993-03-10 | C |
| 6 | 1993-04-20 | C |
其中组B的周期为1992-09-08至1993-01-06(120天),事件4因超出该范围被归为新组C。
内容的提问来源于stack exchange,提问作者Brian Fisher
相关产品推荐
相关产品推荐

