ARTICLE DETAIL

资讯详情

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

ARIMA模型预测上证指数:从数据获取到LSTM对照的毕业设计实战

ARIMA模型预测上证指数:从数据获取到LSTM对照的毕业设计实战 简介这份毕业设计报告以doc文档形式呈现面向统计学、金融工程及数据分析方向的本科生与研究者聚焦时间序列预测这一典型课题。报告以EViews7为工具围绕上证综合指数展开实证分析系统讲解ARIMA模型的理论基础涵盖移动平均过程、自回归过程与自回归移动平均过程并重点阐述差分运算在非平稳序列平稳化中的作用说明差分平稳序列的判定与建模思路。在模型建立环节报告讨论了参数估计方法包括最大似然估计与贝叶斯估计并对模型进行适应性检验与残差白噪声检验最后给出对上证指数的初步预测结果及模型优缺点评述。资源包内含1个doc文件约644KB结构完整包含中英文摘要、目录、绪论、理论基础、模型建立与检验等章节可作为毕业设计写作范本与ARIMA实战参考。目前已有181人学习下载适合需要掌握时间序列建模流程、撰写相关论文的读者借鉴。1. 从一份毕业设计报告说起ARIMA 对上证指数到底能预测到什么程度很多人第一次接触时间序列预测都是从一份毕业设计报告开始的。标题写着「基于 ARIMA 模型对上证指数的预测」看起来像是一个标准的金融数据分析课题但真正动手做的时候问题一个接一个冒出来数据从哪来、怎么判断平稳、p d q 三个参数怎么定、EViews7 里点哪个按钮、预测出来的曲线为什么像一条直线。这些问题不解决报告就只能停在「模型介绍」那一章后面全是空话。ARIMA 模型全称自回归积分滑动平均模型是时间序列预测里最经典也最容易被低估的工具。它不像 LSTM 那样需要大量数据和算力也不像简单的移动平均那样只能看趋势。对于上证指数这种日频、有趋势、有波动聚集特征的金融时间序列ARIMA 能给出一个统计上可解释的基准线。注意我说的是基准线不是发财工具。毕业设计里用它核心价值在于把「数据获取 → 平稳性检验 → 模型定阶 → 参数估计 → 残差诊断 → 预测评估」这条链路完整走一遍而不是追求预测精度有多高。这份报告适合谁如果你是统计学、金融学、数据科学方向的学生正在找一个能落地、有数据、有方法论的毕业设计题目ARIMA 对上证指数是一个稳妥的选择。如果你是从业者想快速给一个时间序列问题搭 baselineARIMA 同样值得先跑一遍。下面我按实际做项目的顺序把每个环节拆开讲清楚包括 EViews7 的操作路径和 Python 的替代方案以及我踩过的那些坑。2. 数据获取与预处理上证指数日线数据怎么拿、怎么清洗2.1 数据来源与字段选择做上证指数预测第一步是拿到可靠的日线数据。常见做法有三种一是从 Yahoo Finance 或新浪财经接口抓取二是用 Tushare 这类开源财经数据接口三是直接从 EViews7 自带的数据库或学校提供的 Wind 终端导出。毕业设计里最稳妥的是用 Tushare免费额度够用字段清晰导出 CSV 后可以直接导入 EViews7 或 Python。需要关注的字段包括交易日期、开盘价、最高价、最低价、收盘价、成交量。ARIMA 建模通常用收盘价序列因为收盘价是当日多空博弈的最终结果连续性和代表性最好。如果你用最高价或最低价序列的噪声会更大平稳性检验更容易不通过。import tushare as ts import pandas as pd # 初始化 Tushare需要替换成你自己的 token ts.set_token(your_token_here) pro ts.pro_api() # 拉取上证指数日线数据000001.SH 是上证指数代码 df pro.index_daily(ts_code000001.SH, start_date20150101, end_date20241231) # 按日期升序排列ARIMA 对顺序敏感 df df.sort_values(trade_date).reset_index(dropTrue) # 只保留日期和收盘价重命名列方便后续处理 df df[[trade_date, close]] df.columns [date, close] # 将日期设为索引并转换为 datetime 类型 df[date] pd.to_datetime(df[date], format%Y%m%d) df.set_index(date, inplaceTrue) # 导出为 CSV方便导入 EViews7 df.to_csv(sh_index_close.csv, encodingutf-8-sig) print(df.head()) print(f数据量{len(df)} 条)这段代码的逻辑很直接拉数据、排序、取收盘价、转日期格式、导出。参数上要注意start_date和end_date的格式是YYYYMMDDindex_daily接口返回的trade_date是字符串必须转成 datetime 才能被 EViews7 或 statsmodels 正确识别。encodingutf-8-sig是为了避免中文 Windows 环境下 Excel 打开 CSV 乱码。2.2 缺失值处理与对数变换上证指数在交易日基本不会缺失但如果你拉的是个股数据停牌日会出现空值。ARIMA 要求序列等间隔且无缺失常见做法是前向填充或线性插值。前向填充适合缺失量少的情况线性插值适合缺失量稍多但趋势连续的场景。另一个关键预处理是对数变换。金融价格序列的波动幅度往往与价格水平相关取对数后可以一定程度上稳定方差。更重要的是对数差分后的序列近似收益率经济含义明确。我一般会先对收盘价取自然对数再做一阶差分然后检验平稳性。import numpy as np # 前向填充缺失值再检查是否还有空值 df[close] df[close].ffill() print(f缺失值数量{df[close].isna().sum()}) # 对数变换 df[log_close] np.log(df[close]) # 一阶差分得到对数收益率 df[log_return] df[log_close].diff() # 去掉差分产生的第一个空值 df.dropna(inplaceTrue) print(df[[close, log_close, log_return]].describe())对数变换后序列的绝对数值变小但趋势和波动结构保留。一阶差分去掉趋势让序列围绕均值波动。注意差分阶数 d 不是随便定的后面会用 ADF 检验来确认。这里先做一阶差分是因为上证指数收盘价几乎肯定是非平稳的而一阶差分后大概率平稳。提示如果你在 EViews7 里操作导入 CSV 后先在工作文件里生成新序列命令是genr log_close log(close)再genr log_return d(log_close)。EViews7 的d()函数就是一阶差分。3. 平稳性检验与模型定阶ADF、ACF、PACF 到底怎么看3.1 ADF 检验判断 d 取多少ARIMA 里的 I 就是差分阶数 d。d 取 0 表示原序列平稳取 1 表示一阶差分后平稳取 2 表示二阶差分后平稳。金融价格序列通常 d1极少数情况下 d2。判断依据是单位根检验最常用的是 ADF 检验。ADF 检验的原假设是序列存在单位根即非平稳。如果检验统计量小于临界值或者 p 值小于 0.05就拒绝原假设认为序列平稳。实际操作中我会对原序列、一阶差分序列、二阶差分序列分别做 ADF看哪个先平稳。from statsmodels.tsa.stattools import adfuller def adf_test(series, name): result adfuller(series, autolagAIC) print(f序列{name}) print(fADF 统计量{result[0]:.4f}) print(fp 值{result[1]:.4f}) print(f临界值{result[4]}) print(---) # 对原序列、一阶差分、二阶差分分别检验 adf_test(df[log_close], log_close 原序列) adf_test(df[log_return], log_return 一阶差分) adf_test(df[log_return].diff().dropna(), 二阶差分)参数autolagAIC表示自动选择滞后阶数以 AIC 最小为准。如果你在 EViews7 里做路径是打开序列 → View → Unit Root Test → 选择 ADF → 看 p 值。EViews7 默认的滞后阶数选择也是 AIC结果和 Python 基本一致。3.2 ACF 与 PACF 图定 p 和 q 的视觉依据确定 d 之后下一步是定 p 和 q。p 是自回归项数q 是滑动平均项数。经典方法是看自相关函数和偏自相关函数的截尾/拖尾特征ACF 截尾、PACF 拖尾则 q 有值PACF 截尾、ACF 拖尾则 p 有值。但实际金融数据里ACF 和 PACF 往往都拖尾这时候不能硬看图要结合 AIC/BIC 网格搜索。import matplotlib.pyplot as plt from statsmodels.graphics.tsaplots import plot_acf, plot_pacf fig, axes plt.subplots(2, 1, figsize(12, 8)) # 画 ACFlags 取 30 够看短期相关性 plot_acf(df[log_return], lags30, axaxes[0]) axes[0].set_title(ACF of Log Return) # 画 PACF plot_pacf(df[log_return], lags30, axaxes[1]) axes[1].set_title(PACF of Log Return) plt.tight_layout() plt.savefig(acf_pacf.png, dpi150) plt.show()看图的经验是如果 ACF 在某个滞后阶数后突然落到置信区间内就是截尾如果缓慢衰减就是拖尾。上证指数对数收益率通常表现为 ACF 和 PACF 都在低阶有显著值然后快速衰减说明 p 和 q 都不会太大一般在 0 到 3 之间。注意不要只靠 ACF/PACF 定阶。我见过太多报告在这里直接写「ACF 一阶截尾所以 q1」结果模型残差检验不通过。正确做法是把 ACF/PACF 当作候选范围再用 AIC/BIC 选最优。3.3 网格搜索定阶AIC 和 BIC 怎么选AIC 和 BIC 都是模型选择准则数值越小越好。AIC 偏向复杂模型BIC 偏向简单模型。毕业设计里我一般两个都看优先选 BIC 较小的如果 AIC 和 BIC 结论冲突选残差诊断更干净的那个。import warnings from statsmodels.tsa.arima.model import ARIMA warnings.filterwarnings(ignore) # 候选 p 和 q 范围d 已经确定为 1 p_range range(0, 4) q_range range(0, 4) results [] for p in p_range: for q in q_range: try: model ARIMA(df[log_close], order(p, 1, q)) fitted model.fit() results.append({ p: p, d: 1, q: q, AIC: fitted.aic, BIC: fitted.bic, LLF: fitted.llf }) except Exception as e: continue result_df pd.DataFrame(results).sort_values(BIC) print(result_df.head(10))这段代码遍历 p 和 q 从 0 到 3 的所有组合d 固定为 1拟合 ARIMA 并记录 AIC、BIC、对数似然。参数范围为什么取 0 到 3因为金融收益率序列的记忆通常很短超过 3 阶的模型容易过拟合而且残差诊断往往不通过。如果你发现最优阶数落在边界上比如 p3 或 q3可以适当扩大范围到 5 再跑一次。EViews7 里做网格搜索稍微麻烦一些需要手动逐个设定equation的 ARMA 项或者用auto.arima的 EViews 插件。如果学校机房只装了 EViews7建议先在 Python 里定好阶再到 EViews7 里复现结果这样效率最高。4. 模型拟合与残差诊断EViews7 和 Python 双路径实操4.1 EViews7 操作路径从导入数据到输出方程EViews7 是很多高校毕业设计的指定软件操作界面老派但功能完整。下面是从零开始的完整路径。第一步导入数据。File → Open → Foreign Data as Workfile → 选择 CSV 文件 → 确认日期列和数值列。导入后工作文件里会出现close序列。第二步生成对数序列和差分序列。在命令窗口输入genr log_close log(close) genr log_return d(log_close)第三步做 ADF 检验。双击log_return→ View → Unit Root Test → 选择 ADF → 滞后阶数选 AIC → 看 p 值。第四步定阶。Quick → Estimate Equation → 输入log_close c ar(1) ar(2) ma(1) ma(2)→ 方法选 LS → 看系数显著性和 AIC/BIC。逐步增减 AR 和 MA 项直到找到最优。第五步残差诊断。在方程窗口 → View → Residual Diagnostics → Correlogram-Q-statistics → 看残差 ACF 是否在置信区间内。再做 White 检验看异方差。第六步预测。在方程窗口 → Forecast → 设定预测区间 → 输出预测序列。EViews7 的输出结果里重点看三块系数估计值和 p 值、AIC/BIC、残差 Q 统计量。系数不显著就删掉对应项Q 统计量 p 值小于 0.05 说明残差还有自相关模型没抓干净。4.2 Python statsmodels 拟合与诊断Python 路径更灵活适合做批量实验和自定义诊断。下面是一个完整的拟合和诊断流程。from statsmodels.stats.diagnostic import acorr_ljungbox import scipy.stats as stats # 假设最优阶数为 ARIMA(1,1,1)根据上一步网格搜索结果替换 best_order (1, 1, 1) model ARIMA(df[log_close], orderbest_order) fitted model.fit() # 打印模型摘要 print(fitted.summary()) # 残差诊断 residuals fitted.resid # Ljung-Box 检验检查残差是否白噪声 lb_test acorr_ljungbox(residuals, lags[10, 20, 30], return_dfTrue) print(lb_test) # 残差正态性检验 stat, p_value stats.normaltest(residuals) print(f正态性检验 p 值{p_value:.4f}) # 残差图 fig, axes plt.subplots(2, 2, figsize(14, 10)) axes[0, 0].plot(residuals) axes[0, 0].set_title(Residuals) axes[0, 1].hist(residuals, bins50) axes[0, 1].set_title(Residual Histogram) plot_acf(residuals, lags30, axaxes[1, 0]) axes[1, 0].set_title(Residual ACF) stats.probplot(residuals, distnorm, plotaxes[1, 1]) axes[1, 1].set_title(Q-Q Plot) plt.tight_layout() plt.savefig(residual_diagnostics.png, dpi150) plt.show()fitted.summary()会输出系数、标准误、z 统计量、p 值、AIC、BIC。重点看 AR 和 MA 项的 p 值是否小于 0.05不显著的项考虑删掉。Ljung-Box 检验的 p 值如果大于 0.05说明残差没有显著自相关模型合格。正态性检验在金融数据里经常不通过因为收益率有尖峰厚尾这不影响预测但要在报告里说明。提示EViews7 和 Python 的 AIC/BIC 计算方式略有差异同一组阶数下数值可能不同但排序基本一致。毕业设计里用哪个软件就以哪个为准不要混着报。4.3 预测与评估滚动预测和静态预测的区别ARIMA 预测分两种静态预测和滚动预测。静态预测用真实历史值做每一步的输入适合评估模型拟合能力滚动预测只用预测起点之前的数据更接近实盘场景。毕业设计里建议两种都做对比 RMSE 和 MAE。from sklearn.metrics import mean_squared_error, mean_absolute_error # 划分训练集和测试集最后 100 个交易日作为测试 train df[log_close][:-100] test df[log_close][-100:] # 用训练集拟合 model_train ARIMA(train, orderbest_order) fitted_train model_train.fit() # 静态预测用测试集的真实值逐步预测 static_pred fitted_train.predict(startlen(train), endlen(train)len(test)-1) # 滚动预测每次只用一个新数据更新模型 rolling_pred [] history list(train) for t in range(len(test)): model_roll ARIMA(history, orderbest_order) fitted_roll model_roll.fit() yhat fitted_roll.forecast()[0] rolling_pred.append(yhat) history.append(test.iloc[t]) # 评估 rmse_static np.sqrt(mean_squared_error(test, static_pred)) rmse_rolling np.sqrt(mean_squared_error(test, rolling_pred)) print(f静态预测 RMSE{rmse_static:.6f}) print(f滚动预测 RMSE{rmse_rolling:.6f})静态预测的 RMSE 通常更小因为它用了真实值。滚动预测的 RMSE 更大但更能反映模型在未知数据上的表现。注意滚动预测计算量大100 个测试点就要拟合 100 次模型如果数据量大可以改用apply或forecast的refitFalse选项。5. 避坑与排查ARIMA 做上证指数预测最容易翻车的 5 个地方5.1 现象ADF 检验 p 值忽大忽小d 定不下来原因ADF 检验对滞后阶数和趋势项设定敏感。如果你在 EViews7 里选了「Trend and Intercept」但数据其实没有趋势p 值会偏大反之如果数据有趋势但只选「None」p 值也会失真。解决先画时序图看有没有明显趋势。上证指数长期有上涨趋势但短期波动大。我一般先选「Intercept」做检验如果 p 值在 0.05 附近徘徊再试「Trend and Intercept」。最终以时序图和经济含义为准不要只盯 p 值。5.2 现象模型拟合很好但预测曲线是一条直线原因ARIMA 的长期预测会收敛到均值。如果你用 d0 且没有强自相关预测很快变平。即使 d1多步预测的方差也会越来越大点估计趋近于常数。解决这是 ARIMA 的固有特性不是 bug。毕业设计里应该把预测区间限制在短期比如 5 到 20 个交易日并报告置信区间。不要拿 ARIMA 做半年以上的预测没有意义。5.3 现象残差 Ljung-Box 检验 p 值小于 0.05原因模型没有抓干净自相关可能是 p 或 q 阶数不够也可能是数据有季节性虽然上证指数日线季节性不明显还可能是异方差导致检验失效。解决先增加 p 和 q 的阶数重新网格搜索。如果还是不行考虑对残差做 ARCH 检验如果存在 ARCH 效应说明需要用 GARCH 类模型ARIMA 只做均值方程。毕业设计里如果遇到这种情况可以在报告里说明并建议后续用 ARIMA-GARCH 组合。5.4 现象EViews7 导入 CSV 后日期错乱原因EViews7 对日期格式的识别比较死板YYYY-MM-DD和YYYYMMDD都可能出问题尤其是中文系统下。解决导入前把 CSV 的日期列统一改成YYYYMMDD格式不带分隔符。如果还是错乱在 EViews7 里手动设定工作文件的频率和起始日期再把数据粘贴进去。我一般会先在 Excel 里把日期列格式化成文本再导入。5.5 现象Python statsmodels 的 ARIMA 和 EViews7 结果对不上原因两个软件的参数估计方法不同。statsmodels 默认用最大似然EViews7 默认用最小二乘。另外常数项的设定也可能不同statsmodels 的trend参数控制是否包含常数EViews7 的c是显式加入的。解决在 statsmodels 里用trendc显式加入常数项和 EViews7 的c对应。如果还有差异检查差分阶数是否一致以及是否对同一段数据建模。毕业设计里选定一个软件为主另一个做交叉验证即可不必强求数值完全一致。6. 进阶技巧用 LSTM 做对照实验让毕业设计更有说服力ARIMA 做完了报告里如果只放一个模型答辩时容易被问「为什么不用机器学习」。我的习惯是加一个 LSTM 作为对照不用做太深只要能跑通并给出 RMSE 对比就能显著提升报告的技术厚度。注意LSTM 不是替代 ARIMA而是提供另一个视角。import torch import torch.nn as nn from torch.utils.data import DataLoader, TensorDataset # 构造滑动窗口数据集用过去 20 天预测下一天 def create_sequences(data, seq_len): xs, ys [], [] for i in range(len(data) - seq_len): xs.append(data[i:iseq_len]) ys.append(data[iseq_len]) return np.array(xs), np.array(ys) seq_len 20 data df[log_return].values X, y create_sequences(data, seq_len) # 划分训练集和测试集 split int(len(X) * 0.8) X_train, X_test X[:split], X[split:] y_train, y_test y[:split], y[split:] # 转成 tensor X_train_t torch.FloatTensor(X_train).unsqueeze(-1) y_train_t torch.FloatTensor(y_train).unsqueeze(-1) X_test_t torch.FloatTensor(X_test).unsqueeze(-1) y_test_t torch.FloatTensor(y_test).unsqueeze(-1) # 定义 LSTM 模型 class LSTMModel(nn.Module): def __init__(self, input_size1, hidden_size32, output_size1): super().__init__() self.lstm nn.LSTM(input_size, hidden_size, batch_firstTrue) self.fc nn.Linear(hidden_size, output_size) def forward(self, x): out, _ self.lstm(x) out self.fc(out[:, -1, :]) return out model_lstm LSTMModel() criterion nn.MSELoss() optimizer torch.optim.Adam(model_lstm.parameters(), lr0.001) # 训练 for epoch in range(50): model_lstm.train() optimizer.zero_grad() output model_lstm(X_train_t) loss criterion(output, y_train_t) loss.backward() optimizer.step() if (epoch1) % 10 0: print(fEpoch {epoch1}, Loss: {loss.item():.6f}) # 预测 model_lstm.eval() with torch.no_grad(): pred_lstm model_lstm(X_test_t).numpy().flatten() rmse_lstm np.sqrt(mean_squared_error(y_test, pred_lstm)) print(fLSTM RMSE{rmse_lstm:.6f}) print(fARIMA RMSE{rmse_rolling:.6f})这段代码的关键参数seq_len20表示用过去 20 个交易日预测下一天hidden_size32是 LSTM 隐藏层维度lr0.001是学习率。训练 50 轮通常够用如果 loss 不下降可以调大 hidden_size 或增加轮数。注意LSTM 对数据量和超参数敏感同样的数据跑两次结果可能不同这是正常现象。报告里要说明随机种子和训练轮数。对比结果时不要只看 RMSE。ARIMA 的系数有统计显著性可以解释LSTM 是黑匣子预测可能更好但说不清为什么。毕业设计里把两者并列讨论各自的适用场景比单押一个模型更有深度。我一般会在报告最后写一句ARIMA 适合捕捉线性自相关LSTM 适合捕捉非线性模式实际应用中可以用 ARIMA 残差喂给 LSTM 做混合模型。这个思路留给后续研究答辩时也是一个加分点。做毕业设计最深的体会是模型跑通只是开始把每一步的为什么写清楚才是报告的核心。我见过太多人把 ARIMA 的 p d q 调出来就结束结果答辩被问「为什么 d 取 1 不取 2」就卡住了。希望你在动手之前先把平稳性检验和定阶的逻辑吃透后面写报告会顺很多。希望帮到你。本文还有配套的精品资源点击获取
返回列表