ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

时间序列预测Python实战:从环境搭建到ARIMA、XGBoost与LSTM

时间序列预测Python实战:从环境搭建到ARIMA、XGBoost与LSTM 简介面向Python数据分析与时序预测学习者的完整代码包源于《Introduction to Time Series Forecasting with Python》教程适合具备基础Python知识、希望系统掌握时序建模与预测流程的读者。压缩包共214个文件以181个Python脚本为主另含32个CSV实验数据集与1份Markdown说明文档整体仅237KB轻量易用。脚本覆盖数据预处理、差分平稳化、ARIMA/SARIMA建模、状态空间模型、基于随机森林与神经网络的机器学习预测以及Facebook Prophet应用和MSE/RMSE/MAE等评估指标计算配套数据包括每日最低气温、太阳黑子、每日女性出生人数等经典时序数据集便于直接复现与对比。目前已有7257人学习参考适合想通过完整代码演练理解时间序列预测全流程、并迁移到金融或销售场景的初学者。1. 这个 zip 里装的不是答案是一整套能复现的时序预测实验拿到手是一个叫Code for Introduction to Time Series Forecasting with Python.zip的文件很多人会把它当成“答案包”急着解压翻代码想从里面抄一段能用的预测脚本。真正这样操作的人一半卡在环境装不起来一半卡在不知道每段代码在为什么问题服务。这个包里装的其实是配合《Introduction to Time Series Forecasting with Python》这本书的示例工程覆盖了数据加载、评估指标、统计学模型、机器学习模型到深度学习模型的完整链路。它不是让你直接抄答案的而是让你顺着它的目录结构把“书里讲了什么”和“代码里写了什么”对应起来。适合两类人刚入门想跑通全流程的 Python 学习者以及已经会调包、想找一套干净模板快速搭实验骨架的工程师。把这本书的代码跑通一遍你对时序预测的认知会从“看过”变成“能复现”。2. 先把环境跑通从解压 zip 到 notebook 出图的 30 分钟拿到代码包的第一件事不是读代码而是让代码能跑起来。这个过程看似简单但 zip 解压、依赖安装、内核选择每一步都有常见翻车点。2.1 解压与目录结构先看清包里到底是什么布局Linux 下最稳的解压命令是用unzip重点是把-d参数用上避免 zip 内容散落到当前目录# 文件名带空格必须加引号-d 指定解压目录 unzip Code for Introduction to Time Series Forecasting with Python.zip -d tsf-code-d tsf-code会把所有文件释放到tsf-code目录下解压后第一件事是cd tsf-code ls -R看目录结构。常见布局是data/放 CSV 数据集notebooks/放按章节拆分的笔记本scripts/放纯 Python 脚本有的版本还把results/或figures/单独拎出来。Windows 用户右键“全部解压缩”即可但如果解压后中文文件名乱码多半是 zip 本身用了 GBK 编码Linux 下可以用unzip -O GBK指定编码Windows 下用 7-Zip 打开后手动解压通常能绕过去。提示zip 文件名带空格在命令行里不写引号会直接把文件名拆成两个参数这是新手最容易踩的第一个坑。2.2 依赖清单与安装顺序虚拟环境别嫌麻烦这套代码的运行依赖并不复杂但直接往系统 Python 里pip install后面会吃苦头。尤其是 statsmodels、scikit-learn、tensorflow 三者的 NumPy 版本要求经常互相打架。我建议从第一步就建虚拟环境避免把系统环境搞乱python -m venv .venv # Linux/macOS 激活 source .venv/bin/activate # Windows 激活命令不同 .venv\Scripts\activate # 有 requirements.txt 就直接装没有就按下面的最小清单装 pip install -r requirements.txt需求文件里通常包含下面这些库我把它们的作用列成一张表方便你对照依赖库在代码里负责什么pandas、numpy数据加载、日期解析、滞后特征构造matplotlib画出时序曲线、残差图、预测对比图statsmodelsARIMA、ETS 等统计学模型的拟合与推断scikit-learn数据切分、缩放、机器学习模型的评估tensorflow / kerasLSTM 等深度学习模型的训练只有后面章节用得到如果requirements.txt不存在最小化安装建议先装前五个等跑到深度学习那章再单独装 tensorflow。这样做的理由是tensorflow 在装的时候会改写 NumPy 版本而 statsmodels 对 NumPy 版本很敏感后装能少折腾一轮。2.3 跑通第一个 notebook先确认内核和环境匹配依赖装好后用 Jupyter 打开 notebooks 目录下的第一个文件。启动命令很简单jupyter lab启动后浏览器会打开 Jupyter Lab 界面。这一步最常见的坑是明明在虚拟环境里装了包notebook 却报ModuleNotFoundError原因通常是 notebook 内核选的是系统 Python 而不是当前虚拟环境。我一般在 VSCode 里做 Python 环境配置打开.ipynb文件后点右上角内核选择器选.venv对应的解释器如果列表里没有先执行一次python -m ipykernel install --user --nametsf注册内核。确认内核后跑第一个 cell 里类似import pandas as pd; df pd.read_csv(...)的代码能正常打印数据框就说明环境通关了。3. 数据加载与评估时序预测代码的第一道分水岭环境跑通只是热身真正的分水岭在数据这一步。时序预测的数据处理和普通机器学习不一样日期必须解析成时间索引切分必须按时间顺序评估指标也有自己的讲究。这套代码里体现得很清楚照着它的思路走能省很多事。3.1 三种数据来源的加载方式代码包里最常见的场景是读一个单变量 CSV。比如经典的国际航班乘客数据一行是月份一行是乘客数。加载标准写法是import pandas as pd df pd.read_csv( data/airline-passengers.csv, parse_dates[Month], # 把 Month 列解析成 datetime 类型 index_colMonth, # 把日期列设为索引 ) print(df.head()) print(df.index) # 确认索引是 DatetimeIndex 而不是普通 RangeIndexparse_dates是这套代码的灵魂参数。时序模型需要依赖时间顺序索引必须是DatetimeIndex才能做滞后、重采样、画图这类操作。如果数据没在读取时解析日期后面到处都会出问题。第二种来源是直接从接口或数据库落到 DataFrame常见做法是先用pd.to_datetime()统一格式化再设索引因为从数据库拉出来的时间字段往往不是标准字符串。第三种来源是多列宽表比如每列是一个城市的销量处理时会把 DataFrame 按列循环对每一列单独走预测流程代码的核心逻辑和单变量完全一样。3.2 按时间顺序切分而不是随机切分新手最容易犯的错是把train_test_split那套 shuffle 思路带进来。时间序列一旦随机打乱等于把未来数据混进了训练集指标会好看得离谱真实部署直接翻车。这套代码里的切分逻辑非常清晰取最后 N 个时间点做测试集# 单变量月度序列习惯用最后 12 个月做测试 n_test 12 train df.iloc[:-n_test] # 从开头到倒数第 13 行 test df.iloc[-n_test:] # 最后 12 行 print(f训练集范围: {train.index.min()} ~ {train.index.max()}) print(f测试集范围: {test.index.min()} ~ {test.index.max()})iloc按行位置切分不受索引是否连续影响适合日期有缺失的情况。如果你的数据是每日粒度测试集一般取 7 天或 30 天如果是月粒度12 个点几乎成了默认配置够评估季节性规律又不会让训练集太短。还有一种更严谨的 walk-forward 切分在代码包后面出现本质是不断把测试集的一个点并进训练集重新训练再预测下一个点代价是训练次数多适合样本量小的场景。3.3 MSE、RMSE、MAE 怎么选怎么算评估代码在包里被封装成一个函数不同的指标对应不同的业务语义。最小实现是这样的from sklearn.metrics import mean_squared_error, mean_absolute_error import numpy as np def evaluate_forecast(y_true, y_pred): mse mean_squared_error(y_true, y_pred) rmse np.sqrt(mse) mae mean_absolute_error(y_true, y_pred) return {MSE: mse, RMSE: rmse, MAE: mae} # 用法示例 result evaluate_forecast(test[Passengers], predictions) print(result)三个指标我一般按场景取舍MSE 因为做了平方对大误差极其敏感模型只要在个别点上预测离谱MSE 就会暴涨适合用来“发现”模型有没有大偏差RMSE 是 MSE 开根号单位回到原始数据的量纲方便和业务方解释MAE 是平均绝对误差最贴近业务直觉比如预测销量平均偏差 300 件。如果同一组数据上 RMSE 明显大于 MAE说明误差分布里存在少数特别大的点这时候不要急着调模型先去看那几个点是不是统计异常值。4. 模型代码怎么组织从 ARIMA 到 XGBoost 再到 LSTM这套 zip 里的代码把模型分成了三个梯队统计学模型、机器学习模型、深度学习模型。每个梯队的数据处理方式完全不同代码结构也因此不同。理解它们的组织方式比背诵 API 有用得多。4.1 ARIMA 与 ETS 的拟合套路就是三个步骤统计学模型的调用逻辑高度统一定义模型、拟合数据、预测未来。以 ARIMA 为例现代 statsmodels 的 API 写法是from statsmodels.tsa.arima.model import ARIMA # order(p, d, q)意思是自回归阶数、差分阶数、移动平均阶数 model ARIMA(train, order(1, 1, 1)) fitted model.fit() # 预测测试集长度的未来值 forecast_result fitted.get_forecast(stepslen(test)) pred_mean forecast_result.predicted_mean # 点预测结果 conf_int forecast_result.conf_int() # 置信区间默认 95% print(fitted.summary()) # 查看系数的 P 值判断模型是否有效order三个参数是理解这套代码的钥匙。p1表示用最近的 1 个历史值做回归d1表示做一阶差分把非平稳序列变平稳q1表示误差项用 1 阶移动平均。初学者直接套(1,1,1)是安全的起手式但这不叫调参只是给了模型一个默认起点。get_forecast比老式的forecast()多返回置信区间这个能力在画图时非常有用能直观看出预测的不确定性随步长加宽的过程。同类的 ETS 模型参数更直白看名字就知道在干什么from statsmodels.tsa.holtwinters import ExponentialSmoothing model ExponentialSmoothing( train, trendadd, # 趋势项用加法如果趋势呈线性 seasonaladd, # 季节项用加法适合波动幅度稳定的序列 seasonal_periods12 # 月度数据一年 12 期 ) fitted model.fit()选加法还是乘法要看序列的季节波动幅度波动幅度常年稳定加法够用节假日效应强、夏季销量是冬季三倍的序列乘法更合适。这套代码里经常同时展示两种设置原因是让你直接在结果里对比哪个误差更小。4.2 把时间序列改造成监督学习才能喂给 XGBoost统计学模型天然理解时间结构而 XGBoost 这种机器学习模型不认时间它只认特征矩阵。因此代码里会有一段关键的“滞后特征构造”把单变量序列变成带特征和标签的表格def make_lag_features(series, lags(1, 2, 3, 6, 12)): df series.to_frame(namey) # 用 shift 把历史值平移到当前行作为特征 for lag in lags: df[flag_{lag}] df[y].shift(lag) # shift 会产生 NaN丢掉前若干行 return df.dropna() features make_lag_features(train[Passengers]) X features.drop(columnsy) y features[y]shift(lag)是这个函数的核心lag_1是上一个时间点的值lag_12是一年前同期的值。当数据存在明显的年度周期性时lag_12往往是 XGBoost 的特征重要性第一名这个现象在代码运行后的 feature importance 图里看得很清楚。特征构造完训练测试流程和普通回归完全一样用 sklearn 的Pipeline包一层就能配合GridSearchCV调max_depth、n_estimators这些参数。注意一个细节测试集的特征也要用训练集的同一套构造逻辑生出来测试集的第一行会因为没有上一步的历史值而缺失常见做法是把训练集末尾几行拼到测试集前面补特征。4.3 LSTM 的最小可跑结构先归一化再切窗口LSTM 的代码结构比前两者复杂一个维度但核心就三件事归一化、构造时间窗口、训练循环。时序数据喂给 LSTM 前必须缩放到 0~1 区间否则激活函数容易饱和导致梯度消失from sklearn.preprocessing import MinMaxScaler scaler MinMaxScaler(feature_range(0, 1)) scaled_train scaler.fit_transform(train[[Passengers]]) # 只在训练集上 fit scaled_test scaler.transform(test[[Passengers]]) # 测试集只用 transformfit_transform和transform分开写不是洁癖是数据泄漏问题如果对整条序列一次性fit_transform缩放器就“偷看”了测试集的取值范围预测结果会虚高。构造窗口的常见做法是设定lookback12即用过去 12 个月预测下一个月然后把窗口数组 reshape 成 LSTM 要求的(样本数, 时间步长, 特征数)三维形状。训练部分就是一个标准的 keras 顺序模型一个LSTM(50)层接一个Dense(1)输出层编译时用adam优化器和mse损失。训练轮数不要贪多我在跑这类代码时习惯加一个EarlyStopping监控验证集损失连续 10 轮不下降就停这能省掉大量空等时间。5. 避坑手册跑这套代码最常见的 5 个翻车点代码本身没问题跑不起来大多是因为环境或使用方式踩了坑。我把这些年见过最多的问题整理成五条每条都是“现象 → 原因 → 解决”的套路照着排查能省下大量瞎试的时间。5.1 statsmodels API 报错同一个函数名字却在不同的位置现象代码里import statsmodels.api as sm然后sm.tsa.ARIMA(...)报错或者提示ARIMA类位置已变更也有的是拟合时报ValueError: non-stationary starting autoregressive parameters。原因statsmodels 在 0.12 之后把 ARIMA 从statsmodels.tsa.arima_model迁移到了statsmodels.tsa.arima.model旧写法在新版本里直接失效或行为改变。另一个常见原因是传入的数据序列是 int 类型而不是 float 类型导致估计器内部矩阵运算报错。解决统一改用新 APIfrom statsmodels.tsa.arima.model import ARIMA在运行代码前先打印statsmodels.__version__确认环境版本。如果数据列是整型先astype(float)转换再传入拟合。5.2 解压后中文文件名乱码pandas 读取路径报错现象Windows 上右键解压出来的文件中文名变成一堆乱码代码里用pd.read_csv(data/乘客数.csv)直接报FileNotFoundError或者虽然能读但路径里的中文在终端里显示成转义字符。原因zip 包内部文件名用的是 GBK 编码而 Windows 解压时按 UTF-8 解码导致乱码更深一层的原因是脚本代码文件本身保存成了 GBKPython 3 默认 UTF-8 读源码就报错。解决把解压目录和所有文件名改成纯英文这是最省事的路如果乱码已经产生在 Linux 下用unzip -O GBK重新解压。代码文件保存时统一选 UTF-8 编码VSCode 右下角可以直接切换。路径带空格的问题也一样处理方式是代码里统一用下划线替换空格列名。5.3 归一化时整条序列一起 fit_transform预测结果虚高现象LSTM 或神经网络模型在测试集上 RMSE 奇低画图时预测曲线和真实曲线几乎重合但一部署到新数据上误差暴涨。原因scaler.fit_transform(df)把训练集和测试集放在一起做了归一化缩放器提前看到了测试集的最大值和最小值模型在“开卷考试”中拿到了答案。这个数据泄漏在时序场景里非常隐蔽因为代码不报错指标还挺好看。解决严格按“训练集fit_transform测试集只transform”的写法。需要计算整个序列的统计量时也只允许使用训练集的统计值。这个坑是最值得花十分钟自查的我自己带过的项目里至少有三次线上事故和它有关。5.4 LSTM 每次跑结果都不一样甚至第二次跑指标差一倍现象同一个 notebook什么代码都没改第二天重跑一轮loss 曲线和预测结果完全不同有时 RMSE 从 20 变成 50。原因深度学习模型有随机初始化权重、dropout、数据打乱都依赖随机数。科学计算库和 Python 的随机数是各自独立的只设一个random.seed(0)完全不够导致每次实验的起点不一样。解决在训练代码开头把所有随机种子一口气固定住。import random import numpy as np import tensorflow as tf random.seed(42) np.random.seed(42) tf.random.set_seed(42)这套四行代码应该成为每个深度学习 notebook 的固定开场。另外LSTM 训练时把shuffleFalse保持时间顺序或固定 shuffle 的随机种子输出会更稳定。5.5 Jupyter 里画图不显示或者中文全部变成方块现象notebook 里执行含plt.plot()的 cell 没任何输出另一台机器上跑通了图也能出但标题和图例里的中文全是方块。原因前者的典型原因是 notebook 内核环境没有启用 matplotlib 的 inline 模式后者是 osx 或 Linux 系统里 matplotlib 默认英文字体中文渲染直接掉了。解决在 notebook 第一个 cell 写入%matplotlib inline这是行业标配做法。中文字体问题则是在画图前设置字体回退。import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei, Noto Sans CJK SC, Arial Unicode MS] plt.rcParams[axes.unicode_minus] False # 修复负号显示成方块的问题有这张配置打底中英文混排的图基本都能正常渲染。远程服务器上跑代码时记得改用plt.savefig(...)落盘而不是plt.show()否则没有显示器的环境会直接抛错。6. 把这套代码改造成自己的模板一条从跑通到复用的路径跑通整套代码只是第一步价值在于把里面散落的脚本整合成自己能复用的模板。我从这套 zip 里提炼三条改造路径都是能立刻上手的技巧。把数据集路径和列名抽成配置。原始代码里散落着大量的airline-passengers.csv和Passengers这类硬编码。我习惯把它们收进一个字典统一放在代码顶部。config { data_path: data/airline-passengers.csv, target_col: Passengers, date_col: Month, test_size: 12, order: (1, 1, 1), }这样每次换数据只需要改配置不用翻遍代码逐个替换。换到多站点销量预测时target_col可以改成循环遍历的列名列表整个实验流程不需要动。用一个评估循环对比多个模型。这套代码里每个模型是独立的脚本不利于横向对比。我一般会把模型切面统一成一个接口输入训练集和测试集输出预测结果。然后写一个循环把 ARIMA、ETS、XGBoost 依次跑一遍输出指标的对比 DataFrame。这个做法能让你一眼看出哪个模型在你的数据上真正占优而不是凭感觉拍板。每次实验留一份记录。时序预测的实验变量多参数、窗口、数据版本都会影响结果。我现在每跑一轮会把配置字典和评估指标一起追加写进 CSV文件名带上日期时间戳。几天后回看时能知道当时的结论是怎么得出的这是给未来的自己留的后悔药。我现在的习惯是先把基线跑通再谈调参优化任何改动前先记录当时的版本结果。希望这个思路对你有帮助。本文还有配套的精品资源点击获取
返回列表