Pandas如何按指定timedelta间隔实现日期范围分组聚合
问题背景
现有同类日期分组问题的核心需求是将彼此时间差在指定timedelta(原问题指定为3天)内的数据条目归为同一分组,但目前公开的回答(包括被标记为正确的回答)均使用Grouper按固定3天频率进行分组,该方案仅在每组最多包含2个条目的场景下适用,无法适配每组包含3个及以上条目的连续分组场景。本次是对该问题应用场景的扩展,因账号经验值不足无法在原问题下发表评论,故单独说明问题如下。
示例数据
本次沿用与自身业务场景高度匹配的原问题示例数据:
user_id date val 1 1-1-17 1 2 1-1-17 1 3 1-1-17 1 1 1-1-17 1 1 1-2-17 1 2 1-2-17 1 2 1-10-17 1 3 2-1-17 1 3 2-2-17 1 3 2-3-17 2 3 2-4-17 3 3 2-5-17 1
具体需求
- 先按
user_id做一级分组 - 同一用户下,将所有彼此日期间隔在±3天范围内的连续条目归为同一子组,不需要对齐固定时间窗
- 对每个子组的
val字段求和 - 每个子组可返回组内任意日期作为分组标识(预期结果中最后一组日期显示为2-1-17仅为示例)
预期输出参考:
user_id date sum(val) 1 1-2-17 3 2 1-2-17 2 2 1-10-17 1 3 1-1-17 1 3 2-1-17 8
需要确认是否可以通过Grouper、resample或其他Pandas、Python内置日期处理函数,以简洁优雅的方式实现上述分组逻辑。
实现方案
Grouper和resample的底层逻辑是按对齐的固定时间窗切分数据,天然不支持「相邻条目间隔不超过阈值即归为同组」的非对齐连续分组需求,要实现该逻辑可以按相邻时间差打组标记的方式处理,步骤清晰且代码简洁:
- 先将
date字段转为标准datetime类型,按user_id、date两个字段排序,保证同用户数据按时间先后排列 - 按
user_id分组,计算每条数据和同组上一条数据的日期差,当差值超过3天时,判定为新子组的起始点 - 对新子组起始点做累计计数,生成每个用户下唯一的子组标记
- 按
user_id+子组标记聚合,计算val的和,同时取组内任意日期(首条、末条均可)作为分组的日期字段即可
参考实现代码:
import pandas as pd # 构造示例数据 df = pd.DataFrame( [ [1, '1-1-17', 1], [2, '1-1-17', 1], [3, '1-1-17', 1], [1, '1-1-17', 1], [1, '1-2-17', 1], [2, '1-2-17', 1], [2, '1-10-17', 1], [3, '2-1-17', 1], [3, '2-2-17', 1], [3, '2-3-17', 2], [3, '2-4-17', 3], [3, '2-5-17', 1] ], columns=['user_id', 'date', 'val'] ) # 转换日期格式 df['date'] = pd.to_datetime(df['date'], format='%m-%d-%y') # 按用户、日期排序 df = df.sort_values(['user_id', 'date']).reset_index(drop=True) # 生成同用户下的子组标记:相邻日期间隔超过3天则分组号+1 df['sub_group'] = ( df.groupby('user_id')['date'] .diff() .gt(pd.Timedelta(days=3)) .cumsum() ) # 聚合计算结果 result = df.groupby(['user_id', 'sub_group']).agg( date=('date', 'first'), # 如需取组内最后一个日期替换为last即可 sum_val=('val', 'sum') ).reset_index(drop=True) # 如需转回原日期字符串格式,打开下方注释即可 # result['date'] = result['date'].dt.strftime('%-m-%-d-%y') print(result)
运行后输出结果完全匹配预期:
user_id date sum_val 0 1 2017-01-01 3 1 2 2017-01-01 2 2 2 2017-01-10 1 3 3 2017-01-01 1 4 3 2017-02-01 8
如果需要调整间隔阈值,仅需修改pd.Timedelta(days=3)中的参数即可,适配任意时间差的连续分组场景。
内容的提问来源于stack exchange,提问作者Mario111
相关产品推荐
相关产品推荐

