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

Pandas中按日期计算指定日期前won列均值的实现问题

问题:基于日期计算历史won列均值(同日期值一致)

我有一个包含10万+行的Pandas DataFrame,需要按日期计算won列的历史均值:对每一行,计算所有created_on早于当前行日期的行中won的均值。核心要求是同一日期的所有行结果必须相同,而非逐行累积的均值。


我的尝试与问题

  1. 单个日期计算函数可行:
def get_win_prop(df, d) -> float:
    mask = (df['created_on'] < d)
    prop = df[mask].won.mean()
    return prop

get_win_prop(d, '2022-10-25')  # 该调用能返回正确结果
  1. 但使用pd.assign()批量计算时,所有结果均为NaN:
d.assign(rolling_won_prop = lambda x: get_win_prop(x, x.created_on))
  1. 自己实现了循环方案,但效率不足:
result = []
for i in d.created_on.unique():
    prev_vals = d[d['created_on'] < i]
    result.append(prev_vals.won.mean())

d.merge(pd.DataFrame({'created_on': d.created_on.unique(), 
                      'rolling_won_prop': result}), how='left')

示例数据:

import pandas as pd
from pandas import Timestamp

d = pd.DataFrame({'created_on': [Timestamp('2022-09-22 00:00:00'), Timestamp('2022-10-14 00:00:00'),Timestamp('2022-10-19 00:00:00'),Timestamp('2022-10-25 00:00:00'),Timestamp('2022-11-02 00:00:00'),
                Timestamp('2022-11-04 00:00:00'),Timestamp('2022-11-16 00:00:00'),Timestamp('2022-11-28 00:00:00'),Timestamp('2022-11-28 00:00:00'),Timestamp('2022-12-07 00:00:00'),
                Timestamp('2022-12-21 00:00:00'),Timestamp('2022-12-21 00:00:00'),Timestamp('2022-12-21 00:00:00'),Timestamp('2022-12-21 00:00:00')],
  'n_lines': [7, 3, 7, 6, 6, 4, 5, 3, 10, 3, 6, 6, 9, 6],
  'n_pieces': [606, 202, 706, 765, 255, 803, 1004, 2702, 1909, 546, 555, 555, 558,555],
  'quote_total': [1780.4299999999998, 3575.4600000000005, 11762.079999999994, 6725.160000000002, 995.9300000000001, 1644.2100000000003, 2620.2299999999996,
                   8082.090000000001, 5302.320000000001, 1959.7599999999998, 8734.67, 9792.3, 0.0, 9720.71],
  'won': [1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0]})

问题分析与解决方案

为什么assign调用返回全NaN?

你的get_win_prop函数设计为接收单个日期值,但x.created_on是Series(整列数据)。此时df['created_on'] < d会生成一个布尔矩阵而非单个掩码,最终计算均值时无法得到有效数值,返回全NaN。

高效的Pandas原生实现

基础版(无分组)

核心思路:先按日期聚合统计,再计算排除当前日期的累积统计量,最后映射回原DataFrame,确保同日期结果一致。

# 1. 按日期聚合,计算每日won总和与记录数
daily_agg = d.groupby('created_on').agg(
    sum_won=('won', 'sum'),
    count_rows=('won', 'count')
).sort_index()

# 2. 计算滞后的累积值(shift(1)排除当前日期的统计)
daily_agg['lag_cumsum_won'] = daily_agg['sum_won'].cumsum().shift(1)
daily_agg['lag_cumsum_rows'] = daily_agg['count_rows'].cumsum().shift(1)

# 3. 计算历史均值,首日期无历史数据则为NaN
daily_agg['rolling_won_prop'] = daily_agg['lag_cumsum_won'] / daily_agg['lag_cumsum_rows']

# 4. 合并回原数据
result = d.merge(daily_agg[['rolling_won_prop']], on='created_on', how='left')

分组版(按客户ID)

若需按客户ID分组计算,只需在聚合时加入分组键,再按客户分组计算累积值:

# 假设DataFrame包含customer_id列
daily_agg_grouped = d.groupby(['customer_id', 'created_on']).agg(
    sum_won=('won', 'sum'),
    count_rows=('won', 'count')
).sort_index()

# 按客户分组计算滞后累积值
daily_agg_grouped['lag_cumsum_won'] = daily_agg_grouped.groupby('customer_id')['sum_won'].cumsum().shift(1)
daily_agg_grouped['lag_cumsum_rows'] = daily_agg_grouped.groupby('customer_id')['count_rows'].cumsum().shift(1)

daily_agg_grouped['rolling_won_prop'] = daily_agg_grouped['lag_cumsum_won'] / daily_agg_grouped['lag_cumsum_rows']

# 合并回原数据
result_grouped = d.merge(daily_agg_grouped[['rolling_won_prop']], on=['customer_id', 'created_on'], how='left')

方案优势

  • 矢量化操作:聚合与累积均为Pandas内部优化的操作,处理10万+行数据效率远高于循环
  • 严格满足同日期结果一致的要求
  • 分组场景下逻辑清晰,可直接扩展

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 05:35:01