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

如何用Pandas DataFrame.resample实现锚定月度特定日期的滚动均值计算

这个需求确实戳中了Pandas常规滚动/重采样的盲区——因为你要的是锚定每个行日期的月度回溯区间,不是固定天数或者自然月的窗口,常规方法确实搞不定。我之前做类似的需求时,是用自定义区间筛选结合apply(或者批量生成日期对)来实现的,给你分享两种可行的方案:


方案一:逐行生成回溯区间(中小数据量友好)

核心思路是给每一行的日期,循环生成所有符合要求的回溯月度区间,然后筛选区间内的数据计算均值。

步骤拆解:

  1. 先确保日期列是datetime类型,并且数据按日期排序:
import pandas as pd
from dateutil.relativedelta import relativedelta

# 假设你的日期列名为'date',目标值列名为'value'
df['date'] = pd.to_datetime(df['date'])
df = df.sort_values('date').reset_index(drop=True)
  1. 定义一个函数,输入单行数据,返回该行所有回溯月度区间的均值:
def get_monthly_roll_means(row, source_df, value_col='value'):
    current_end = row['date']
    mean_dict = {}
    
    # 循环生成回溯区间,直到区间起始早于数据最早日期
    for n in range(1, 100):  # 这里100是最大回溯次数,可按需调整
        # 计算区间起始日期:当前结束日期减1个月,再加1天(匹配你的区间规则)
        interval_start = current_end - relativedelta(months=1) + pd.Timedelta(days=1)
        if interval_start < source_df['date'].min():
            break
        
        # 筛选区间内的数据并计算均值
        mask = (source_df['date'] >= interval_start) & (source_df['date'] <= current_end)
        interval_mean = source_df.loc[mask, value_col].mean()
        
        # 用回溯次数命名均值列
        mean_dict[f'roll_mean_{n}m'] = interval_mean
        
        # 更新下一轮的结束日期为当前区间的前一天
        current_end = interval_start - pd.Timedelta(days=1)
    
    return pd.Series(mean_dict)
  1. 将函数应用到每一行,合并结果到原DataFrame:
# 生成回溯均值DataFrame
dfm = df.apply(lambda row: get_monthly_roll_means(row, df), axis=1)
# 合并原数据和均值结果
final_df = pd.concat([df, dfm], axis=1)

方案二:批量生成日期对(大数据量高效)

如果你的DataRow行数很多,逐行apply效率会偏低,可以先批量生成所有需要计算的区间对,再通过分组计算均值:

from itertools import count

# 批量生成所有(原行索引, 区间结束日期, 区间起始日期, 均值列名)的组合
date_pairs = []
for idx, row in df.iterrows():
    current_end = row['date']
    for n in count(1):
        interval_start = current_end - relativedelta(months=1) + pd.Timedelta(days=1)
        if interval_start < df['date'].min():
            break
        date_pairs.append({
            'original_idx': idx,
            'end_date': current_end,
            'start_date': interval_start,
            'mean_col': f'roll_mean_{n}m'
        })

# 转成DataFrame并分组计算均值
pairs_df = pd.DataFrame(date_pairs)
mean_results = pairs_df.groupby(['original_idx', 'mean_col']).apply(
    lambda x: df.loc[(df['date'] >= x['start_date'].iloc[0]) & (df['date'] <= x['end_date'].iloc[0]), 'value'].mean()
).unstack()

# 合并回原数据
final_df = df.join(mean_results)

关键注意事项:

  • 依赖python-dateutil库处理月份加减(避免pd.DateOffset在月末日期的异常),需要提前安装:pip install python-dateutil
  • 如果某个回溯区间内没有数据,均值会返回NaN,可根据需求用fillna()填充(比如0或前一个均值)
  • 如果有重复日期,建议先对原数据按日期做聚合(比如取均值),避免重复计算

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:33:13