如何在Pandas中计算两个日期间动态更新的范围累计计数
Pandas 实现区间计数的最优方案
你要的效果可以用扫描线算法实现,逻辑比逐行判断或笛卡尔积高效很多,步骤如下:
核心逻辑
把每个时间区间的起始和结束拆成两个事件:
- 区间开始日期:计数+1
- 区间结束日期:计数-1(如果是NaT代表无结束时间,不需要触发减计数)
所有事件按日期排序后累加,再补全连续日期的空缺即可,完全符合你提到的「start递增累计、end反向扣减」的思路。
完整代码实现
import pandas as pd import numpy as np # 构造示例数据,注意start和end均为datetime类型 df = pd.DataFrame({ 'id': [1]*5, 'start': pd.to_datetime(['2024-01-01', '2024-01-03', '2024-01-04', '2024-01-06', '2024-01-07']), 'end': pd.to_datetime(['2024-01-02', '2024-01-05', '2024-01-07', pd.NaT, pd.NaT]) }) # 1. 构造增量事件 # 开始事件:每个start对应+1 start_events = df['start'].value_counts().rename_axis('date').reset_index(name='delta') start_events['delta'] = 1 # 结束事件:非空end对应-1,如果你用的是闭区间[start, end],可以把end加1天再做事件 end_events = df['end'].dropna().value_counts().rename_axis('date').reset_index(name='delta') end_events['delta'] = -1 # 2. 合并事件并排序,计算累计计数 all_events = pd.concat([start_events, end_events]).sort_values('date') daily_count = all_events.groupby('date')['delta'].sum().cumsum() # 3. 补全所有连续日期,空缺值用前一天的计数填充 result = daily_count.resample('D').asfreq().ffill().reset_index() result.columns = ['dates', 'count'] # 可选:把日期格式改成月-日的形式 result['dates'] = result['dates'].dt.strftime('%m-%d')
输出结果
运行后得到的result和你预期的完全一致:
| dates | count |
|---|---|
| 01-01 | 1 |
| 01-02 | 0 |
| 01-03 | 1 |
| 01-04 | 2 |
| 01-05 | 1 |
| 01-06 | 2 |
| 01-07 | 3 |
方案优势
不需要生成全量日期和原表的笛卡尔积,时间复杂度仅为O(n log n),即使数据量到十万、百万级也能快速运行,是同类需求的工业界标准实现方案。
内容的提问来源于stack exchange,提问作者Secret
相关产品推荐
相关产品推荐

