Pandas实现混合频率时间区间数据的月度均值计算
多频率重叠时间周期月度求和实现方案
pd.Grouper 仅支持固定频率、无重叠区间的时间分组逻辑,无法直接处理跨月度/季度/年度的重叠区间匹配需求,可通过区间逐次匹配的方式实现,步骤如下:
1. 数据预处理
首先将多层索引的字符串日期转换为标准datetime格式,方便后续日期比较:
import pandas as pd import numpy as np # 构造和提问完全对齐的样例数据 multi_index = pd.MultiIndex.from_tuples([("2022-01-01", "2022-12-31"), ("2022-01-01", "2022-03-30"), ("2022-03-01", "2022-03-30"), ("2022-04-01", "2022-04-30")]) multi_index.names = ['period_begin', 'period_end'] df = pd.DataFrame([4,3,5,8], index=multi_index, columns=['value']) # 索引转列+日期格式转换 df = df.reset_index() df['period_begin'] = pd.to_datetime(df['period_begin']) df['period_end'] = pd.to_datetime(df['period_end'])
2. 生成连续月度索引
提取数据覆盖的最早、最晚时间边界,生成每月第一天为节点的连续时间序列,作为结果的索引:
min_dt = df['period_begin'].min() max_dt = df['period_end'].max() # 频率MS代表每月第一天 month_list = pd.date_range(start=min_dt, end=max_dt, freq='MS')
3. 逐月份匹配覆盖区间求和
遍历每个月度节点,筛选所有时间范围覆盖当月的观测值求和即可。
注意:提问样例里的季度、月度周期结束日期没有取自然月最后一天(比如3月周期结束写为3月30日而非3月31日),因此筛选条件调整为:观测起始日早于/等于当月第一天,且观测结束日晚于/等于当月第一天,即可正确匹配覆盖当月的所有周期,不会出现漏匹配。
res = [] for month_start in month_list: # 筛选覆盖当月的所有观测 cover_mask = (df['period_begin'] <= month_start) & (df['period_end'] >= month_start) month_sum = df.loc[cover_mask, 'value'].sum() res.append({'month_begin': month_start, 'Monthly_Avg': month_sum}) # 转换为目标格式 result_df = pd.DataFrame(res).set_index('month_begin')
结果说明
运行后得到的结果完全符合给定计算规则:
Monthly_Avg month_begin 2022-01-01 7 2022-02-01 7 2022-03-01 12 2022-04-01 12 2022-05-01 4 2022-06-01 4 2022-07-01 4 2022-08-01 4 2022-09-01 4 2022-10-01 4 2022-11-01 4 2022-12-01 4
其中1-2月为年值+一季度值之和(4+3=7),3月为年值+一季度值+3月单月值之和(4+3+5=12),4月为年值+4月单月值之和(4+8=12),5-12月仅叠加年值4。如果实际数据里周期结束日期严格取自然周期最后一天,只需要把筛选条件里的df['period_end'] >= month_start替换为df['period_end'] >= month_start + pd.offsets.MonthEnd(0)即可。
内容的提问来源于stack exchange,提问作者W. Walter
相关产品推荐
相关产品推荐

