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

Pandas性能优化:迭代处理超200万条数据过慢的解决方法

优化200万行数据的月度汇总计算性能

数据集

表格形式

idopen_monthend_monthquantity
0012023-01-312023-02-281
0022023-01-312023-03-315
0032023-01-312023-04-304
0042023-02-282023-02-282
0052023-02-282023-03-313
0062023-02-282023-04-306
0072023-03-312023-03-317
0082023-03-312023-04-309

pandas构造代码

import pandas as pd

x = pd.DataFrame({
    'id': ['001', '002', '003', '004', '005', '006', '007', '008'],
    'open_month': ['2023-01-31', '2023-01-31', '2023-01-31', '2023-02-28', '2023-02-28', '2023-02-28', '2023-03-31', '2023-03-31'],
    'end_month': ['2023-02-28', '2023-03-31', '2023-04-30', '2023-02-28', '2023-03-31', '2023-04-30', '2023-03-31', '2023-04-30'],
    'quantity': [1, 5, 4, 2, 3, 6, 7, 9]
})

需求说明

需要生成一张汇总表:

  • 行:开户后的月数(从0开始)
  • 列:开户月份
  • 值:对应开户月份的记录中,结束时间小于等于「开户月份+N个月」的quantity总和

预期结果

2023-01-312023-02-282023-03-31
0027
11516
261116

原实现代码(性能瓶颈)

table = pd.DataFrame()
for i in range(len(x['open_month'].unique())):
    for month in x['open_month'].unique():
        date = month + pd.offsets.MonthEnd(i)
        table.at[i, month] = x.query('open_month == @month and end_month <= @date')['quantity'].sum()

原代码在200万行数据上运行极慢,需要性能优化方案。


优化方案

核心思路

避免嵌套循环和逐次query(每次query都会遍历全表,时间复杂度O(n²)),改用向量化日期计算+分组累积求和,将时间复杂度降到O(n)级别。

步骤1:转换日期类型并计算月差

先将日期列转为datetime类型,再计算每条记录的结束时间与开户时间的月差(即该记录会在开户后第几个月被计入汇总):

# 转换为日期类型
x['open_month'] = pd.to_datetime(x['open_month'])
x['end_month'] = pd.to_datetime(x['end_month'])

# 计算结束时间相对于开户时间的月数差(得到该记录对应的目标行索引)
x['month_diff'] = (x['end_month'].dt.year - x['open_month'].dt.year) * 12 + (x['end_month'].dt.month - x['open_month'].dt.month)

步骤2:分组透视并计算累积求和

按开户月份和月差分组求和,再透视成目标格式,最后计算累积求和并补全所有需要的行:

# 分组求和:按开户月份和月差汇总quantity
grouped = x.groupby(['open_month', 'month_diff'])['quantity'].sum().unstack(fill_value=0)

# 生成所有需要的月差行(从0到最大月差)
max_month_diff = grouped.columns.max()
all_month_diffs = pd.Index(range(max_month_diff + 1), name='month_diff')
grouped = grouped.reindex(all_month_diffs, fill_value=0)

# 计算累积求和(第N行需要包含所有<=N月差的记录总和)
result = grouped.cumsum(axis=0)

# 调整索引和列名格式,匹配预期结果
result.index.name = '开户后月数'
result.columns = result.columns.strftime('%Y-%m-%d')

验证结果

执行上述代码后,result将与预期结果完全一致,且处理200万行数据的时间会从分钟级压缩到秒级。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 12:33:21