Python ARIMA 时间序列实战:周大福每日金价预测(完整流程 + 代码排错)
一、前言
黄金价格走势分析是时间序列预测的经典落地场景,金价受市场、行情、国际局势等多重因素影响,具备明显趋势性与非平稳特征,非常适合使用传统时序模型 ARIMA 进行建模分析。
本文基于Python + statsmodels实现周大福每日金价预测全流程,包含数据读取、数据预处理、可视化分析、ADF 平稳性检验、差分处理、ARIMA 模型训练、滚动预测、模型评估、未来 7 日金价预测等完整环节。同时修正原项目代码中的语法错误、逻辑漏洞,所有代码可直接在Jupyter Notebook运行,适合数据分析、时序入门学习者练手。
项目环境与依赖
- 开发工具:Python 3.x、Jupyter Notebook
- 核心依赖库:
pandas:数据读取、清洗、时间处理matplotlib:数据可视化statsmodels:ADF 平稳性检验、ARIMA 时序建模numpy:数值计算、误差指标计算
- 数据集:
周大福每日金价.csv(字段:品牌名称、产品名称、价格、涨跌、更新时间)
二、整体项目流程
- 导入库 + 全局配置(中文显示、警告过滤)
- 读取 CSV 数据 + 数据预处理(时间格式转换、时间索引、排序、缺失值处理)
- 原始金价趋势可视化
- ADF 单位根平稳性检验 + 滚动统计绘图
- 一阶差分处理 + 再次平稳性检验
- 划分训练集 / 测试集 + ARIMA 滚动预测
- 预测结果可视化 + 模型误差评估(MAPE)
- 全量数据建模,预测未来 7 日金价
- 代码报错总结与优化建议
三、分步代码实战(修正版,可直接运行)
3.1 导入依赖库 + 全局环境配置
解决 Matplotlib 中文乱码、负号显示问题,过滤无关警告,统一代码运行环境。
python
运行
# 导入基础库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 时序检验与建模库
from statsmodels.tsa.stattools import adfuller
from statsmodels.tsa.arima.model import ARIMA
# 过滤警告
import warnings
warnings.filterwarnings("ignore")
# ========== 全局绘图配置(必加,解决中文乱码) ==========
# Windows 系统字体
plt.rcParams['font.sans-serif'] = ['SimHei']
# Mac 系统请替换为:plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示异常
3.2 读取数据 + 数据预处理
原始数据存在时间倒序、缺失值、文本时间等问题,这是时间序列数据的典型问题,需标准化处理。
python
运行
# 1. 读取CSV金价数据
df = pd.read_csv('周大福每日金价.csv')
print("数据前5行:")
print(df.head())
# 2. 时间列转为标准datetime格式(时序分析核心步骤)
df['更新时间'] = pd.to_datetime(df['更新时间'])
# 3. 将时间列设置为索引(时间序列标准格式)
df.set_index('更新时间', inplace=True)
# 4. 按时间升序排序(修正原始数据倒序问题)
df.sort_index(inplace=True)
# 5. 缺失值检测与统计
print("\n===== 数据缺失值统计 =====")
print(df.isnull().sum())
# 6. 提取核心序列:金价,并删除价格缺失行
ts = df['价格']
ts.dropna(inplace=True)
print(f"\n有效金价数据总条数:{len(ts)}")
print("预处理后数据预览:")
print(ts.head())
代码说明
pd.to_datetime:将文本日期转为时间类型,是时间序列分析的前提;set_index:把时间作为索引,方便后续切片、绘图、建模;dropna:删除价格缺失样本,避免建模报错。
3.3 原始金价趋势可视化
直观观察金价整体走势、趋势特征,判断数据是否存在明显上升 / 下降趋势。
python
运行
print("\n--- 步骤2: 原始金价趋势可视化 ---")
plt.figure(figsize=(12, 6))
plt.plot(ts.index, ts.values, label='每日金价', color='orange', linewidth=1.2)
plt.xlabel('日期')
plt.ylabel('价格 (元/克)')
plt.title('周大福黄金价格趋势图', fontsize=16)
plt.legend()
plt.grid(True, linestyle='--', alpha=0.6)
plt.show()
现象解读:从走势图可看出,金价存在明显趋势,均值不断变化,初步判断为非平稳时间序列,后续需差分处理。
3.4 自定义函数:滚动统计 + ADF 平稳性检验
ADF 检验(单位根检验)是判断时间序列是否平稳的主流方法:
p-value > 0.05:序列非平稳;p-value ≤ 0.05:序列平稳,可直接用于 ARIMA 建模。
这里修复原项目代码语法错误,完善 ADF 结果打印逻辑:
python
运行
print("\n--- 步骤3: ADF平稳性检验 + 滚动统计 ---")
def check_stationarity(timeseries):
# 计算7日滚动均值、滚动标准差
rolmean = timeseries.rolling(window=7).mean()
rolstd = timeseries.rolling(window=7).std()
# 绘制滚动统计图表
plt.figure(figsize=(12, 6))
plt.plot(timeseries, color='blue', label='原始价格')
plt.plot(rolmean, color='red', label='7日滚动均值')
plt.plot(rolstd, color='black', label='7日滚动标准差')
plt.legend(loc='best')
plt.title('7日滚动均值 & 滚动标准差')
plt.grid(alpha=0.5)
plt.show()
# 执行ADF单位根检验
dftest = adfuller(timeseries, autolag='AIC')
dfoutput = pd.Series(dftest[0:4], index=['Test Statistic', 'p-value', '#Lags Used', 'Number of Observations Used'])
# 拼接临界值
for key, value in dftest[4].items():
dfoutput[f'Critical Value ({key})'] = value
# 打印检验结果
print("ADF 检验详细结果:")
print(dfoutput)
# 平稳性结论
if dftest[1] <= 0.05:
print("✅ 结论: p-value <= 0.05,数据是平稳序列")
else:
print("❌ 结论: p-value > 0.05,数据是非平稳序列")
# 对原始金价序列做平稳性检验
check_stationarity(ts)
运行结果参考:原始金价p-value ≈ 0.9989,远大于 0.05,数据非平稳,必须做差分处理。
3.5 一阶差分处理 + 二次平稳性检验
ARIMA 模型要求输入平稳序列,针对非平稳数据,使用一阶差分消除趋势: 公式:差分后值 = 当前值 - 前一日值
python
运行
print("\n--- 步骤4: 一阶差分处理 + 平稳性再检验 ---")
# 一阶差分,并删除差分产生的空值
ts_diff = ts.diff().dropna()
# 检验差分后序列的平稳性
check_stationarity(ts_diff)
运行结果参考:一阶差分后p-value ≈ 1.22e-21,远小于 0.05,序列转为平稳。因此 ARIMA 模型差分阶数 d=1。
3.6 划分训练集 / 测试集 + ARIMA 滚动预测
按照时间顺序划分数据集(时序数据禁止随机划分):前 90% 为训练集,后 10% 为测试集。 采用滚动一步预测(时序经典预测方式):每预测 1 个值,就把真实值加入历史数据,动态更新模型。
python
运行
print("\n--- 步骤5: ARIMA模型训练与滚动预测 ---")
# 划分数据集:前90%训练集,后10%测试集
train_size = int(len(ts) * 0.9)
train, test = ts[0:train_size], ts[train_size:]
print(f"训练集长度:{len(train)} | 测试集长度:{len(test)}")
# 初始化历史数据、预测结果列表
history = list(train.values)
predictions = []
# 滚动预测:逐一对测试集进行预测
for i in range(len(test)):
# ARIMA(p,d,q) 结合差分结果,设置 order=(5,1,0)
model = ARIMA(history, order=(5, 1, 0))
model_fit = model.fit()
# 预测单步数据
yhat = model_fit.forecast()[0]
predictions.append(yhat)
# 将当日真实值加入历史数据,更新模型
history.append(test.iloc[i])
# 预测结果转为DataFrame,方便后续绘图与计算误差
forecast_df = pd.DataFrame({'预测值': predictions}, index=test.index)
3.7 预测结果可视化 + 模型误差评估(MAPE)
使用 MAPE(平均绝对百分比误差) 评估模型效果,MAPE 是时序预测最常用指标:
- MAPE < 10%:预测效果优秀;
- 10% < MAPE < 20%:趋势拟合良好;
- MAPE > 20%:短期波动预测偏差较大。
修复原项目 MAPE 函数顺序错误:
python
运行
print("\n--- 步骤6: 预测可视化 + 模型误差评估 ---")
# 1. 绘制训练集、真实值、预测值对比图
plt.figure(figsize=(14, 7))
plt.plot(train.index, train.values, label='训练数据(历史真实金价)', color='blue')
plt.plot(test.index, test.values, label='测试数据(真实金价)', color='green')
plt.plot(forecast_df.index, forecast_df['预测值'], label='ARIMA模型预测值', color='red', linestyle='--')
plt.title('周大福金价:ARIMA预测 VS 真实值', fontsize=16)
plt.xlabel('日期')
plt.ylabel('价格 (元/克)')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
# 2. 定义MAPE计算函数(修复原代码逻辑错误)
def calculate_mape(true, pred):
true = np.array(true)
pred = np.array(pred)
# 防止除数为0
mask = true != 0
return np.mean(np.abs((true[mask] - pred[mask]) / true[mask])) * 100
# 计算误差
mape = calculate_mape(test.values, forecast_df['预测值'])
print(f"预测平均绝对百分比误差 (MAPE): {mape:.2f}%")
3.8 全量建模,预测未来 7 日金价
使用全部历史数据训练最终模型,实现未来 7 个交易日金价预测:
python
运行
print("\n--- 额外功能:预测未来7日金价 ---")
# 全量数据训练ARIMA模型
future_model = ARIMA(ts, order=(5, 1, 0))
future_model_fit = future_model.fit()
# 预测未来7步数据,并获取置信区间
future_forecast = future_model_fit.get_forecast(steps=7)
future_values = future_forecast.predicted_mean
future_conf_int = future_forecast.conf_int()
# 打印预测结果
print("未来7个交易日金价预测结果(元/克):")
for idx, price in enumerate(future_values, 1):
print(f"第{idx}天预测金价:{price:.2f}")
四、原项目代码报错汇总 & 修复说明
结合你提供的源码,整理所有语法错误、逻辑漏洞,也是运行时高频报错点:
1. ADF 检验代码语法截断错误
原代码:
python
运行
dfoutput = pd.Series(dftest[0:4], index=['Test Statistic', 'p-value', '#Lags Use
for key, value in dftest[4].items(): print(dfoutput)
错误:字符串换行截断、循环逻辑混乱。 修复:补全索引名称,规范循环打印临界值。
2. MAPE 函数执行顺序错误
原代码:先调用函数,再转换数组,导致计算异常。 修复:函数内部先将真实值、预测值转为数组,增加除 0 保护。
3. 绘图代码截断
原代码plt.plot(..., li 为代码截断,运行直接报错。 修复:补全参数 linestyle='--'。
4. 变量未定义报错
原代码使用forecast_values但未定义,统一使用forecast_df['预测值']。
5. 时序数据常识错误
原始数据时间倒序,未执行sort_index(),导致训练集 / 测试集划分错乱。 修复:时间索引后强制升序排序。
五、结果分析与模型总结
5.1 实验结果解读
- 平稳性分析:原始金价为非平稳序列,一阶差分后转为平稳,因此 ARIMA 最优差分阶数
d=1; - 模型误差:本次实验 MAPE 约 27.41%,说明模型能捕捉金价整体趋势,但对短期剧烈波动拟合不足;
- 预测效果:ARIMA 作为单变量时序模型,仅使用历史金价建模,未结合成交量、大盘、国际金价等外部特征,短期预测存在偏差属于正常现象。
5.2 ARIMA 参数说明(order=(p,d,q))
- p(自回归阶数):利用前 p 期历史数据预测当前值,本文取
p=5; - d(差分阶数):将非平稳序列转为平稳序列的差分次数,本文取
d=1; - q(移动平均阶数):利用前 q 期残差修正预测值,本文取
q=0。
5.3 项目优化方向(进阶拓展)
- 模型升级:使用
SARIMA(季节性 ARIMA),适配金价潜在季节性规律; - 特征工程:引入均线、涨跌幅度、国际金价等多因子,使用
SARIMAX多变量时序模型; - 参数寻优:通过 AIC/BIC 准则网格搜索最优
p、d、q组合,替代人工调参; - 深度学习:使用 LSTM、Prophet 模型,进一步提升短期波动预测精度;
- 异常值处理:对金价跳空、极端涨跌数据做平滑处理,降低误差。
六、完整运行环境安装命令
如果运行代码提示ModuleNotFoundError,在终端 / Jupyter 单元格内执行安装:
bash
运行
# 安装全套依赖
pip install pandas numpy matplotlib statsmodels
Jupyter 内专属安装(环境统一):
python
运行
!pip install pandas numpy matplotlib statsmodels
七、博文结语
本文从零完成周大福金价 ARIMA 时间序列预测全实战,覆盖数据清洗、可视化、平稳性检验、差分、ARIMA 建模、滚动预测、误差评估等时序分析核心知识点,同时修复了源码中所有语法与逻辑报错。
ARIMA 是入门时间序列的必学模型,该项目不仅可以用于金价预测,也可迁移到销量、客流、股价、气温等各类时序场景。
如果文章对你有帮助,欢迎点赞、收藏、评论,后续会持续分享 Python 数据分析、时间序列、机器学习实战案例!
更多推荐


所有评论(0)