You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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的底层逻辑是按对齐的固定时间窗切分数据,天然不支持「相邻条目间隔不超过阈值即归为同组」的非对齐连续分组需求,要实现该逻辑可以按相邻时间差打组标记的方式处理,步骤清晰且代码简洁:

  1. 先将date字段转为标准datetime类型,按user_id、date两个字段排序,保证同用户数据按时间先后排列
  2. 按user_id分组,计算每条数据和同组上一条数据的日期差,当差值超过3天时,判定为新子组的起始点
  3. 对新子组起始点做累计计数,生成每个用户下唯一的子组标记
  4. 按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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 17:18:20