ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

BP神经网络回归实战:从原理到代码实现与调优指南

2026/8/31 17:10:32 拓冰建站 浏览量
BP神经网络回归实战:从原理到代码实现与调优指南 简介本资源是一套面向本科及以上学习者与科研初学者的BP神经网络回归建模实践方案聚焦碳排放量这一典型时间序列预测任务通过MATLAB实现完整建模流程解决传统BP网络在时序数据中动态特征捕捉能力不足的问题。压缩包共9个文件5个核心MATLAB脚本、3个Excel数据表、1个MAT文件总大小仅32KB轻量易部署其中含训练主程序、误差评估函数MSE/RMSE/MAE/MBE、决定系数R²计算模块及多版本BP训练脚本数据文件涵盖原始碳排放时序样本与训练过程误差记录全部代码带中文注释便于理解原理与二次开发。已有164人学习下载资源结构清晰、模块解耦明确既可直接运行复现结果也支持替换数据或调整网络结构用于其他回归场景拓展应用。1. 项目概述从“黑箱”到“可解释”的回归预测在数据分析和预测建模的领域里回归分析是我们理解变量间关系、进行数值预测的基石。从经典的线性回归到复杂的非线性模型我们一直在寻找更强大的工具来拟合现实世界中的复杂数据模式。当数据背后的规律不再是简单的直线或多项式时传统的线性模型就显得力不从心。这时BP神经网络Backpropagation Neural Network作为一种强大的非线性函数逼近器就进入了我们的视野。这个项目“基于BP神经网络的回归分析”其核心价值在于提供了一套从数据准备、网络构建、训练调优到结果评估的完整、可复现的解决方案。它不仅仅是一段代码更是一个完整的分析框架旨在帮助数据分析师、算法工程师甚至相关领域的研究者将BP神经网络这个听起来有些“黑箱”的模型变成一个可以实际解决回归预测问题的“白盒”工具。无论你是想预测房价、股票走势还是分析工业参数对产品质量的影响这套完整的数据和代码都能让你跳过繁琐的底层搭建直接切入模型调优与应用的核心。2. 项目整体设计与核心思路拆解2.1 为什么选择BP神经网络做回归回归问题的本质是寻找一个函数 ( f )使得 ( y f(X) )其中 ( X ) 是输入特征( y ) 是连续的目标值。BP神经网络特别是多层感知机MLP因其万能逼近定理而闻名——理论上一个包含足够多神经元和至少一个隐藏层的神经网络可以以任意精度逼近任何连续函数。这与许多现实世界中的非线性、高维关系不谋而合。在这个项目中选择BP神经网络而非其他回归模型如支持向量回归SVR、决策树回归等主要基于以下几点考量强大的非线性拟合能力数据间的真实关系往往错综复杂存在交互效应和高阶非线性。BP神经网络通过隐藏层和激活函数如ReLU, Sigmoid, Tanh的组合能够自动学习并表征这些复杂模式。端到端的学习无需像传统统计方法那样手动进行特征工程如构造多项式项、交互项。网络能从原始或初步处理的特征中自动提取对预测有用的高阶特征。对大规模数据的适应性虽然本项目可能基于中等规模数据集演示但BP神经网络的结构尤其是配合现代优化器能够很好地扩展到海量数据通过批量训练高效学习。方案的完整性“代码完整数据齐全”意味着项目提供了一个从零到一的闭环体验。用户不仅能学习如何调用一个神经网络库更能理解数据如何流入、网络如何构建、损失如何计算、权重如何更新这一完整流程这对于深入掌握机器学习原理至关重要。2.2 项目核心组件与工作流设计一个完整的BP神经网络回归项目其工作流可以清晰地划分为几个阶段本项目正是遵循了这一逻辑数据准备与预处理阶段这是所有机器学习项目的基石。项目提供的“数据齐全”意味着包含了用于训练和测试的原始数据集。这一阶段的核心任务包括数据加载、探索性分析、处理缺失值、特征缩放如归一化或标准化这对神经网络训练收敛至关重要以及划分训练集、验证集和测试集。网络模型构建阶段这是项目的核心。需要确定网络的结构即输入层维度由特征数量决定。隐藏层的层数与每层神经元数量这是主要的超参数决定了模型的容量和复杂度。层数越多、神经元越多拟合能力越强但也越容易过拟合。激活函数的选择隐藏层通常使用ReLURectified Linear Unit或其变种因为它能有效缓解梯度消失问题加速收敛。输出层对于回归任务通常使用线性激活函数即无激活函数因为我们需要输出连续的任意值。损失函数回归任务最常用的是均方误差MSE它衡量预测值与真实值之间的平均平方差。平均绝对误差MAE也是一个鲁棒性更强的选择。优化器负责更新网络权重以最小化损失。Adam优化器因其自适应学习率特性成为目前最流行且通常效果良好的默认选择。模型训练与调优阶段使用训练集数据对网络进行迭代训练。关键操作包括前向传播计算预测值和损失。反向传播计算损失相对于各权重的梯度。优化器利用梯度更新权重。同时在独立的验证集上监控性能用于早期停止防止过拟合和超参数调优如学习率、批大小、网络结构等。模型评估与结果分析阶段在从未参与训练和调优的测试集上对最终模型进行公正评估。除了损失函数值还应使用回归任务常用的指标如R²分数决定系数、平均绝对误差MAE、均方根误差RMSE等。同时通过绘制预测值 vs. 真实值的散点图、残差图等直观分析模型表现。注意一个常见的误区是只关注最终测试集上的高分数而忽略了模型在验证集上的稳定性以及过拟合的检查。务必确保验证集和测试集的划分是随机的、独立的并且测试集只在最后评估时使用一次。3. 核心细节解析与实操要点3.1 数据预处理不止是缩放那么简单“数据齐全”是优势但如何正确使用数据是成败的关键。对于神经网络数据预处理不当会导致训练困难、收敛缓慢甚至完全失败。特征缩放归一化/标准化这是必须的步骤。因为神经网络中权重的初始化和梯度下降优化算法对输入特征的尺度非常敏感。如果某个特征的数值范围例如“年薪”在0-100万远大于另一个特征例如“年龄”在0-1标准化后那么权重更新会严重偏向大尺度特征。通常我们对每个特征进行Z-score标准化减去均值除以标准差或Min-Max归一化缩放到[0,1]区间。标准化通常更受青睐因为它不会改变数据分布且对异常值不那么敏感。处理缺失值与异常值项目数据如果“齐全”可能已处理了这些问题。但实践中必须检查。对于缺失值可根据情况采用删除、中位数/均值填充或使用算法预测填充。对于异常值需要结合业务知识判断是录入错误还是真实情况决定是否剔除或缩尾处理。特征工程可选但重要虽然神经网络能自动学习特征但适当的特征工程能显著提升性能、降低模型复杂度。例如对于周期性特征如小时、月份可以将其转换为正弦/余弦编码对于分类特征进行独热编码或嵌入编码创建有意义的交互特征或多项式特征为网络提供更直接的线索。3.2 网络结构设计在“深度”与“宽度”间寻找平衡bp神经网络结构图通常展示的是一个输入层、若干隐藏层和一个输出层的全连接结构。设计时需考虑深度层数更深的网络可以学习更复杂的层次化特征。但对于许多回归问题1-3个隐藏层往往足够。过深的网络在数据量不足时极易过拟合。宽度每层神经元数一个经验法则是隐藏层神经元数量可以介于输入维度和输出维度之间常见的是逐渐减少如金字塔形也可以是保持不变。另一个启发式方法是使用“膨胀-收缩”结构即第一个隐藏层神经元数多于输入层以增加模型容量。一个实用的起点对于中等复杂度的回归问题可以尝试一个包含1-2个隐藏层的网络每个隐藏层的神经元数可以是输入特征数的0.5倍到2倍。例如输入有20个特征可以尝试[64, 32]或[128, 64]这样的结构。然后根据验证集表现进行调整。实操心得不要一开始就设计非常庞大的网络。从一个较小的网络开始训练如果它在训练集上都表现不佳欠拟合再逐步增加层数或神经元。这比一开始就用大网络然后拼命正则化要更高效。3.3 损失函数与优化器的选择损失函数均方误差MSE是回归任务的标准选择它对大误差给予更大的惩罚因此模型会极力避免出现大的预测偏差。如果你的数据中含有较多异常值MSE可能会使模型过度关注这些异常点。此时平均绝对误差MAE更为鲁棒它对所有误差给予线性惩罚。也可以考虑Huber Loss它在误差较小时像MSE误差较大时像MAE是两者的折中。优化器Adam优化器是当前事实上的标准。它结合了动量Momentum和自适应学习率RMSProp的优点在大多数情况下都能快速稳定地收敛。其关键超参数是学习率learning_rate通常可以从1e-3、3e-4或1e-4开始尝试。如果训练过程中损失震荡剧烈可以降低学习率如果收敛过慢可以适当增大。学习率调度固定学习率可能不是最优的。可以采用学习率衰减策略如在训练后期降低学习率以精细调整权重。PyTorch中的StepLR、ReduceLROnPlateau或 TensorFlow/Keras 中的回调函数都能方便地实现这一点。4. 实操过程与核心环节实现假设我们使用Python并借助深度学习框架如PyTorch或TensorFlow/Keras来实现。这里以PyTorch风格为例展示核心代码逻辑。4.1 环境搭建与数据加载首先确保安装了必要的库numpy,pandas,matplotlib,scikit-learn和torch。import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader, TensorDataset import pandas as pd from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler import matplotlib.pyplot as plt # 1. 加载数据 data pd.read_csv(your_regression_data.csv) # 假设项目提供了CSV文件 X data.drop(target_column, axis1).values # 特征 y data[target_column].values.reshape(-1, 1) # 目标值重塑为列向量 # 2. 划分训练集、验证集、测试集 (例如 60%/20%/20%) X_temp, X_test, y_temp, y_test train_test_split(X, y, test_size0.2, random_state42) X_train, X_val, y_train, y_val train_test_split(X_temp, y_temp, test_size0.25, random_state42) # 0.25 * 0.8 0.2 # 3. 特征标准化 (非常重要) scaler_X StandardScaler() X_train_scaled scaler_X.fit_transform(X_train) X_val_scaled scaler_X.transform(X_val) # 注意使用训练集的均值和标准差 X_test_scaled scaler_X.transform(X_test) scaler_y StandardScaler() y_train_scaled scaler_y.fit_transform(y_train) y_val_scaled scaler_y.transform(y_val) y_test_scaled scaler_y.transform(y_test) # 4. 转换为PyTorch张量并创建DataLoader train_dataset TensorDataset(torch.FloatTensor(X_train_scaled), torch.FloatTensor(y_train_scaled)) val_dataset TensorDataset(torch.FloatTensor(X_val_scaled), torch.FloatTensor(y_val_scaled)) test_dataset TensorDataset(torch.FloatTensor(X_test_scaled), torch.FloatTensor(y_test_scaled)) train_loader DataLoader(train_dataset, batch_size32, shuffleTrue) val_loader DataLoader(val_dataset, batch_size32, shuffleFalse)4.2 定义BP神经网络模型接下来我们定义一个简单的多层感知机MLP模型。class RegressionMLP(nn.Module): def __init__(self, input_size, hidden_layers[64, 32], dropout_rate0.1): super(RegressionMLP, self).__init__() layers [] prev_size input_size # 动态构建隐藏层 for i, hidden_size in enumerate(hidden_layers): layers.append(nn.Linear(prev_size, hidden_size)) layers.append(nn.ReLU()) layers.append(nn.Dropout(dropout_rate)) # 添加Dropout防止过拟合 prev_size hidden_size # 输出层线性层无激活函数 layers.append(nn.Linear(prev_size, 1)) self.network nn.Sequential(*layers) def forward(self, x): return self.network(x) # 实例化模型 input_dim X_train_scaled.shape[1] model RegressionMLP(input_sizeinput_dim, hidden_layers[128, 64]) print(model)4.3 训练循环与验证监控这是模型学习的核心过程我们同时监控训练损失和验证损失。device torch.device(cuda if torch.cuda.is_available() else cpu) model.to(device) criterion nn.MSELoss() # 损失函数均方误差 optimizer optim.Adam(model.parameters(), lr0.001) # 优化器Adam scheduler optim.lr_scheduler.ReduceLROnPlateau(optimizer, modemin, factor0.5, patience10) # 学习率调度 num_epochs 200 train_losses, val_losses [], [] for epoch in range(num_epochs): # 训练阶段 model.train() running_train_loss 0.0 for batch_X, batch_y in train_loader: batch_X, batch_y batch_X.to(device), batch_y.to(device) optimizer.zero_grad() outputs model(batch_X) loss criterion(outputs, batch_y) loss.backward() optimizer.step() running_train_loss loss.item() * batch_X.size(0) epoch_train_loss running_train_loss / len(train_loader.dataset) train_losses.append(epoch_train_loss) # 验证阶段 model.eval() running_val_loss 0.0 with torch.no_grad(): for batch_X, batch_y in val_loader: batch_X, batch_y batch_X.to(device), batch_y.to(device) outputs model(batch_X) loss criterion(outputs, batch_y) running_val_loss loss.item() * batch_X.size(0) epoch_val_loss running_val_loss / len(val_loader.dataset) val_losses.append(epoch_val_loss) # 学习率调度 scheduler.step(epoch_val_loss) # 打印进度 if (epoch 1) % 20 0: print(fEpoch [{epoch1}/{num_epochs}], Train Loss: {epoch_train_loss:.4f}, Val Loss: {epoch_val_loss:.4f}) # 简单早期停止如果验证损失连续多个epoch不下降 # 更健壮的实现需要保存最佳模型这里为简化示例 # 绘制损失曲线 plt.plot(train_losses, labelTraining Loss) plt.plot(val_losses, labelValidation Loss) plt.xlabel(Epoch) plt.ylabel(Loss (MSE)) plt.legend() plt.title(Training and Validation Loss Curve) plt.show()4.4 模型评估与结果可视化训练完成后在测试集上进行最终评估并将预测值反标准化回原始尺度。# 在测试集上评估 model.eval() test_predictions_scaled [] test_targets_scaled [] with torch.no_grad(): for batch_X, batch_y in test_loader: batch_X, batch_y batch_X.to(device), batch_y.to(device) outputs model(batch_X) test_predictions_scaled.append(outputs.cpu()) test_targets_scaled.append(batch_y.cpu()) test_predictions_scaled torch.cat(test_predictions_scaled).numpy() test_targets_scaled torch.cat(test_targets_scaled).numpy() # 将标准化后的预测值和真实值反标准化 test_predictions scaler_y.inverse_transform(test_predictions_scaled) test_targets scaler_y.inverse_transform(test_targets_scaled) # 计算评估指标 from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score mse mean_squared_error(test_targets, test_predictions) rmse np.sqrt(mse) mae mean_absolute_error(test_targets, test_predictions) r2 r2_score(test_targets, test_predictions) print(fTest MSE: {mse:.4f}) print(fTest RMSE: {rmse:.4f}) print(fTest MAE: {mae:.4f}) print(fTest R² Score: {r2:.4f}) # 绘制预测值 vs. 真实值散点图 plt.figure(figsize(8,6)) plt.scatter(test_targets, test_predictions, alpha0.5) plt.plot([test_targets.min(), test_targets.max()], [test_targets.min(), test_targets.max()], r--, lw2) # 对角线 plt.xlabel(True Values) plt.ylabel(Predictions) plt.title(True vs. Predicted Values (Test Set)) plt.show() # 绘制残差图 residuals test_targets - test_predictions plt.figure(figsize(8,6)) plt.scatter(test_predictions, residuals, alpha0.5) plt.axhline(y0, colorr, linestyle--) plt.xlabel(Predictions) plt.ylabel(Residuals) plt.title(Residual Plot) plt.show()5. 常见问题与排查技巧实录在实际操作中你几乎一定会遇到下面这些问题。这里记录了我的排查思路和解决方法。5.1 问题一损失不下降或下降非常缓慢症状训练了几个epoch甚至几十个epoch后训练损失和验证损失几乎不变或者下降的幅度微乎其微。可能原因与排查学习率过大或过小这是最常见的原因。学习率太大会导致损失在最优值附近震荡甚至发散学习率太小则收敛极慢。解决方法尝试使用一个经典的学习率如1e-3、1e-4或者使用学习率查找器LR Finder来探索一个合适的范围。观察损失曲线如果是震荡就调小学习率如果是几乎水平就调大。数据未标准化输入特征的尺度差异巨大导致梯度更新失衡。解决方法务必对输入特征进行标准化或归一化处理。网络结构问题隐藏层神经元数量过少模型容量不足以拟合数据。解决方法适当增加隐藏层神经元数量或层数。激活函数问题在深度网络中如果使用Sigmoid或Tanh可能导致梯度消失。解决方法隐藏层统一使用ReLU或其变种如Leaky ReLU。权重初始化不当如果权重初始化为0或过小的随机值可能导致对称性破坏问题。解决方法使用框架默认的初始化如Kaiming初始化 for ReLU通常就很好。我的经验遇到损失不降我第一个检查的就是数据预处理特别是标准化第二个就是学习率。我会先画一个epoch50的损失曲线看看趋势这能快速定位问题。5.2 问题二模型过拟合症状训练损失持续下降但验证损失在某个点后开始上升两者之间的差距越来越大。可能原因与排查模型过于复杂相对于数据量网络拥有太多的参数层数多、神经元多。解决方法简化模型结构减少层数或神经元数量。这是最根本的方法。缺乏正则化模型可以“记住”训练数据中的噪声。解决方法添加Dropout层在训练时随机“关闭”一部分神经元强制网络学习更鲁棒的特征。如前面代码所示在隐藏层后加入nn.Dropout(0.2)。L1/L2权重正则化在优化器中加入权重衰减weight decay惩罚大的权重值。Adam优化器中可以通过weight_decay参数设置L2正则化。早停Early Stopping监控验证损失当其在连续多个epoch内不再改善时停止训练并回滚到验证损失最小的那个epoch的模型。训练数据不足这是本质问题。解决方法如果可能收集更多数据。或者使用数据增强技术对于回归任务可能有限但可以对输入特征添加微小噪声来模拟。我的经验Dropout和早停是我最常用的组合拳。我会先从一个稍大的模型开始训练观察验证损失曲线一旦出现过拟合迹象就加入Dropout并启用早停。权重衰减如weight_decay1e-4通常也会作为默认配置加上。5.3 问题三预测结果存在系统性偏差症状在预测值 vs. 真实值散点图中数据点虽然大致沿对角线分布但整体偏上或偏下或者在残差图中残差均值明显不为0且随预测值变化呈现明显的趋势如喇叭形、弯曲形。可能原因与排查目标变量分布偏斜如果目标变量y严重偏斜如长尾分布MSE损失会使得模型倾向于预测较大的值导致对小值的预测系统性偏高。解决方法考虑对目标变量进行变换如对数变换log(1y)使其分布更接近正态训练后再反变换回来。或者使用MAE、Huber等对异常值不敏感的损失函数。模型偏差模型复杂度不够无法捕捉数据的真实趋势。解决方法检查残差图模式。如果残差呈现明显的非线性模式如U型说明模型遗漏了重要的非线性关系需要增加网络容量或进行更复杂的特征工程。数据泄露验证集或测试集的信息在预处理时如标准化被“污染”。解决方法确保标准化器StandardScaler等预处理对象仅用训练集数据拟合fit然后应用到验证集和测试集transform。绝对不能用全部数据来拟合。我的经验残差图是诊断模型问题的利器。一个健康的模型其残差应该随机、均匀地分布在0附近。任何明显的模式都指向了模型的缺陷。我总会仔细分析残差图它比单纯的R²分数能告诉我更多信息。5.4 问题速查表问题现象可能原因优先排查步骤损失为NaN或无限大学习率太大、数据包含NaN/Inf、梯度爆炸1. 大幅降低学习率2. 检查数据清洗3. 尝试梯度裁剪torch.nn.utils.clip_grad_norm_训练损失震荡剧烈学习率太大、批大小太小1. 降低学习率2. 适当增大批大小如从32到64验证损失远大于训练损失严重过拟合1. 增加Dropout率2. 增强L2正则化增大weight_decay3. 简化模型结构4. 检查是否误将测试集当验证集模型预测全是同一个值学习率太小、网络结构有误如最后一层用了Sigmoid、梯度消失1. 检查网络输出层激活函数应为线性2. 增大学习率3. 检查梯度是否正常传播可打印中间层输出范围R²分数为负模型预测比简单使用均值还要差1. 检查数据预处理标准化是否正确2. 检查特征和目标变量是否匹配3. 模型可能完全未学习检查训练流程6. 模型调优与性能提升进阶策略当基础模型搭建并运行起来后下一步就是精雕细琢追求更好的性能和泛化能力。这不仅仅是为了刷高测试集分数更是为了确保模型在真实、未知数据上的可靠性。6.1 超参数的系统化调优手动调整超参数如学习率、隐藏层大小、Dropout率、批大小效率低下。系统化的方法能帮你更快地找到接近最优的组合。网格搜索Grid Search为每个超参数设定一个候选值列表尝试所有可能的组合。虽然计算成本高但对于3-4个超参数的小范围搜索是可行的。可以使用sklearn.model_selection.GridSearchCV配合Keras的包装器或Ray Tune、Optuna等更强大的工具。随机搜索Random Search实践证明在大多数情况下随机搜索比网格搜索更高效。它不是在固定的网格上搜索而是在超参数空间内随机采样。这让你能用相同的计算资源探索更广阔的空间。贝叶斯优化Bayesian Optimization这是目前最先进的超参数调优方法之一。它利用已有的评估结果来构建一个概率模型预测哪些超参数组合可能带来更好的性能从而智能地选择下一组要尝试的参数。Optuna和Hyperopt库很好地实现了这种方法。实操建议对于初学者可以从手动调整最重要的两个参数开始学习率和网络大小层数与神经元数。使用验证集损失作为评判标准。当手动调整遇到瓶颈时再引入随机搜索或贝叶斯优化。6.2 利用交叉验证获得稳健评估我们之前采用了简单的训练/验证/测试集分割。为了更稳健地评估模型性能尤其是数据量不大时可以使用K折交叉验证。流程将训练集不含测试集均匀分成K份如5份。依次将其中1份作为验证集其余K-1份作为训练集训练K个模型。最后计算这K个模型在各自验证集上性能的平均值作为模型性能的估计。优势充分利用有限数据减少因单次数据划分随机性带来的评估偏差。得到的性能估计更可靠。注意交叉验证主要用于模型评估和超参数选择。一旦通过交叉验证确定了最优超参数你需要用这些超参数在全部训练集训练验证上重新训练一个最终模型然后在独立的测试集上进行最终的一次性评估。# 使用sklearn进行K折交叉验证的简单思路伪代码风格 from sklearn.model_selection import KFold kfold KFold(n_splits5, shuffleTrue, random_state42) fold_scores [] for train_idx, val_idx in kfold.split(X_train_full_scaled): # 划分本折的数据 X_train_fold, X_val_fold X_train_full_scaled[train_idx], X_train_full_scaled[val_idx] y_train_fold, y_val_fold y_train_full_scaled[train_idx], y_train_full_scaled[val_idx] # 创建模型、训练注意要重新初始化模型权重 model create_model() train_model(model, X_train_fold, y_train_fold, X_val_fold, y_val_fold) # 评估本折模型在验证集上的性能 score evaluate_model(model, X_val_fold, y_val_fold) fold_scores.append(score) print(fCross-Validation Scores: {fold_scores}) print(fMean CV Score: {np.mean(fold_scores):.4f} (/- {np.std(fold_scores):.4f}))6.3 集成学习让多个网络共同决策如果单个模型的性能已经达到瓶颈集成学习是进一步提升预测准确性和稳定性的有效手段。其核心思想是“三个臭皮匠顶个诸葛亮”。Bagging自助聚合例如训练多个相同的BP神经网络模型每个模型使用训练集的不同自助采样集bootstrap sample进行训练。预测时取所有模型预测值的平均值回归任务。这可以有效降低方差减少过拟合。随机森林就是决策树上的Bagging。模型平均这是最简单直接的集成方法。用不同的随机种子初始化、或使用不同的超参数配置训练出几个独立的神经网络模型。最终的预测结果是这些模型预测值的简单平均或加权平均。这种方法通常总能带来小幅但稳定的性能提升。Stacking训练多个不同的“基学习器”第一层模型可以是不同结构的神经网络也可以是SVR、决策树等其他算法。然后用这些基学习器对训练数据的预测结果作为新的特征训练一个“元学习器”第二层模型通常是一个简单的线性回归或浅层神经网络来进行最终预测。Stacking潜力很大但实现更复杂也更容易过拟合需要谨慎使用验证集。我的经验对于重要的项目我几乎总会训练3-5个同构但不同初始化的模型然后取它们的预测平均值作为最终输出。这个简单的操作几乎零成本但常常能将RMSE降低几个百分点并且使预测结果更加稳定。本文还有配套的精品资源点击获取