Python时间序列分析实战:从Pandas数据预处理到ARIMA与SARIMA建模预测
发布时间:2026/10/11 21:57:18 锦皓数字建站

简介本资源是一份面向Python数据分析初学者与进阶学习者的时间序列实战资料以美国西雅图费利蒙桥自行车流量数据为案例帮助读者掌握Pandas处理时间序列数据的完整流程。内容涵盖CSV数据读取、日期索引设置、列名重命名、缺失值与重复值清洗、describe统计描述以及resample重采样、rolling滚动平均等核心方法并结合Matplotlib与Seaborn完成可视化呈现便于观察季节性趋势与周间波动规律。资源包共1个PDF文件大小约391KB以图文形式记录完整代码与运行结果适合对照练习与复盘。目前已有1113人学习下载可作为数据分析课程配套案例或自学时间序列的参考材料帮助读者理解时间序列数据的特性与分析方法。1. 时间序列分析到底在分析什么从一份 PDF 实践说起很多人第一次接触时间序列是从一份名为「Python数据分析实践时间序列实例.pdf」的资料开始的。打开一看里面是销售数据、股价、传感器读数这类按时间排列的记录然后要求你画图、做差分、拟合模型。问题在于大部分教程只告诉你「调用哪个函数」却不解释「为什么这条曲线要这样处理」。结果就是换一份数据立刻翻车。时间序列分析的核心是研究一个变量随时间变化的规律并利用这个规律做预测或异常检测。它和普通回归最大的区别在于样本之间不独立今天的数据和昨天的数据强相关。这个「自相关」特性既是它的价值所在也是所有坑的源头。这篇文章面向两类人一是手里有 PDF 或类似教程、想真正跑通一个完整实例的初学者二是用过 Pandas 但一遇到缺失值、非平稳、预测偏移就卡住的从业者。我会按「数据准备 → 平稳性处理 → 建模 → 验证 → 避坑」的顺序把一份时间序列实例从纸面落到可复现的代码上。2. 用 Pandas 把时间序列数据读进来索引、频率与缺失值2.1 时间列不是普通列to_datetime 与 set_index 的配合拿到一份 CSV 或 Excel第一步不是画图而是把时间列变成 DatetimeIndex。很多人直接用pd.read_csv读进来时间列是字符串后面做重采样、滑动窗口全报错。正确做法是两步先转 datetime再设为索引。import pandas as pd import numpy as np # 读取数据假设时间列名为 date数值列名为 value df pd.read_csv(timeseries_data.csv, parse_dates[date]) # 如果 parse_dates 没生效手动转换 df[date] pd.to_datetime(df[date], format%Y-%m-%d) # 设为索引并排序 df df.set_index(date).sort_index() # 检查索引类型和频率 print(df.index) print(df.index.freq) # 可能是 None说明频率未识别逻辑说明parse_dates在读取时直接解析比读完后转换快。set_index之后Pandas 的.resample()、.rolling()才能按时间窗口操作。sort_index()是必须的因为很多时间序列文件是乱序的不排序会导致差分和滑动窗口计算错误。参数说明format参数在时间格式统一时指定能大幅提速如果格式混杂去掉format让 Pandas 自动推断但会慢。df.index.freq为 None 时可以用df df.asfreq(D)强制指定日频但要注意这会引入缺失值。2.2 缺失时间点与缺失值asfreq 和 interpolate 的边界真实数据里时间点缺失和数值缺失是两回事。时间点缺失是指 1 月 3 日没记录1 月 4 日有数值缺失是指 1 月 3 日有记录但值为 NaN。前者用asfreq补全时间轴后者用interpolate或fillna补数值。# 补全时间轴按天频率 df df.asfreq(D) # 查看缺失情况 print(df.isna().sum()) # 线性插值补数值缺失 df[value] df[value].interpolate(methodlinear) # 如果开头或结尾仍有 NaN用前向/后向填充 df[value] df[value].ffill().bfill()逻辑说明asfreq(D)会生成完整的日期序列缺失的日期对应值为 NaN。interpolate只对数值列有效且默认按索引顺序插值。ffill和bfill是兜底但不要滥用因为会引入虚假的持续性。参数说明methodlinear适合趋势平稳的数据如果数据有明显季节性可以用methodtime或methodspline但样条插值在边界容易震荡。limit参数可以限制连续填充的最大数量避免长段缺失被过度平滑。提示插值前先画图看一眼缺失分布。如果缺失是随机的插值影响小如果缺失集中在某段时间插值会制造虚假趋势。3. 平稳性检验与差分ADF 检验、定阶与过差分识别3.1 为什么必须做平稳性检验ADF 的原假设与 p 值时间序列建模ARIMA、VAR 等的前提是平稳性。平稳的意思是均值、方差、自协方差不随时间变化。不平稳的数据直接建模会出现伪回归预测结果毫无意义。ADFAugmented Dickey-Fuller检验是最常用的方法原假设是「存在单位根即不平稳」。from statsmodels.tsa.stattools import adfuller def adf_test(series): result adfuller(series.dropna(), autolagAIC) print(fADF Statistic: {result[0]:.4f}) print(fp-value: {result[1]:.4f}) print(Critical Values:) for key, value in result[4].items(): print(f {key}: {value:.4f}) return result[1] p adf_test(df[value]) if p 0.05: print(不平稳需要差分) else: print(平稳可以建模)逻辑说明autolagAIC自动选择滞后阶数避免人为指定。p 值小于 0.05 时拒绝原假设认为平稳。但要注意ADF 对结构性突变敏感如果数据中间有断崖式下跌ADF 可能误判。参数说明regression参数可选 c常数、ct常数趋势、n无。如果数据有明显趋势用 ct如果只是均值非零用 c。maxlag默认是12*(nobs/100)^(1/4)一般不用改。3.2 差分不是越多越好一阶差分与过差分判断不平稳就差分但差分次数过多会引入过度差分表现为自相关函数ACF在滞后 1 期出现大的负值。通常一阶差分足够少数情况需要二阶。# 一阶差分 df[diff_1] df[value].diff() # 检验差分后的平稳性 p_diff adf_test(df[diff_1].dropna()) # 如果仍不平稳做二阶差分 if p_diff 0.05: df[diff_2] df[diff_1].diff() adf_test(df[diff_2].dropna()) # 画 ACF 看是否过差分 from statsmodels.graphics.tsaplots import plot_acf import matplotlib.pyplot as plt fig, axes plt.subplots(2, 1, figsize(10, 6)) plot_acf(df[diff_1].dropna(), axaxes[0], lags30) plot_acf(df[diff_2].dropna(), axaxes[1], lags30) plt.tight_layout() plt.show()逻辑说明一阶差分后的 ACF 如果快速衰减到零说明差分合适如果滞后 1 期是很大的负值接近 -0.5说明过差分应该退回。二阶差分只在数据有加速度趋势时使用比如某些经济指标。参数说明lags30是查看 30 期内的自相关一般不超过样本量的 1/4。plot_acf默认会画置信区间超出区间的柱状条表示显著自相关。注意差分会让数据损失一个样本点且差分后的数据解释性变差。如果原始数据本身平稳不要为了「看起来更平稳」而强行差分。4. 用 ARIMA 和 SARIMA 建模定阶、拟合与预测还原4.1 ARIMA 的 p、d、q 怎么定ACF 与 PACF 的读图法ARIMA(p, d, q) 中d 是差分次数p 是自回归项q 是移动平均项。定阶方法有两种看 ACF/PACF 图或用 AIC/BIC 网格搜索。先讲读图法。from statsmodels.graphics.tsaplots import plot_pacf fig, axes plt.subplots(2, 1, figsize(10, 6)) plot_acf(df[diff_1].dropna(), axaxes[0], lags30) plot_pacf(df[diff_1].dropna(), axaxes[1], lags30) plt.tight_layout() plt.show()逻辑说明ACF 截尾在 q 期后突然降到零→ MA(q)PACF 截尾在 p 期后突然降到零→ AR(p)两者都拖尾 → ARMA(p, q)。实际数据很少完美截尾所以通常结合 AIC 网格搜索。参数说明plot_pacf的method参数可选 ywYule-Walker或 ols最小二乘样本量小时用 ols 更稳。4.2 网格搜索定阶与模型拟合AIC 最小化读图法只能给大致范围精确阶数用 AIC 网格搜索。import warnings from statsmodels.tsa.arima.model import ARIMA warnings.filterwarnings(ignore) best_aic np.inf best_order None best_model None for p in range(0, 4): for q in range(0, 4): try: model ARIMA(df[value], order(p, 1, q)) result model.fit() if result.aic best_aic: best_aic result.aic best_order (p, 1, q) best_model result except: continue print(fBest ARIMA order: {best_order}, AIC: {best_aic:.2f}) print(best_model.summary())逻辑说明order(p, 1, q)中的 1 是差分次数由上一章确定。AIC 越小越好但要注意AIC 会偏向复杂模型如果两个模型 AIC 接近选简单的。try-except是必须的因为某些阶数组合会导致不收敛。参数说明model.fit()默认用最大似然可以用methodcss改用条件最小二乘速度更快但精度略低。trend参数可以指定 c 或 t但差分后一般不需要。4.3 预测与还原把差分后的预测值变回原始尺度ARIMA 预测出来的是差分后的值必须还原。forecast和get_forecast的区别在于后者能拿置信区间。# 预测未来 10 期 forecast_result best_model.get_forecast(steps10) forecast_mean forecast_result.predicted_mean forecast_ci forecast_result.conf_int() # 还原累加差分 last_value df[value].iloc[-1] forecast_original last_value forecast_mean.cumsum() print(forecast_original)逻辑说明一阶差分的还原是累加。cumsum()把差分预测值累加再加上最后一个原始值。如果是二阶差分需要累加两次。conf_int()给出置信区间但还原后的区间不是简单的累加需要按差分公式重新计算。参数说明steps10是预测步长步长越长置信区间越宽。alpha0.05对应 95% 置信区间可以改成 0.1 得到 90%。提示预测还原是最容易出错的一步。建议先用历史数据做一次「预测-还原」闭环对比原始值确认还原逻辑正确。5. 时间序列实践中的避坑与排查5 个血泪教训5.1 现象模型拟合很好预测全错原因数据泄露。在差分或标准化时用了全量数据计算均值和方差导致训练集包含了未来信息。解决所有预处理差分、标准化只能在训练集上拟合再应用到测试集。用sklearn的Pipeline或手动切分。5.2 现象ADF 检验 p 值很小但模型残差仍有自相关原因ADF 只检验单位根不检验残差白噪声。残差自相关说明模型没提取完信息。解决用 Ljung-Box 检验残差如果 p 值小于 0.05增加 AR 或 MA 阶数或考虑 SARIMA。from statsmodels.stats.diagnostic import acorr_ljungbox residuals best_model.resid lb_test acorr_ljungbox(residuals, lags[10], return_dfTrue) print(lb_test)5.3 现象季节数据用 ARIMA 预测结果完全跟不上周期原因ARIMA 不处理季节性。解决用 SARIMA指定seasonal_order(P, D, Q, s)s 是周期长度如 7 天、12 个月。D 是季节差分次数通常为 1。5.4 现象asfreq之后数据量暴增内存不够原因原始数据是低频如月频asfreq(D)强行转日频生成大量 NaN。解决不要盲目升频。如果必须升频用resample(D).interpolate()而不是asfreq或者只对缺失日期做reindex。5.5 现象预测值是一条直线原因模型退化为均值预测。常见于差分过度、阶数过高、或数据本身是白噪声。解决检查 ACF/PACF确认差分次数用auto_arima自动定阶如果数据确实是白噪声任何模型都只能预测均值这时候应该放弃建模。6. 进阶技巧用 SARIMA 处理季节性并用滚动预测验证6.1 SARIMA 的季节项参数怎么设SARIMA 在 ARIMA 基础上增加(P, D, Q, s)。s 是周期比如日数据以周为周期s7月数据以年为周期s12。P、D、Q 的定阶方法和 ARIMA 一样但看的是季节滞后上的 ACF/PACF。from statsmodels.tsa.statespace.sarimax import SARIMAX # 假设 s7先做季节差分 df[seasonal_diff] df[value].diff(7) # 拟合 SARIMA model SARIMAX(df[value], order(1, 1, 1), seasonal_order(1, 1, 1, 7), enforce_stationarityFalse, enforce_invertibilityFalse) result model.fit(dispFalse) print(result.summary())逻辑说明enforce_stationarityFalse和enforce_invertibilityFalse在数据边界不稳定时能提高收敛率但可能得到非平稳解。dispFalse关闭迭代输出。参数说明seasonal_order的第四个参数 s 必须和数据周期一致。如果 s7季节差分diff(7)消除周内模式。6.2 滚动预测用时间序列交叉验证代替单次划分单次训练/测试划分在时间序列上不可靠因为一次划分可能恰好碰到平稳段。滚动预测walk-forward更接近真实场景。from sklearn.metrics import mean_absolute_error def walk_forward_validation(data, order, seasonal_order, n_test): predictions [] actuals [] for i in range(len(data) - n_test, len(data)): train data[:i] test data[i:i1] model SARIMAX(train, orderorder, seasonal_orderseasonal_order, enforce_stationarityFalse, enforce_invertibilityFalse) result model.fit(dispFalse) pred result.forecast(steps1) predictions.append(pred.iloc[0]) actuals.append(test.iloc[0]) mae mean_absolute_error(actuals, predictions) return mae, predictions, actuals mae, preds, acts walk_forward_validation(df[value], (1,1,1), (1,1,1,7), 20) print(fWalk-forward MAE: {mae:.4f})逻辑说明每次用当前点之前的所有数据训练预测下一个点然后滑动窗口。这样能模拟真实部署时的逐步预测。MAE 比 RMSE 更直观单位与原始数据一致。参数说明n_test20是测试步数一般取总长度的 10%~20%。如果数据量小可以减少步数但至少 10 步才能看出稳定性。6.3 一个我常犯的错误忽略预测步长对置信区间的影响早期我做预测时只报点预测不报区间。后来发现步长超过 5 期后置信区间宽到没有实用价值。现在我的习惯是预测步长不超过一个季节周期并且必须附上置信区间。如果区间太宽就老实告诉业务方「这个预测不可靠」而不是硬给一个数字。希望帮到你。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。