时间序列季节性分析与调整方法实战

张开发
2026/4/24 15:18:22 15 分钟阅读

分享文章

时间序列季节性分析与调整方法实战
1. 时间序列季节性分析基础时间序列数据中的季节性成分是指那些以固定周期重复出现的波动模式。以墨尔本每日最低气温数据集为例我们可以清晰地观察到每年冬季低温、夏季高温的周期性变化。这种季节性波动会掩盖我们真正关心的信号影响预测模型的准确性。理解季节性成分对机器学习建模有两方面重要意义首先通过识别并去除季节性成分我们能获得更清晰的信号。就像在嘈杂的环境中过滤掉背景噪音让模型能够专注于学习数据中的真实模式。其次季节性信息本身也可以成为有价值的特征。例如在气温预测中知道当前处于一年中的哪个季节本身就具有很强的预测力。常见的季节性类型包括日内季节性如交通流量的早晚高峰周季节性如零售销售额的周末高峰月季节性如水电费的月度周期年季节性如本文讨论的气温变化提示判断数据是否存在季节性最直观的方法是绘制不同时间尺度的折线图并添加趋势线辅助观察。当周期性波动明显且规律时就可以考虑进行季节性调整。2. 数据准备与初步分析2.1 数据集介绍我们使用的数据集记录了澳大利亚墨尔本市1981-1990年共10年的每日最低气温包含3650个观测值。数据格式简单明了只有日期和温度两列Date,Temperature 1981-01-01,20.7 1981-01-02,17.9 1981-01-03,18.82.2 数据加载与可视化使用pandas加载数据并绘制原始序列from pandas import read_csv from matplotlib import pyplot series read_csv(daily-minimum-temperatures.csv, header0, index_col0, parse_datesTrue) series.plot(figsize(12,6)) pyplot.title(Daily Minimum Temperatures in Melbourne (1981-1990)) pyplot.show()从图中可以明显看出数据具有以下特征强烈的年周期性季节性相对稳定的波动幅度无明显长期趋势变化存在少量异常波动点2.3 季节性特征量化为了更精确地量化季节性特征我们可以计算自相关函数(ACF)from statsmodels.graphics.tsaplots import plot_acf plot_acf(series, lags730) # 分析2年的滞后 pyplot.show()ACF图会在滞后365天处显示出显著的相关性峰值这证实了年季节性的存在。3. 差分法季节性调整3.1 基本差分法最简单的季节性调整方法是差分法即用当前值减去去年同期值diff series.diff(periods365) # 年差分 diff.plot(figsize(12,6)) pyplot.title(Seasonally Adjusted (Differencing)) pyplot.show()这种方法虽然简单但存在两个明显问题会损失第一年的数据因为没有前一年数据可减闰年2月29日的处理会引入误差3.2 改进的月平均差分法更稳健的方法是先计算月平均温度再进行差分monthly_mean series.resample(M).mean() monthly_diff monthly_mean.diff(12) # 12个月差分然后将月平均差异应用到日数据上adjusted [] for i in range(365, len(series)): month series.index[i].month year series.index[i].year - 1 monthly_avg series.loc[f{year}-{month}].mean() adjusted.append(series.iloc[i] - monthly_avg)这种方法的优势减少日波动带来的噪声自动处理闰日问题结果更加稳定可靠注意事项差分法假设季节性模式是严格相加的即每年波动幅度相同。如果实际季节性效应是相乘的波动幅度随时间变化需要先对数据取对数。4. 建模法季节性调整4.1 季节性建模原理与差分法不同建模法尝试显式地建立季节性模型。基本思路是将时间索引一年中的第几天作为自变量X将观测值作为因变量y拟合一个周期性函数如正弦波或多项式用模型预测季节性成分从原始值中减去预测的季节性成分4.2 多项式曲线拟合使用4阶多项式拟合季节性模式import numpy as np # 创建时间索引一年中的第几天考虑闰年 day_of_year series.index.dayofyear X day_of_year.values.reshape(-1,1) y series.values # 4阶多项式拟合 coefs np.polyfit(X.flatten(), y, deg4) poly np.poly1d(coefs) # 生成季节性曲线 seasonal poly(X.flatten())4.3 季节性调整实现用拟合的季节性曲线调整原始数据adjusted y - seasonal plt.figure(figsize(12,6)) plt.plot(series.index, adjusted) plt.title(Seasonally Adjusted (Modeling Approach)) plt.show()4.4 模型评估与改进评估季节性模型的好坏可以检查调整后序列的自相关函数plot_acf(adjusted, lags730) plt.show()理想情况下调整后序列在季节性滞后365天处不应再有显著相关性。如果仍然存在可能需要提高多项式阶数尝试傅里叶级数拟合使用更复杂的季节性模型如STL分解5. 高级季节性调整技术5.1 STL分解法STLSeasonal and Trend decomposition using Loess是一种更鲁棒的分解方法from statsmodels.tsa.seasonal import STL stl STL(series, period365, seasonal13) res stl.fit() plt.figure(figsize(12,8)) res.plot() plt.show()STL的优点自动处理趋势成分对异常值鲁棒允许季节性模式缓慢变化5.2 移动平均法对于高频数据可以使用移动平均法估计季节性# 计算365天移动平均去除季节性 trend series.rolling(window365, centerTrue).mean() # 计算季节性成分 seasonal series - trend5.3 Prophet模型Facebook Prophet是专门为时间序列预测设计的工具内置了季节性建模from prophet import Prophet df series.reset_index() df.columns [ds, y] model Prophet(yearly_seasonalityTrue) model.fit(df) future model.make_future_dataframe(periods365) forecast model.predict(future)6. 季节性调整的注意事项6.1 方法选择考量选择季节性调整方法时需考虑数据频率日/周/月数据季节性模式是否稳定是否有足够的观测周期计算资源限制6.2 常见问题处理问题1调整后序列仍存在季节性可能原因季节性模式非线性或随时间变化解决方案尝试更高阶模型或允许季节性变化的算法问题2调整引入人为波动可能原因过度拟合季节性模式解决方案简化模型增加正则化问题3如何处理缺失数据推荐方案在季节性调整前先填补缺失值可用方法线性插值、季节性插值或预测填补6.3 结果验证方法验证季节性调整效果的实用方法视觉检查绘制调整前后序列对比统计检验如季节性单位根检验预测评估比较使用调整前后数据的预测精度残差分析检查调整后序列的自相关性7. 季节性信息在预测中的应用7.1 作为特征工程季节性信息可以作为额外特征输入预测模型# 添加季节性特征 df[day_of_year] df[ds].dt.dayofyear df[month] df[ds].dt.month df[season] df[month] % 12 // 3 1 # 1-4表示四季7.2 多周期季节性建模某些数据可能具有多重季节性如每日和每周模式from statsmodels.tsa.holtwinters import ExponentialSmoothing model ExponentialSmoothing(series, seasonal_periods[7,365], trendadd, seasonaladd) fit model.fit()7.3 季节性调整与预测流程完整的预测流程建议探索性分析可视化、ACF等季节性调整选择适当方法对调整后序列建模预测后再加入季节性成分评估预测精度8. 实际应用案例扩展8.1 零售销售预测零售数据通常具有周季节性周末高峰年季节性节假日高峰特殊事件影响促销活动调整策略# 先去除周季节性 weekly_diff sales.diff(7) # 再去除年季节性 annual_diff weekly_diff.diff(365)8.2 能源负荷预测电力负荷数据特点日内季节性24小时周期周季节性工作日/周末差异温度敏感性强处理方法# 使用STL分解多重季节性 stl STL(load, period[24, 24*7], seasonal[25, 25*7])8.3 经济指标分析经济数据注意事项季节性模式可能随时间变化需要官方季节性调整方法如X-13ARIMA-SEATS考虑日历效应工作日天数、节假日9. 性能优化与大规模应用9.1 计算效率优化处理长时间序列时的技巧使用稀疏矩阵存储并行计算季节性成分增量式更新模型from joblib import Parallel, delayed def compute_seasonal_chunk(data_chunk): return seasonal_model.predict(data_chunk) results Parallel(n_jobs4)(delayed(compute_seasonal_chunk)(chunk) for chunk in np.array_split(series, 4))9.2 实时季节性调整流数据场景下的处理方法滑动窗口季节性估计指数加权移动平均在线学习算法online_adjusted [] window_size 365*3 # 3年窗口 for i in range(window_size, len(stream)): window stream[i-window_size:i] seasonal compute_seasonal(window) online_adjusted.append(stream[i] - seasonal[-1])10. 工具与资源推荐10.1 Python库推荐statsmodels提供多种经典时间序列分析方法Prophet面向商业预测的易用工具Darts统一的时间序列预测框架sktime专门的时间序列机器学习库10.2 学习资源《Forecasting: Principles and Practice》免费在线教材Kaggle时间序列竞赛实战练习平台M4竞赛报告了解最新方法各库的官方文档和示例10.3 实用代码片段快速检查季节性的函数def check_seasonality(series, max_lag730): 检查序列中的季节性模式 acf sm.tsa.stattools.acf(series, nlagsmax_lag) peaks argrelextrema(acf, np.greater)[0] significant peaks[acf[peaks] 2/np.sqrt(len(series))] return significant自动季节性调整管道from sklearn.base import BaseEstimator, TransformerMixin class SeasonalAdjuster(BaseEstimator, TransformerMixin): def __init__(self, methodstl, period365): self.method method self.period period def fit(self, X, yNone): if self.method stl: self.model STL(X, periodself.period) elif self.method diff: self.model None return self def transform(self, X): if self.method stl: res self.model.fit() return res.resid elif self.method diff: return X.diff(self.period).dropna()在实际项目中我发现理解数据的季节性结构是时间序列分析最关键的第一步。不同的调整方法各有利弊通常需要尝试多种方法并评估其效果。对于重要的预测任务建议保留部分原始季节性信息作为模型特征而不是完全依赖调整后的数据。

更多文章