尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Python时间序列预测实战:从ARIMA到Prophet与机器学习

发布时间:2026/9/28 14:43:03

资讯中心
01
ARTICLE

Python时间序列预测实战:从ARIMA到Prophet与机器学习

Python时间序列预测实战:从ARIMA到Prophet与机器学习
简介这套Python时间序列预测代码资源面向数据分析与机器学习学习者从趋势、季节性与周期性等基础概念讲起系统涵盖Pandas时间序列处理、数据清洗与差分预处理、ARIMA与SARIMA建模、状态空间与卡尔曼滤波动态更新以及随机森林、Prophet等前沿方法帮助读者快速建立从理论到实践的知识框架。资源共214个文件以181个Python脚本为核心配合32个CSV示例数据集和1个Markdown说明文档压缩包仅237KB轻量便携。已有7257人学习下载是广受关注的时间序列入门参考资料。脚本覆盖数据加载、趋势分析、模型构建与训练预测全过程包含matplotlib可视化与MSE、RMSE、MAE、R²等评估指标实现多数代码可直接运行便于结合气温、太阳黑子等经典数据动手实验理解模型机理后迁移到金融、销售等实际场景是从理论到代码实践的高性价比资源包。1. 这份 Python 时间序列预测代码包到底能帮你解决什么问题把一份 CSV 读进 Pandas画出折线图接着拟合 ARIMA、跑 Prophet、再对比随机森林——这套 Python 时间序列预测流程我在气象、销售、流量预测几个项目里反复折腾过。最耗时间的从来不是模型本身而是数据格式、平稳性处理、滞后特征怎么构造这些细节。这份《Introduction to Time Series Forecasting with Python》代码包就是把整条链路按步骤摊开的实战笔记daily-minimum-temperatures.csv、sunspots.csv、daily-total-female-births.csv 三个经典数据集配上 pandas 数据预处理、ARIMA/SARIMA、Prophet、机器学习模型的完整可运行代码。适合刚入门、需要对照代码跑通流程的 Python 数据分析师也适合想把时序预测完整链路一次搭顺手的从业者。2. 数据加载与预处理Pandas 时间索引、缺失值与差分先把 zip 包解压到项目目录三个 CSV 文件不要改文件名直接放同一目录。我用 VSCode 的 Jupyter 插件一步步调试环境建议 Python 3.8 以上装好 pandas、statsmodels、pmdarima、prophet、scikit-learn、matplotlib 这几件套。2.1 三个数据集与读取方式三个 CSV 是不同形态的时间序列各代表一类典型问题文件数据内容时间粒度特征daily-minimum-temperatures.csv每日最低气温日1981–1990年季节性强无明显趋势sunspots.csv太阳黑子数月多周期叠加非线性明显daily-total-female-births.csv每日新生儿数日1959 全年短期随机性强趋势弱数据集之间的差异是刻意安排的气温数据适合演示 SARIMA 和 Prophet太阳黑子适合演示非线性模型出生数适合演示短期滚动预测。换到自己的业务数据时先判断数据属于哪个类型再选模板代码比拿一个模型硬套省事得多。import pandas as pd # 气温数据日度约10年 df_temp pd.read_csv( daily-minimum-temperatures.csv, parse_dates[Date], index_colDate ) df_temp.columns [temp] print(df_temp.head()) print(df_temp.info()) # 太阳黑子月度数据 df_sunspot pd.read_csv( sunspots.csv, parse_dates[date], index_coldate ) print(df_sunspot.head())这段代码里最容易看漏的是parse_dates和index_col两个参数。parse_dates[Date]把日期列解析成 datetime64 类型index_colDate把日期设成索引。后续 resample、按年切片、差分对齐时间轴都依赖这两步。如果不指定Pandas 会把日期当普通字符串画图时 x 轴按字典序排列时间顺序全乱预测结果也会错位到让你怀疑人生。2.2 可视化观察趋势与季节性先画图再建模时间序列拿到手第一步不是建模是画图这一步就是常说的 Python 数据分析与可视化。我一般会把原始序列、滚动均值、按月聚合三张图都出一遍先定性地判断有没有趋势、季节性周期多长再决定用不用差分、要不要上 SARIMA。import matplotlib.pyplot as plt # 原始序列 df_temp[temp].plot(figsize(12, 4), titleDaily Min Temperature) plt.show() # 30天滚动均值观察趋势 df_temp[temp].rolling(window30).mean().plot(figsize(12, 4)) plt.show() # 按月聚合观察季节性 monthly_mean df_temp.groupby(df_temp.index.month)[temp].mean() monthly_mean.plot(kindbar, figsize(8, 4)) plt.show()滚动窗口window30适合日度数据把日间噪声磨掉后趋势更清楚。按月聚合是看季节形态的最快方式气温数据会呈现典型单峰冬季低、夏季高。注意groupby(df_temp.index.month)取到的是月份 1 到 12跨年份时会把不同年份的同月数据合并求均值这正是我们想要的季节剖面。如果按月画出来曲线平坦没有起伏说明季节性弱后面可以省掉 SARIMA 的季节差分。2.3 缺失值、异常值处理与差分三个 CSV 都很规整但换成自己的数据时缺失和时间索引不连续是大概率遇到的事。先看缺失量print(df_temp.isnull().sum()) # 检查时间索引是否连续 all_days pd.date_range( startdf_temp.index.min(), enddf_temp.index.max(), freqD ) print(缺失日期数:, len(all_days.difference(df_temp.index)))缺失值处理我按场景来连续缺失 1 到 2 个点用interpolate()线性插值缺失段较长用前向填充ffill()只能算兜底如果业务上缺的那几天本来就没意义比如节假日无交易直接 drop 更干净。不要上来就fillna(0)会把序列均值拉偏ARIMA 的差分和 ACF 图全部变形。df_temp[temp] df_temp[temp].interpolate(methodlinear) # 平稳性检验 from statsmodels.tsa.stattools import adfuller series df_temp[temp].dropna() result adfuller(series) print(ADF p-value:, result[1]) # p 0.05 时不平稳做一阶差分 if result[1] 0.05: df_temp[temp_diff] series.diff(1)ADF 检验的原假设是序列存在单位根、不平稳p 值小于 0.05 才能拒绝原假设、认为平稳。气温这类强季节数据一阶差分后仍可能带季节单位根这时要么做季节差分要么交给 SARIMA 内部处理。差分产生的第一个 NaN 不需要补建模时dropna()即可。3. ARIMA 与 SARIMA 实战从自动定阶到季节参数调优ARIMA 是时序预测绕不开的经典模型。虽然现在有不少人直接上 Prophet 或深度学习但 ARIMA 训练快、可解释性强、对短序列友好尤其是和 auto_arima 配合后定阶不用靠猜仍然是实际项目里最先尝试的方案。3.1 ARIMA 的三个组成部分ARIMA 把非平稳序列的建模拆成三块AR(p) 用历史观测值的线性组合解释当前值I(d) 用 d 阶差分把非平稳序列变平稳MA(q) 用历史预测误差的线性组合修正当前值。理解这三个字母比背公式更容易确定参数p 大致对应自相关在几阶处截尾q 对应偏自相关在几阶处截尾d 则是让 ADF p 值低于 0.05 的最少差分次数。对日度气温数据来说d 取 1 通常就够因为均值漂移不严重不是随机游走那种不收敛的序列。p 和 q 可以观察 ACF、PACF 图来定但手工看图定阶因人而异所以我一般先用 pmdarima 跑一个参考值再手动微调。模型选型的逻辑在 ARIMA 这里体现得很典型先做最小代价的平稳化再确定滞后阶数最后看残差是否还有自相关。3.2 手动拟合 ARIMAorder 参数怎么定from statsmodels.tsa.arima.model import ARIMA model ARIMA(df_temp[temp], order(5, 1, 0)) fit model.fit() print(fit.summary()) # 未来30天预测 forecast fit.get_forecast(steps30) pred_mean forecast.predicted_mean pred_conf forecast.conf_int(alpha0.05) print(pred_mean.head())order(5, 1, 0)表示 AR(5)、一阶差分、无 MA 项。气温序列日与日之间有很强的自相关AR 阶数取 5 左右能覆盖一周内的天气惯性。如果取 1 或 2残差里通常还能看到明显的自相关说明信息没榨干。fit.summary()里重点看 coef 列的 P|z|不显著的滞后项可以去掉以简化模型。get_forecast(steps30)返回预测均值、置信区间和标准误。alpha0.05表示 95% 置信区间画图时能直观看到预测不确定性随步长放大按月汇报时比单条预测线更有说服力。如果手动定阶没底用 pmdarima 兜底跑一轮from pmdarima import auto_arima auto_fit auto_arima( df_temp[temp], start_p0, max_p10, start_q0, max_q10, d1, seasonalFalse, stepwiseTrue, traceTrue, information_criterionaic ) print(auto_fit.order)stepwiseTrue用贪心搜索而不是全组合遍历几分钟内能结束。information_criterionaic在拟合优度和参数数量之间做权衡避免参数越多模型越好的假象。auto_arima 给出的 order 可以直接塞进 statsmodels 的 ARIMA 使用两个库的接口兼容性在这一场景下没有问题。3.3 SARIMA 处理周期性seasonal_order 的四个值当 ACF 在滞后 12、24、36 处持续出现显著峰值说明序列有明确季节周期此时 ARIMA 不够用要换 SARIMAX。seasonal_order有四个值(P, D, Q, m)前面三个对应季节部分的 AR、差分、MA最后一个 m 是季节周期长度。月度数据 m12日度数据按周 m7季度数据 m4。from statsmodels.tsa.statespace.sarimax import SARIMAX s_model SARIMAX( df_temp[temp], order(1, 1, 1), seasonal_order(1, 1, 1, 12), enforce_stationarityFalse, enforce_invertibilityFalse ) s_fit s_model.fit(dispFalse) print(s_fit.summary())这里的 m 我写了 12 而不是 7因为气温的季节周期是「年」而不是「周」按月度聚合后周期就是 12。写错季节周期是 SARIMA 最常见的翻车点把 m7 用在日度气温数据上模型会去学周内波动而年周期完全没被建模预测结果自然跑偏。提示seasonal_order 里的 m 不是拍脑袋定的。月度数据取 12、日度数据按周取 7、季度数据取 4。拿不准时先画按月聚合图看周期峰出现在哪个滞后阶数。enforce_stationarity和enforce_invertibility默认 True 时会限制参数空间对强季节性数据容易导致收敛失败。设成 False 后更容易拟合成功但代价是需要人工检查 summary 里的残差诊断看 Ljung-Box p 值是否大于 0.05否则残差里还有可提取的信息。4. Prophet 与机器学习方法非线性时序的两种替代路线ARIMA 对线性关系处理得很好但遇到太阳黑子这种多周期叠加、非线性明显的序列就力不从心。这时候两条路一条是用 Prophet 这种为业务时序设计的工具一条是把时序改造成普通回归问题喂给随机森林或神经网络。4.1 Prophet开箱即用的趋势加季节模型Prophet 是加法模型把时间序列分解成趋势、季节性、节假日三部分核心是拟合分段线性趋势函数。它和 ARIMA 最大的区别是不需要平稳化直接吃原始时间戳和数值自动处理缺失值和离群点。对非统计背景的人来说Prophet 的接口友好得多但它的突变点检测像是黑匣子调参方向不对时预测曲线会飘。from prophet import Prophet df_prophet df_temp.reset_index().rename( columns{Date: ds, temp: y} ) model Prophet( yearly_seasonalityTrue, weekly_seasonalityFalse, daily_seasonalityFalse, changepoint_prior_scale0.05 ) model.fit(df_prophet) future model.make_future_dataframe(periods365) forecast model.predict(future) model.plot(forecast)Prophet 强制要求列名是ds和yds是时间戳y是数值。yearly_seasonalityTrue让模型自动拟合年周期对气温数据必开weekly_seasonality对日度气温没意义关掉省参数。changepoint_prior_scale是趋势突变点灵敏度默认 0.05数据里有明显拐点时可以调到 0.1 到 0.5但调太高会把噪声当趋势。make_future_dataframe(periods365)在历史数据末尾往后生成 365 天时间戳predict返回的yhat是预测值yhat_lower和yhat_upper是置信区间。如果数据里有固定的节假日效应比如电商大促可以在 Prophet 里加add_country_holidays或自定义节假日列表预测效果会再提升一截。4.2 滑窗法把时序改造成监督学习随机森林、SVM、神经网络都不能直接吃时间序列需要把序列转成监督学习格式当前值、滞后值、目标值。做法是按窗口滑动构造特征这就是滑窗法。def make_lags(series, n_lags): df pd.DataFrame({y: series}) for i in range(1, n_lags 1): df[flag_{i}] series.shift(i) return df.dropna() df_feat make_lags(df_temp[temp], 14) print(df_feat.head(16))shift(i)把序列整体下移 i 行lag_1是昨天的气温lag_14是两周前的气温。dropna()去掉前 14 行没有足够历史数据的样本。n_lags取多少没有定论我一般先试季节周期的 1 到 2 倍气温数据 14 天是合理起点——太短模型看不到周期太长特征冗余、计算慢、还容易过拟合。关键坑在这里make_lags基于完整序列构造如果之后再做切分测试集特征会用到未来信息之外的历史数据这就是典型的数据泄漏。正确做法是先按时间切分原始序列再对切分后的每一段分别构造 lag 特征。后面第 5 章会展开讲。4.3 随机森林与 MLP 的实战对比特征造好后模型就是普通回归任务。随机森林对特征尺度不敏感不用标准化MLP 需要标准化输入否则高层神经元容易被大数值特征主导。from sklearn.ensemble import RandomForestRegressor from sklearn.neural_network import MLPRegressor from sklearn.preprocessing import StandardScaler from sklearn.metrics import mean_squared_error X df_feat.drop(columnsy) y df_feat[y] cut int(len(df_feat) * 0.8) X_train, X_test X.iloc[:cut], X.iloc[cut:] y_train, y_test y.iloc[:cut], y.iloc[cut:] # 随机森林 rf RandomForestRegressor( n_estimators300, max_depth12, min_samples_leaf3, random_state42 ) rf.fit(X_train, y_train) # MLP 需要标准化 scaler StandardScaler() X_train_s scaler.fit_transform(X_train) X_test_s scaler.transform(X_test) mlp MLPRegressor( hidden_layer_sizes(32, 16), max_iter500, early_stoppingTrue, random_state42 ) mlp.fit(X_train_s, y_train) pred_rf rf.predict(X_test) pred_mlp mlp.predict(X_test_s) print(RF RMSE:, mean_squared_error(y_test, pred_rf, squaredFalse)) print(MLP RMSE:, mean_squared_error(y_test, pred_mlp, squaredFalse))n_estimators300在特征量不大时足够再多只增加耗时max_depth12限制单棵树深度min_samples_leaf3迫使叶子节点至少 3 个样本两者都是常规防过拟合策略。MLP 的hidden_layer_sizes(32, 16)对 14 个 lag 特征规模够用early_stoppingTrue在验证集 loss 不再下降时提前终止省时间。MLP 参数敏感翻车概率比随机森林高所以我一般先用随机森林跑一个基准再决定要不要上 MLP。5. 模型评估与常见问题排查五个高频踩坑点模型评估这部分看着简单实际上最容易让人栽跟头。指标选错、切分方式不对、数据泄漏每一条都会让测试结果虚高然后上线被打脸。这一章按「现象 → 原因 → 解决」记录我反复遇到过的五个坑每一条都是真金白银换来的。5.1 回归指标与业务口径from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score print(RMSE:, mean_squared_error(y_test, pred_rf, squaredFalse)) print(MAE:, mean_absolute_error(y_test, pred_rf)) print(R²:, r2_score(y_test, pred_rf))RMSE 对大的误差点更敏感适合不希望出现严重偏离的场景比如库存控制里一个极端错误就能导致缺货或积压。MAE 反映平均偏差业务汇报更直观。R² 在数据平稳时有参考价值但对差分后序列构建的模型意义不大因为差分已经去掉了大部分均值结构R² 天然偏低不代表模型差。5.2 训练集切分与数据泄漏切分必须按时间顺序而不是随机 shuffle这是时序和普通表格分类最本质的区别。常见做法是前 80% 做训练、后 20% 做测试。上面滑窗代码里我特意用了iloc切分而不是train_test_split就是为了强调这点train_test_split默认随机抽样会打乱时间顺序模型看到未来数据测试指标虚高到不可信上线后实际误差可能是测试时的两倍以上。5.3 高频踩坑记录现象 1read_csv之后日期变成了 object 类型plot出来的 x 轴乱序预测结果错位。 原因没加parse_dates参数Pandas 把1981-01-01当作普通字符串处理。 解决read_csv时加parse_dates[Date]如果日期格式特殊用pd.to_datetime(df[Date], format%m/%d/%Y)显式指定格式。检查方法很简单df_temp.index.dtype为 datetime64 才算成功。现象 2auto_arima跑了几十分钟还没出结果CPU 持续满载。 原因p、q 搜索范围太大且stepwiseFalse组合数按 (max_p1)*(max_q1) 量级膨胀。 解决先stepwiseTrue开贪心搜索max_p、max_q限制在 8 以内seasonalFalse。只有数据量很小且确信需要全搜索时才关 stepwise。traceTrue能看到当前搜索到哪个组合跑得太慢时及时止损。现象 3Prophet 预测曲线整体比真实值低一截趋势突变处跟不上。 原因changepoint_prior_scale0.05对趋势变化的灵敏度不够突变点没被识别。 解决把changepoint_prior_scale调到 0.2 试跑对比验证集误差。调大后测试误差反而上升说明模型把噪声当成了趋势回退到 0.05 附近。用n_changepoints限制突变点数量也能防止过度拟合。现象 4模型在训练集 R²0.99测试集 RMSE 是训练集的 5 倍以上。 原因先构造 lag 特征再切分测试集特征间接包含了训练区间的信息或者 lag 数量太多把噪声细节记住了。 解决先按时间切分原始序列再对每一段构造 lag 特征同时减小max_depth、增大min_samples_leaf。另外检查预测值是否比真实值滞后一天——如果 lag_1 特征太强模型学到的只是「昨天等于今天」。现象 5对差分序列做预测后预测结果回不到原始量纲温度预测出来是 0.01 这种歪值。 原因在 diff 后的序列上建 ARIMApredict 输出是差分值没有做逆差分还原。 解决直接用 statsmodels 的 ARIMA 并传入原始序列它会自动做差分和逆差分输出天然是原始尺度。如果手动差分还原逻辑是pred_original[i] pred_diff[i] actual[i-1]也就是差分预测值逐段累加到真实观测上。这个还原逻辑建议写成函数封装第一遍手写必出错。6. 多步预测与滚动验证让预测结果真正可用前面的get_forecast(steps30)是一次性给出未来 30 天的预测但其中第 30 天的预测建立在第 29 天预测值之上误差会逐级累积步长越长越不可信。更稳健的做法是滚动预测每预测一天就把真实值追加到历史里再预测下一天每一步都基于真实观测评估出的模型能力更接近业务实况。import numpy as np history df_temp[temp].values[:3000] test df_temp[temp].values[3000:3010] preds [] for t in range(len(test)): model ARIMA(history, order(5, 1, 0)) fit model.fit() yhat fit.forecast(steps1)[0] preds.append(yhat) history np.append(history, test[t]) print(滚动预测前5步:, preds[:5])每次循环重拟合一次模型很耗时但验证集通常只取几十步代价可接受。业务上如果追求效率常见做法是每 7 天或 30 天重拟合一次中间用最近一次拟合的模型滚动预测。滚动预测比一次性预测更能暴露模型的短期跟踪能力。我最早做气温预测时直接拿一条 30 天预测线汇报结果第 20 天以后偏差大到没法看。从那以后我每跑一个时序模型都强制自己在测试集上滚一遍宁可慢几分钟也不拿一条不靠谱的长预测曲线去汇报——因为滚动误差会告诉你模型到底在哪个步长上开始失真的。希望这些细节对你有帮助。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。