黄金期货预测实战:多元线性回归与多层感知机神经网络对比

发布时间:2026/10/30 0:47:24
黄金期货预测实战:多元线性回归与多层感知机神经网络对比 简介这份资源面向量化金融方向的学生、研究者与投资分析人员围绕中国黄金期货价格预测这一具体场景系统对比多元线性回归与多层感知机MLP神经网络的预测准确性。项目先以多元线性回归刻画价格与影响因子间的线性关系再引入MLP捕捉非线性模式并配合时间序列平稳性检验与格兰杰因果检验筛选有效变量帮助读者理解两类模型在不同情形下的优势与局限为模型选择提供实证参考。压缩包共13个文件约225KB包含2个Python脚本分别对应线性拟合预测与MLP精度分析、8张png结果图、1份docx附赠资源、1份txt说明及README.md覆盖从数据处理、建模到结果可视化的完整流程。目前已有79人学习下载适合希望以小型案例入门金融时间序列预测、快速复现并对比线性与神经网络方法的读者。1. 黄金期货预测的两种路线线性回归与多层感知机到底差在哪黄金期货价格预测这件事做的人多做对的少。我见过太多人拿一段收盘价序列直接丢进模型跑出一个 R² 0.98 的结果就以为成了结果一到实盘就翻车。问题往往不在模型本身而在于没有先搞清楚这段价格序列到底是不是平稳的特征之间有没有因果关系以及线性模型和神经网络各自适合捕捉什么形态的信号。这个项目标题里同时出现了多元线性回归和多层感知机神经网络还带了时间序列分析、平稳性检验、格兰杰因果检验这几个关键词说明作者想做的不是简单跑个模型对比而是走一条完整的量化研究链路先检验数据性质再筛选因果特征最后用两类模型做预测准确性的横向对比。适合谁看如果你手上有黄金期货的日频或分钟频数据想搞清楚线性模型和 MLP 在什么条件下谁更准、为什么准以及整条链路里哪些步骤不能省这篇就是写给你的。2. 数据准备与平稳性检验别拿非平稳序列直接喂模型2.1 黄金期货价格序列的获取与清洗做黄金期货预测数据源常见的有上海期货交易所的黄金主力连续合约、伦敦金现货报价以及各类数据终端导出的日频 OHLCV。我一般会先把数据整理成一张宽表字段包括日期、开盘、最高、最低、收盘、成交量、持仓量然后做三件事对齐交易日历、处理缺失值、检查异常跳变。import pandas as pd import numpy as np # 读取黄金期货日频数据假设已有 CSV 文件 df pd.read_csv(gold_futures_daily.csv, parse_dates[date]) df df.sort_values(date).reset_index(dropTrue) # 对齐交易日历剔除周末与明显非交易日的空行 df df[df[volume] 0].copy() # 缺失值处理价格类用前向填充成交量类用中位数填充 price_cols [open, high, low, close] df[price_cols] df[price_cols].ffill() df[volume] df[volume].fillna(df[volume].median()) # 检查异常跳变单日涨跌幅超过 8% 的标记出来人工确认 df[pct_change] df[close].pct_change() outliers df[df[pct_change].abs() 0.08] print(f异常跳变记录数{len(outliers)})这段代码的逻辑是先保证时间顺序正确再处理缺失和异常。参数上volume 0这个过滤条件是为了剔除停牌或数据缺失导致的空行前向填充只用于价格列因为价格具有连续性而成交量用中位数填充是为了避免极端值拉偏分布。异常跳变阈值设 8% 是黄金期货日频的常见经验值超过这个幅度要么是真实极端行情要么是数据错误必须人工确认。2.2 平稳性检验ADF 与差分阶数的选择时间序列分析里平稳性检验是绕不过去的一步。黄金期货收盘价几乎肯定是非平稳的直接拿去做回归或喂神经网络模型学到的只是趋势不是规律。常见做法是先做 ADF 检验如果不通过就做一阶差分再检验直到通过为止。from statsmodels.tsa.stattools import adfuller def adf_test(series, name): result adfuller(series.dropna(), autolagAIC) print(f{name} ADF 统计量{result[0]:.4f}p 值{result[1]:.4f}) for key, value in result[4].items(): print(f 临界值 {key}{value:.4f}) return result[1] # 对收盘价做 ADF 检验 p_close adf_test(df[close], 收盘价) # 一阶差分 df[close_diff] df[close].diff() p_diff adf_test(df[close_diff], 收盘价一阶差分)ADF 检验的原假设是序列存在单位根即非平稳。p 值小于 0.05 才能拒绝原假设认为序列平稳。实际跑下来收盘价的 p 值经常在 0.5 以上一阶差分后通常能降到 0.01 以下。如果一阶差分还不平稳就要考虑二阶差分或对数差分但阶数越高信息损失越大我一般最多做到一阶差分再不行就换特征构造方式。提示差分后的序列长度会少一个样本做后续建模时要注意对齐索引别让特征和标签错位。2.3 格兰杰因果检验哪些变量真的对预测有用格兰杰因果检验回答的是一个很实际的问题变量 X 的过去值能不能帮助预测变量 Y 的当前值。在黄金期货场景里我通常会检验美元指数、原油价格、美债收益率、VIX 等外生变量对黄金收盘价的因果性。检验结果显著的变量才值得放进特征集不显著的直接剔除避免维度灾难。from statsmodels.tsa.stattools import grangercausalitytests def granger_test(data, cause_col, effect_col, max_lag5): test_data data[[effect_col, cause_col]].dropna() results grangercausalitytests(test_data, maxlagmax_lag, verboseFalse) for lag in range(1, max_lag 1): p_value results[lag][0][ssr_ftest][1] print(f滞后 {lag} 期p 值 {p_value:.4f}) # 假设 df 中已有美元指数列 dxy granger_test(df, dxy, close_diff, max_lag5)这段代码对每个滞后阶数做 F 检验输出 p 值。我一般看滞后 1 到 5 期里有没有至少一个 p 值小于 0.05有就保留该变量。注意格兰杰因果检验要求序列平稳所以要用差分后的数据做否则结果不可信。另外检验的是统计意义上的因果不是物理因果别过度解读。3. 多元线性回归建模基线模型怎么搭才靠谱3.1 特征工程与滞后阶数的确定线性回归做时间序列预测核心是把时间序列问题转化成监督学习问题。具体做法是构造滞后特征用 t-1、t-2、…、t-k 时刻的值预测 t 时刻的值。滞后阶数 k 怎么定我一般先看自相关函数和偏自相关函数再结合格兰杰检验的结果。def create_lag_features(series, n_lags): df_lag pd.DataFrame({y: series}) for i in range(1, n_lags 1): df_lag[flag_{i}] series.shift(i) return df_lag.dropna() # 用差分后的收盘价构造滞后特征 lag_df create_lag_features(df[close_diff], n_lags5) print(lag_df.head()) print(f样本数{len(lag_df)})参数说明n_lags5表示用前 5 天的差分值预测当天。这个值不是拍脑袋定的可以先跑一遍不同滞后阶数的回归看调整后 R² 和 AIC 的变化。我一般会试 3、5、10、20 这几个档位选验证集误差最小的。注意dropna()会损失前 k 个样本样本量小的时候要权衡。3.2 线性回归的训练与系数解读特征构造好之后线性回归的训练本身很简单关键是解读系数和做残差诊断。from sklearn.linear_model import LinearRegression from sklearn.model_selection import train_test_split from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score X lag_df.drop(columns[y]) y lag_df[y] # 按时间顺序切分不能随机打乱 split_idx int(len(X) * 0.8) X_train, X_test X.iloc[:split_idx], X.iloc[split_idx:] y_train, y_test y.iloc[:split_idx], y.iloc[split_idx:] model_lr LinearRegression() model_lr.fit(X_train, y_train) y_pred_lr model_lr.predict(X_test) print(系数, dict(zip(X.columns, model_lr.coef_.round(4)))) print(截距, round(model_lr.intercept_, 4)) print(fMSE{mean_squared_error(y_test, y_pred_lr):.6f}) print(fMAE{mean_absolute_error(y_test, y_pred_lr):.6f}) print(fR²{r2_score(y_test, y_pred_lr):.4f})系数解读上如果 lag_1 的系数接近 1 且显著说明差分序列有一阶自相关如果多个滞后项系数都很小说明线性模型可能抓不到什么规律。R² 在差分序列上通常不会很高0.05 到 0.2 都算正常别拿原始价格的 R² 来比。残差诊断要看残差是否白噪声如果还有自相关说明滞后阶数不够或者模型形式不对。3.3 线性模型的边界在哪里线性回归的优势是可解释性强、训练快、不容易过拟合。但它的边界也很明显它只能捕捉线性关系对非线性交互、 regime switching、波动率聚集这些黄金期货常见的形态无能为力。我一般把线性回归当基线如果 MLP 连这个基线都跑不过那说明网络结构或特征有问题得回去查。4. 多层感知机建模网络结构、训练与调参4.1 MLP 的网络结构与激活函数选择多层感知机做时间序列预测输入层维度等于特征数输出层一个神经元做回归。隐藏层怎么设常见做法是两到三层每层 32 到 128 个神经元。激活函数我一般用 ReLU输出层不加激活函数。import torch import torch.nn as nn class GoldMLP(nn.Module): def __init__(self, input_dim, hidden_dims[64, 32]): super().__init__() layers [] prev_dim input_dim for h_dim in hidden_dims: layers.append(nn.Linear(prev_dim, h_dim)) layers.append(nn.ReLU()) layers.append(nn.Dropout(0.2)) prev_dim h_dim layers.append(nn.Linear(prev_dim, 1)) self.net nn.Sequential(*layers) def forward(self, x): return self.net(x) input_dim X_train.shape[1] model_mlp GoldMLP(input_diminput_dim, hidden_dims[64, 32]) print(model_mlp)结构说明两层隐藏层第一层 64 个神经元第二层 32 个每层后面接 ReLU 和 Dropout(0.2)。Dropout 是为了防止过拟合时间序列样本量通常不大这个参数很关键。输入维度由特征数决定输出维度是 1因为做的是回归预测。4.2 训练循环与早停策略MLP 训练最容易翻车的地方是过拟合和训练不稳定。我一般用 Adam 优化器学习率设 1e-3配合早停。from torch.utils.data import DataLoader, TensorDataset # 转成张量 X_train_t torch.tensor(X_train.values, dtypetorch.float32) y_train_t torch.tensor(y_train.values, dtypetorch.float32).view(-1, 1) X_test_t torch.tensor(X_test.values, dtypetorch.float32) y_test_t torch.tensor(y_test.values, dtypetorch.float32).view(-1, 1) train_ds TensorDataset(X_train_t, y_train_t) train_loader DataLoader(train_ds, batch_size32, shuffleTrue) optimizer torch.optim.Adam(model_mlp.parameters(), lr1e-3) criterion nn.MSELoss() best_loss float(inf) patience 20 counter 0 for epoch in range(500): model_mlp.train() epoch_loss 0.0 for xb, yb in train_loader: optimizer.zero_grad() pred model_mlp(xb) loss criterion(pred, yb) loss.backward() optimizer.step() epoch_loss loss.item() * len(xb) epoch_loss / len(train_ds) if epoch_loss best_loss: best_loss epoch_loss counter 0 torch.save(model_mlp.state_dict(), best_mlp.pth) else: counter 1 if counter patience: print(f早停于 epoch {epoch}) break参数说明batch_size 设 32 是常见起点样本少可以降到 16学习率 1e-3 是 Adam 的默认值如果 loss 震荡明显可以降到 1e-4patience 设 20 表示连续 20 个 epoch 验证损失不降就停。注意这里用的是训练损失做早停严格来说应该划一个验证集但样本量小的时候可以先用训练损失观察。4.3 预测与评估MLP 和线性回归怎么比才公平评估的时候两个模型必须用同一份测试集、同一个评估指标。我一般看 MSE、MAE 和方向准确率三个指标。model_mlp.load_state_dict(torch.load(best_mlp.pth)) model_mlp.eval() with torch.no_grad(): y_pred_mlp model_mlp(X_test_t).numpy().flatten() mse_mlp mean_squared_error(y_test, y_pred_mlp) mae_mlp mean_absolute_error(y_test, y_pred_mlp) # 方向准确率预测涨跌方向与实际一致的比例 dir_acc_lr np.mean(np.sign(y_pred_lr) np.sign(y_test)) dir_acc_mlp np.mean(np.sign(y_pred_mlp) np.sign(y_test)) print(fMLP MSE{mse_mlp:.6f}MAE{mae_mlp:.6f}) print(f线性回归方向准确率{dir_acc_lr:.4f}) print(fMLP 方向准确率{dir_acc_mlp:.4f})方向准确率在金融预测里比 MSE 更实用因为交易看的是方向。如果 MLP 的 MSE 更低但方向准确率没提升说明它只是拟合了幅度没抓到方向。我见过不少案例MLP 在 MSE 上略胜但方向准确率和线性回归差不多这时候就要考虑是不是特征里根本没有非线性信号。5. 避坑与排查黄金期货预测里最容易翻车的五件事5.1 用原始价格做回归R² 虚高现象线性回归 R² 跑到 0.95 以上看起来效果极好。原因原始价格序列非平稳模型学到的只是趋势测试集和训练集共享同一个趋势R² 自然高。解决先做平稳性检验用差分后的序列建模R² 降到 0.1 左右才是正常水平。5.2 随机切分时间序列造成未来信息泄露现象测试集效果远好于预期实盘一塌糊涂。原因用train_test_split默认随机打乱导致训练集里混入了未来数据。解决按时间顺序切分前 80% 做训练后 20% 做测试绝对不能 shuffle。5.3 格兰杰检验用了非平稳序列现象检验结果一大堆显著但模型效果没提升。原因格兰杰因果检验要求序列平稳用原始价格做检验F 统计量分布不对p 值不可信。解决先差分再做检验或者用协整检验处理非平稳序列的长期关系。5.4 MLP 训练 loss 不降或震荡现象训练 loss 一直在高位震荡或者降到某个值就不动了。原因学习率太大、特征没标准化、或者网络太深。解决先做特征标准化学习率降到 1e-4 试试隐藏层从两层减到一层观察 loss 曲线。5.5 用 MSE 选模型忽略方向准确率现象MLP 的 MSE 比线性回归低但实盘收益没改善。原因MSE 衡量的是幅度误差金融预测更看重方向。解决把方向准确率作为主要评估指标MSE 作为辅助两个模型在同一测试集上对比。6. 进阶技巧用滚动窗口验证和特征重要性分析提升可信度走到这里模型已经能跑通了但离可信还差一步。我一般会做两件事滚动窗口验证和特征重要性分析。滚动窗口验证的做法是用前 N 天训练预测第 N1 天然后窗口向前滑动一天重新训练再预测。这样能模拟实盘的滚动预测场景比单次切分更可靠。def rolling_window_eval(X, y, model_fn, window_size200, step1): preds, actuals [], [] for start in range(0, len(X) - window_size - step, step): end start window_size X_train_rw X.iloc[start:end] y_train_rw y.iloc[start:end] X_test_rw X.iloc[end:end step] y_test_rw y.iloc[end:end step] model model_fn() model.fit(X_train_rw, y_train_rw) pred model.predict(X_test_rw) preds.extend(pred) actuals.extend(y_test_rw) return np.array(preds), np.array(actuals) preds_lr, actuals_lr rolling_window_eval(X, y, lambda: LinearRegression(), window_size200) print(f滚动窗口线性回归方向准确率{np.mean(np.sign(preds_lr) np.sign(actuals_lr)):.4f})参数说明window_size200表示每次用 200 个样本训练这个值可以根据数据量调整一般不少于特征数的 10 倍step1表示每天滚动一次计算量大但最贴近实盘。如果数据量很大可以设 step5 或 10 降低计算成本。特征重要性分析方面线性回归看系数绝对值MLP 可以用 permutation importance把某一列特征随机打乱看模型误差增加多少增加越多说明该特征越重要。from sklearn.inspection import permutation_importance def mlp_predict(X_np): model_mlp.eval() with torch.no_grad(): return model_mlp(torch.tensor(X_np, dtypetorch.float32)).numpy().flatten() result permutation_importance( model_mlp, X_test.values, y_test.values, n_repeats10, random_state42, scoringneg_mean_squared_error ) for i, col in enumerate(X.columns): print(f{col}重要性均值 {result.importances_mean[i]:.6f})我自己的习惯是每次做完一轮模型对比先把滚动窗口验证跑一遍如果滚动窗口的方向准确率能稳定在 52% 以上再考虑进一步调参或加特征。低于这个数说明特征里没有可用的信号换模型也是白搭。黄金期货预测这件事模型只是最后一步前面的平稳性检验和因果筛选才是决定上限的地方。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询