多年日值数据集计算逐日历日3日滑动90th percentile值问题求助
适配多规则年长度的逐日3日滑动90百分位计算方案
核心思路
规避直接按真实日期切片的逻辑,通过月日唯一标识+当年内日序匹配的方式实现窗口数据自动适配,无需提前判断数据集的年长度规则,自动跳过当年不存在的日期,避免报错。
实现步骤
1. 原始数据预处理
对已剔除闰日的原始数据集新增两列标识:
md_str:格式为MM-DD的字符串,用于唯一标识月日组合,实现跨年月日匹配doy:当前记录在所属年份的日序(即当年第几天),不同年长度规则的年份单独计算即可
示例预处理代码:
import pandas as pd # 假设原始数据为df,DATE列已转为datetime类型 # 生成月日标识 df['md_str'] = df.apply(lambda x: f"{x['month']:02d}-{x['day']:02d}", axis=1) # 生成日序:如果是标准公历日期直接用dayofyear,360天规则的年可自行计算:(month-1)*30 + day df['doy'] = df.index.dayofyear # 按年份分组,预存每年的最大日序 year_max_doy = df.groupby('year')['doy'].max().to_dict()
2. 生成目标计算基准表
生成所有需要输出结果的月日组合(共365个,不含2月29日),可直接基于平年公历日期生成:
# 生成平年所有日期,提取月日标识作为目标列表 target_dates = pd.date_range(start='2023-01-01', end='2023-12-31') target_md_list = [f"{d.month:02d}-{d.day:02d}" for d in target_dates]
3. 按目标中心日匹配窗口计算百分位
对每个目标月日,遍历所有年份匹配当年的3天窗口数据,汇总后计算90百分位:
import numpy as np result = [] for target_md in target_md_list: val_pool = [] # 按年份遍历 for year, group in df.groupby('year'): # 查找当年是否存在该月日,不存在直接跳过 target_row = group[group['md_str'] == target_md] if target_row.empty: continue # 拿到目标日当年的日序 curr_doy = target_row['doy'].iloc[0] max_doy = year_max_doy[year] # 计算窗口范围,处理边界循环 window_doys = [] # 前一天 window_doys.append(curr_doy - 1 if curr_doy - 1 >=1 else max_doy) # 中心天 window_doys.append(curr_doy) # 后一天 window_doys.append(curr_doy +1 if curr_doy +1 <= max_doy else 1) # 提取当年窗口内的数值加入计算池 year_vals = group[group['doy'].isin(window_doys)]['value'].tolist() val_pool.extend(year_vals) # 计算90百分位,空值可自行处理 p90 = np.percentile(val_pool, 90) if val_pool else np.nan result.append({'md_str': target_md, 'p90_3d': p90}) # 转为结果表 result_df = pd.DataFrame(result)
方案优势
- 无需提前判断数据集的年长度规则,自动适配360/365/366天的年份
- 自动跳过当年不存在的日期,不会出现日期不存在的报错
- 年初/年末边界日期的窗口自动在当年内循环,符合滑动窗口计算逻辑
内容的提问来源于stack exchange,提问作者alpaca
相关产品推荐
相关产品推荐

