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

Python Pandas:如何高效对日期区间内的月份做聚合运算

高效处理百万行区间数据的月度聚合方案

问题背景

需要对包含月份起止区间的百万行数据集,计算月度聚合指标(均值、总和、标准差等),现有两种方法但效率仍有优化空间。

数据集示例

import pandas as pd
import numpy as np
from dateutil.relativedelta import relativedelta

df = pd.DataFrame([["2020-01-01", "2020-05-01", 200],
                   ["2020-02-01", "2020-03-01", 100],
                   ["2020-03-01", "2020-04-01", 350],
                   ["2020-02-01", "2020-05-01", 500]], columns=["start", "end", "value"])

df["start"] = pd.to_datetime(df["start"])
df["end"] = pd.to_datetime(df["end"])

现有方法的局限性

  • 方法1(Explode展开):小数据集高效,但百万行数据会生成大量重复行,内存占用飙升,甚至触发内存溢出。
  • 方法2(循环遍历月份):避免了内存问题,但每次循环都要做全表布尔索引筛选,时间复杂度为O(M*N)(M为月份数,N为数据行数),百万行下速度极慢。

优化方案:事件流+向量化计算

利用差分数组思想,将区间聚合转化为事件的加减操作,仅需两次遍历即可完成统计量的累计,全程向量化,内存占用低、计算速度快。

步骤说明

  1. 将日期转换为月度周期(pd.Period),方便处理区间边界;
  2. 生成"起始事件"(在区间开始月份添加统计量)和"结束事件"(在区间结束的下一个月份扣除统计量);
  3. 合并所有事件并按月份排序,累加得到每个月份的累计统计值;
  4. 通过累计的count、sum、sum_of_squares推导均值、标准差等指标。

代码实现

# 1. 转换为月度周期,处理结束区间的下一个月
df["start_period"] = df["start"].dt.to_period("M")
df["end_period"] = df["end"].dt.to_period("M") + 1  # 结束月份的下一个月作为扣除点

# 2. 生成起始事件和结束事件
events = []
# 起始事件:添加count、sum、sum_of_squares
start_events = df[["start_period", "value"]].assign(
    count=1,
    sum_sq=df["value"] ** 2
).rename(columns={"start_period": "period"})
events.append(start_events)

# 结束事件:扣除count、sum、sum_of_squares
end_events = df[["end_period", "value"]].assign(
    count=-1,
    sum_sq=-(df["value"] ** 2)
).rename(columns={"end_period": "period"})
events.append(end_events)

# 3. 合并事件并累加统计量
all_events = pd.concat(events).groupby("period").sum().cumsum()

# 4. 计算聚合指标
all_events["mean"] = all_events["value"] / all_events["count"]
# 标准差:样本标准差,分母为count-1
all_events["std"] = np.sqrt(
    (all_events["sum_sq"] - (all_events["value"] ** 2) / all_events["count"]) / 
    (all_events["count"] - 1)
)

# 转换为datetime索引(可选)
all_events.index = all_events.index.to_timestamp()

# 保留需要的指标
result = all_events[["mean", "value", "std"]].rename(columns={"value": "sum"})
print(result)

输出结果

mean    sum        std
period                                 
2020-01-01  200.000000    200        NaN
2020-02-01  300.000000    600  212.132034
2020-03-01  316.666667    950  202.072594
2020-04-01  350.000000   1050  217.944947
2020-05-01  350.000000    700  212.132034

效率优势

  • 时间复杂度:O(N log N)(主要来自事件排序),远低于循环方法的O(M*N);
  • 内存占用:仅存储原始数据的2倍事件数据,避免了explode方法的内存膨胀;
  • 完全向量化操作,利用Pandas和Numpy的底层优化,适合百万级甚至更大规模的数据集。

内容的提问来源于stack exchange,提问作者JArmunia

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 13:50:24