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

百万级Pandas DataFrame高效计算分组历史日期DPD均值

高效计算分组日期前的DPD均值(百万行数据优化)

原始数据

import pandas as pd

df = pd.DataFrame([['John', '1/1/2017','10'],
                   ['John', '2/2/2017','15'],
                   ['John', '2/2/2017','20'],
                   ['John', '3/3/2017','30'],
                   ['Sue', '1/1/2017','10'],
                   ['Sue', '2/2/2017','15'],
                   ['Sue', '3/2/2017','20'],
                   ['Sue', '3/3/2017','7'],
                   ['Sue', '4/4/2017','20']],
                   columns=['Customer', 'Deposit_Date','DPD'])
# 预处理:转换日期和数值类型
df['Deposit_Date'] = pd.to_datetime(df['Deposit_Date'])
df['DPD'] = df['DPD'].astype(int)

需求说明

新增一列PreviousMean,表示每个Customer截至当前Deposit_Date**之前(不含当日)**的DPD均值,无历史记录时填充为NaN。期望输出如下:

Customer Deposit_Date  DPD  PreviousMean
0     John   2017-01-01   10           NaN
1     John   2017-02-02   15          10.0
2     John   2017-02-02   20          10.0
3     John   2017-03-03   30          15.0
4      Sue   2017-01-01   10           NaN
5      Sue   2017-02-02   15          10.0
6      Sue   2017-03-02   20          12.5
7      Sue   2017-03-03    7          15.0
8      Sue   2017-04-04   20          13.0

现有方案的问题

原方案使用apply逐行遍历计算,代码如下:

df['PreviousMean'] = df.apply(
    lambda x: df[(df.Customer == x.Customer) & (df.Deposit_Date < x.Deposit_Date)].DPD.mean(), 
axis=1)

该方法时间复杂度为O(n²),每一行都要重新过滤整个DataFrame,在百万行数据下运行速度极慢,完全无法满足性能要求。

高效实现方案

优化思路

利用Pandas的分组聚合、累计统计函数替代逐行计算,核心是先按客户和日期聚合,再计算截至上一日期的累计总和与计数,最后推导均值。

代码实现

# 1. 按客户+日期分组,计算每日DPD总和与记录数
daily_stats = df.groupby(['Customer', 'Deposit_Date']).agg(
    dpd_sum=('DPD', 'sum'),
    count=('DPD', 'size')
).reset_index()

# 2. 按客户分组,计算截至上一日期的累计总和与累计计数
daily_stats['cum_sum'] = daily_stats.groupby('Customer')['dpd_sum'].cumsum().shift(1)
daily_stats['cum_count'] = daily_stats.groupby('Customer')['count'].cumsum().shift(1)

# 3. 计算均值,无历史记录时为NaN
daily_stats['PreviousMean'] = daily_stats['cum_sum'] / daily_stats['cum_count']

# 4. 将结果合并回原DataFrame
df = df.merge(daily_stats[['Customer', 'Deposit_Date', 'PreviousMean']], 
              on=['Customer', 'Deposit_Date'], how='left')

代码说明

  • 第一步将同一天同客户的记录合并,减少后续计算量;
  • 第二步用cumsum()计算累计值,shift(1)将累计值后移一行,得到当前日期之前的所有历史数据总和与数量;
  • 最后通过merge将结果关联回原表,确保同一天的所有记录共享相同的PreviousMean。

性能优势

该方法时间复杂度为O(n log n)(主要来自分组排序),百万行数据下的运行速度比原apply方法快数十倍甚至上百倍,完全适配大数据量场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 03:15:21