Python pandas中如何对含异常值、带季节性的时间序列进行平滑处理
带季节性特征的时间序列平滑落地方案
针对电力系统负荷这类存在强日/周/年周期波动、夹杂零散异常值的时序数据,普通全序列滚动平滑会破坏季节性规律,结合pandas实现的最优方案如下:
第一步:前置数据规整
- 先将文本格式的时间列转换为pandas可识别的时间索引,针对日-月-年格式的时间数据,使用
pd.to_datetime()时必须指定匹配的格式参数,避免时间解析错乱。 - 对同一时间戳下的多条重复记录,优先取同时刻的数值中位数做初步聚合,从源头减少同一时间点多值对后续平滑的干扰。
- 按时间升序排列全部记录,确保时间轴连续无断点。
第二步:适配季节性的平滑实现
两类可落地的最优实现路径,可根据数据量和精度需求选择:
- 鲁棒性STL分解平滑(精度优先)
针对需要高精度拟合的场景,直接使用支持鲁棒模式的STL分解工具处理即可。这个分解过程会自动把序列拆成三个部分:长期缓慢变化的趋势项、固定周期波动的季节项、零散无规律的残差项。开启鲁棒模式后,计算时会自动给离群的异常值降权,不会因为几个尖峰就把趋势拟合偏差。处理完先筛掉残差里的极端值(用上下1.5倍四分位距的范围判定即可),替换成同窗口的正常值后,再把平滑后的趋势和稳定的季节项拼合,最终得到的平滑序列完全不会磨掉早晚高峰、工作日与周末的固有负荷规律,和预期的平滑效果匹配度最高。 - 季节分层滚动平滑(效率优先)
如果数据量特别大不想引入额外的时序分解依赖,纯靠pandas也能实现。核心逻辑是不跨周期做平均,把同季节位置的点凑成一组再做滚动计算:比如电力负荷最明显的是24小时周期,那就把所有同一天同一小时的历史值归为一组,每组单独计算30天窗口的滚动中位数(相比均值,中位数抗异常值干扰能力更强)。如果要保留周度的周期差异,就再加一个“当天是周几”的分组维度,把工作日和周末的同时刻值分开分组,算出来的平滑值完全符合实际负荷的季节规律。
常见踩坑点
- 别图省事直接拉全序列做7天/30天滚动平均:这种算法会把跨周期的点凑在一起计算,比如周末凌晨的低负荷会被前一天的晚高峰值平均掉,算出来的曲线完全没有实际的周期特征,和真实负荷规律偏差很大。
- 别一看到异常值就删行:直接用同时间窗口的正常值替换掉异常值即可,硬删会把连续的时间轴剪出断点,后续做其他分析时容易出现问题。
参考实现代码
import pandas as pd import numpy as np # 读取并规整数据 df = pd.read_csv("your_load_data_path.csv") df['dat_time'] = pd.to_datetime(df['dat_time'], format="%d-%m-%Y %H:%M:%S") df = df.sort_values('dat_time').set_index('dat_time') # 同一时间戳初步聚合去重 df = df.groupby(df.index)['system_load'].median().to_frame() # 按小时+星期几分层,做30天窗口的中位数滚动平滑,保留日/周双重季节性 df['hour'] = df.index.hour df['weekday'] = df.index.weekday df['smoothed_load'] = df.groupby(['hour', 'weekday'])['system_load'].transform( lambda s: s.rolling(window=30, center=True, min_periods=1).median() )
内容的提问来源于stack exchange,提问作者swhh
相关产品推荐
相关产品推荐

