Boosting 回归模型超参调优指南
XGBoost、CatBoost和LightGBM等提升决策树算法是非常强大的回归任务机器学习方法。要获得最佳预测性能需要进行超参数调优例如网格搜索来探索数千种参数组合。虽然暴力技术可以完成任务但它们很快就会变得计算量过大并且可能导致过拟合模型使其无法泛化到未见过的数据。另一方面贝叶斯优化提供了一个更高效的替代方案通过智能地导航超参数空间来减少计算负担。值得注意的是仅仅使用贝叶斯技术进行超参数优化也不足以保证模型的鲁棒性。适当的验证策略包括独立验证集和交叉验证程序对于评估模型在训练数据之外的泛化能力至关重要。在本博客中你将通过实战示例学习如何优化提升回归模型同时最小化过拟合的风险。 我们将使用HGBoost 库来训练和优化基于XGBoost的回归模型并使用贝叶斯优化技术。在工作流程中我们将仔细地将数据分为训练集、测试集和独立验证集结合内部优化循环和外部交叉验证循环来选择最鲁棒的模型。然后我们将解释并可视化分析优化后的超参数空间以及由此产生的模型性能指标。在整个博客中理论和实际示例的结合将帮助你逐步更好地理解为自己的数据集做出决策。1、回归模型的超优化是一个多步骤过程构建一个鲁棒的提升回归模型远不只是简单地将算法拟合到数据上。挑战是双重的首先我们想要识别一个能最大化预测性能的参数组合其次我们旨在防止过拟合并确保模型能泛化到未见过的数据。超优化工作流是一个多步骤过程可以分解为九个较小的步骤。第一步专注于准备数据而剩余步骤二到九主要由HGBoost框架自动化。不过你在所有步骤中都有足够的控制权在以下部分中我们将详细介绍每个步骤并解释它们如何有助于创建一个可靠且可解释的回归模型。导入并预处理数据集将数据集加载到你的 Python 环境中并执行必要的预处理步骤如处理缺失值、编码分类变量、移除不一致性以及为模型训练准备特征矩阵。将数据集拆分为训练集、测试集和验证集仔细地将数据划分为独立的子集以避免信息泄漏。训练集和测试集在超参数优化期间使用而独立验证集保留用于最终对选定模型的无偏评估。选择适当的评估指标选择一个与问题目标一致的回归指标如 RMSE、MAE 或 R²。所选指标将指导优化过程并决定模型性能的评估方式。构建嵌套交叉验证框架创建一个双重循环验证策略其中内部循环执行贝叶斯超参数优化外部循环使用交叉验证评估模型鲁棒性。这种方法有助于防止过于乐观的性能估计。识别能够泛化的最佳性能模型不仅根据预测准确性比较候选模型还要根据它们在不同验证折中的持续泛化能力。目标是选择一个在未见数据上可靠执行的模型。在独立验证集上评估选定模型模型选择后在未触动的验证集上评估最终性能以获得真实世界预测性能的无偏估计。在完整数据集上训练最终模型一旦确定了最优超参数使用完整数据集重新训练选定的提升回归模型以最大化可用于学习的信息。可视化超参数搜索空间和模型性能生成信息丰富的图表以检查优化轨迹、比较模型配置并更好地理解特定超参数如何影响预测性能。解释结果和模型行为分析结果评估模型的优势和局限性并解释学习到的模式以获得关于优化过程和回归模型本身的实用洞察。2、HGBoost 库超优化梯度提升库HGBoost是一个用于XGBoost、LightGBM和CatBoost超参数优化的 Python 包。HGBoost 自动化了最密集的步骤如上图所示步骤 2 到 9。这带来了许多优势自动搜索能泛化的最佳模型减少选择过训练模型的可能性通过有洞察力的图表提供可解释的结果深入检查超参数空间了解所有评估模型的性能确定 k 折交叉验证的准确率最后但并非最不重要的最佳决策树可以与最重要的特征一起绘制示意图如下图所示。3、回归挑战参数优化的实战用例对于这个用例我们将使用 Titanic 数据集。我选择这个众所周知的数据集是因为我想把重点放在超参数优化步骤上而不一定是数据本身。因为我们已经见过这个数据集很多次所以更容易理解我们采取的一些步骤以及如何优化结果。这可以帮助你将类似的解释映射到你自己的数据集上。总结来说Titanic 数据集是免费使用的曾是 Kaggle 比赛 从灾难中学习机器学习 的一部分。它包含 891 个样本和 12 个特征。这个数据集经常被用来预测布尔型生存变量。在我们的案例中将把年龄设为目标值。在开始之前设置你的环境并安装所需的包第一步是使用 Conda、Venv 或 uv 创建一个新环境。我强烈建议始终为项目或实验创建新的干净环境。原因是旧环境可能包含特定版本的包这些包可能与新安装冲突。然后在终端中从 PyPi 安装HGboost。# 1. Install the library pip install hgboost # 2. Install hyperopt from GitHub source githttps://github.com/erdogant/hyperopt.git3.1 数据预处理数据预处理可能是密集的通常需要反复迭代直到你清理、插补、移除变量。对于 Titanic 数据集我们将移除PassengerId和Name等特征以及包含缺失值的行样本。预处理步骤后有 714 行 x 203 列。请注意在实际项目中建议仔细进行探索性数据分析、特征清理和特征工程。最大的性能提升通常来自这些初始步骤。最大的性能提升通常来自特征清理和特征工程等步骤。超参数调优是为了榨出最后的隐藏的信息。预处理步骤完成后我们可以使用HGboost将数据集转换为XGBoost 算法可以使用的结构化形式。请参见下面代码块中的示例。# Import the library from hgboost import hgboost import numpy as np # Initialize hgb hgboost() # Load example data set df hgb.import_example(titanic) print(df) # PassengerId Survived Pclass ... Fare Cabin Embarked # 0 1 0 3 ... 7.2500 NaN S # 1 2 1 1 ... 71.2833 C85 C # 2 3 1 3 ... 7.9250 NaN S # 3 4 1 1 ... 53.1000 C123 S # 4 5 0 3 ... 8.0500 NaN S # .. ... ... ... ... ... ... ... # 886 887 0 2 ... 13.0000 NaN S # 887 888 1 1 ... 30.0000 B42 S # 888 889 0 3 ... 23.4500 NaN S # 889 890 1 1 ... 30.0000 C148 S # 890 891 0 3 ... 7.7500 NaN Q # [891 rows x 11 columns] # Set age as target value, then remove from data set y df[Age].values I ~np.isnan(y) # Remove features df.drop([Age, PassengerId, Name], axis1, inplaceTrue) # Perform pre-processing X hgb.preprocessing(df) # New dataset X X.loc[I,:] y y[I] ################################################################## print(X) # Survived_1.0 Pclass_1.0 ... Embarked_Q Embarked_S # 0 False False ... False True # 1 True True ... False False # 2 True False ... False True # 3 True True ... False True # 4 False False ... False True # .. ... ... ... ... ... # 885 False False ... True False # 886 False False ... False True # 887 True True ... False True # 889 True True ... False False # 890 False False ... True False # [714 rows x 203 columns]预处理函数导入 df2onehot 库 将分类值编码为独热编码并保持连续值不变。请注意预处理步骤是在考虑到我们将要训练XGBoost 算法的情况下执行的。这需要一个独热编码步骤因为XGBoost无法处理非数值因子。阅读这篇博客以了解更多关于优势以及如何进行预处理的信息。如何驯龙不产生过拟合的梯度提升超参数调优使用 XGBoost、CatBoost 和 LightBoost 等提升决策树算法你可能超越其他模型但是……3.2 拆分数据集在初始化HGBoost时我们可以更改默认输入参数如下面的代码部分所示。进行超参数优化时更重要的步骤之一是将数据划分为独立的子集以避免数据泄漏。训练集和测试集在超参数优化期间使用而独立验证集保留用于最终对选定模型的无偏评估。总体而言对于监督任务将数据分成独立部分以避免在学习模型时过拟合是重要的。过拟合发生在模型过于好地学习了训练数据时包括噪声和不能泛化的模式导致在新的未见数据上表现不佳。在训练过程中数据集被分为训练集、测试集和独立验证集。验证集在整个训练过程中保持不变只在最后用于客观地评估最终模型的性能。在下面的示例中数据集使用 20% 的测试比例和 20% 的验证比例进行拆分由test_size0.2和eval_size0.2定义。此外训练期间应用了 5 折交叉验证以提高模型评估的鲁棒性。下图展示了数据集如何被划分为不同的拆分代码输出还报告了分配给每个子集的确切样本数。# Initialize library. hgb hgboost( max_eval500, # Search space is based on the number of evaluations. threshold0.5, # Classification threshold. In case of two-class model this is 0.5. cv5, # k-folds cross-validation. test_size0.2, # Percentage split for the testset. val_size0.2, # Percentage split for the validationset. top_cv_evals10, # Number of top best performing models that is evaluated. is_unbalancedTrue, # Control the balance of positive and negative weights, useful for unbalanced classes. random_stateNone, # Fix the random state to create reproducible results. n_jobs-1, # The number of CPU jobs to run in parallel. -1 means using all processors. gpuFalse, # Compute using GPU in case of True. early_stopping_rounds25, verboseinfo, # Print progress to screen. ) # results hgb.xgboost_reg(X, y, eval_metricrmse) # [hgboost.hgboost] [INFO] Start hgboost regression. # [hgboost.hgboost] [INFO] Collecting %s parameters. # [hgboost.hgboost] [INFO] method: xgb_reg # [hgboost.hgboost] [INFO] eval_metric: rmse # [hgboost.hgboost] [INFO] larger_is_better: False # [hgboost.hgboost] [INFO] ***************************************************************************************** # [hgboost.hgboost] [INFO] Total dataset: (714, 202) # [hgboost.hgboost] [INFO] Validation set: (143, 202) # [hgboost.hgboost] [INFO] Test-set: (143, 202) # [hgboost.hgboost] [INFO] Train-set: (428, 202)3.3选择适当的评估指标为了评估和优化回归模型的性能我们需要选择一个与问题目标一致的指标。常见的评估指标有均方根误差RMSE、均方误差MSE、平均绝对误差MAE和 R²。所选指标决定了在训练期间如何衡量模型性能并指导优化过程。在这个实现中评估指标可以通过eval_metric参数指定。如果不仔细拆分数据你就有过拟合模型参数并将数据拟合或学习得太好的风险。然后它可能很容易在正确预测新的未见过的数据样本上失败。3.4 拟合、优化超参数并选择最佳性能模型在这一点上我们已经为XGBoost预处理了数据并决定了使用哪个评估指标。我们现在可以开始拟合模型并优化超参数了。HGBoost中超参数优化的第一步是设置内部循环以使用贝叶斯优化超参数以及设置外部循环以使用k折交叉验证测试最佳性能模型的泛化能力。在我们的案例中搜索空间取决于XGBoost可用的超参数。超参数优化的搜索空间由HGBoost处理。我将使用 MAE 评估指标因为误差容易解释。我们将预测年龄当我们看到 MAE10 时这意味着平均而言预测值与真实值的距离是 10 年例如真实年龄可以是 40 岁预测年龄是 30或 50岁。# Train a model with XGBoost results hgb.xgboost(X, y, pos_label1, methodxgb_reg, eval_metricmae) # [hgboost.hgboost] [INFO] ***************************************************************************************** # [hgboost.hgboost] [INFO] Evaluate best [xgb_reg] model on validation dataset (143 samples, 20%) # [hgboost.hgboost] [INFO] [mae]: 9.567 using optimized hyperparameters on validation set. # [hgboost.hgboost] [INFO] [mae]: 10.15 using default (not optimized) parameters on validation set. # [hgboost.hgboost] [INFO] ***************************************************************************************** # [hgboost.hgboost] [INFO] Retrain [xgb_reg] on the entire dataset with the optimal hyperparameters. # [hgboost.hgboost] [INFO] Fin! # Print summary of results print(results[summary]) # Plot the summary of all evaluated models hgb.plot()通过运行如代码块所示的HGBoost我们遍历了搜索空间并创建了 500 个不同的模型max_eval500每个模型的性能对每组参数进行了评估也见下面图表的 x 轴。接下来我们可以根据模型性能进行排名以使用 5 折交叉验证方案cv5进一步调查排名前 10 的最佳性能模型的鲁棒性。从这个意义上说我们的目标是防止找到过训练的模型。通过绘图函数.plot()我们可以获得 500 个模型性能在这种情况下是 MAE的洞察。当我们看这张图时可以看到一条绿色虚线它描绘的是没有使用交叉验证方法的最佳性能模型而红色虚线描绘的是使用交叉验证的最佳性能模型。模型性能在MAE [9.5–11.25]范围内变化。我们选择的模型是红色虚线对应的那个。当我们看排名前 10 的模型红色的方形标记时它们在 k 折交叉验证期间的性能略差。换句话说500 次迭代中的最佳模型用绿色虚线表示但在 CV 中它的性能并不是最好的。因此选择了前 10 个中能更好泛化的模型红色虚线即 k 折 CV 中平均 MAE 最低的那个。通过这种方式我们旨在选择性能最好且能泛化的模型。对于我们的数据集500 次迭代中得分最高的模型得分为MAE9.567而基于 5 折交叉验证的平均得分为MAE10.2。虽然我们没有选择得分最高的模型但我们也避免了依赖一个可能过拟合的单一模型。我们现在有了一个准备好对新数据进行预测的模型。但在做预测之前让我们先尝试理解上面所有步骤中发生了什么见下一节中的步骤 5。3.5 结果的解释在这一点上我们有了一个训练好的模型并简要了解了基于交叉验证和独立验证集的回归结果。所有测试过的不同模型的超参数现在返回在results[summary]中可以进一步检查。摘要如下图所示。这里的每一行都是一个使用不同超参数集合学习的新模型。创建图表对于深入理解模型性能以及调查超参数在贝叶斯优化过程中如何调优非常有帮助。这将有助于更好地理解模型参数与准确率之间的关系。建立信任并获得对结果的直觉是知道模型参数是否被可靠选择的关键。制作图表并理解结果。我们可以使用内置功能创建以下图表用于深入调查超参数空间的图表。汇总所有评估模型的图表。显示使用交叉验证方案的性能的图表。绘制独立验证集的结果。最佳模型和最佳性能特征的决策树图。3.6 超参数调优的解释在我们找到优化后的模型后我们可以调查贝叶斯优化过程中调优的所选超参数的可靠性。使用.plot_params()函数我们可以创建有洞察力的图表如图 2所示。该图包含多个直方图或核密度图其中每个子图包含一个在 500 次模型迭代期间优化的单个参数。直方图底部的小条描绘了 500 次评估而黑色虚线垂直线描绘了在排名前 10 的最佳性能模型中使用的特定参数值。绿色虚线描绘的是没有使用交叉验证方法的最佳性能模型而红色虚线描绘的是使用交叉验证的最佳性能模型。让我们看下面的图。在其中一个子图中有参数subsample其值范围从 0.4 到 1.1。在 0.7 附近有一个明显的峰值表明贝叶斯优化更密集地探索了这些区域。我们最佳性能的模型似乎使用subsample0.72红色虚线。但还有更多值得看的。当我们现在看同一个子图但在下面的图中我们也有subsample其中每个点是 500 个模型之一。横轴是迭代次数纵轴是优化后的值。对于这个参数在优化过程的迭代中有一个明显的趋势。它首先探索了上界区域然后移向下界区域因为降低subsample值时模型得分明显更好。通过这种方式所有超参数都可以与不同模型关联起来进行解释。3.7 独立验证集上模型性能的解释为确保模型能在未见数据上泛化我们使用独立验证集。下图描绘了回归线预测结果没有显示出强异常值或持续的高估或低估。对于非常年轻的年龄组可能存在轻微低估因为模型预测的年龄比真实年龄更小。为了进一步调查我们最终模型的泛化能力我们可以使用.plot_cv()函数绘制 5 折交叉验证的结果。这将创建不同折的 ROC 曲线如图 5所示。在这里我们可以看到模型在不同折中的斜率或多或少相似。因此我们的最终模型在 k 折 CV 上没有表现出异常。3.8 最佳模型的决策树图通过决策树图我们可以更好地理解模型在分类中如何做出决策。它也可能提供一些关于这样的模型是否能泛化到其他数据集的直觉。请注意默认返回的是最佳树num_tree0但创建了许多树可以通过指定输入参数.treeplot(num_trees1)来返回。此外我们还可以绘制最佳性能特征如下图所示。特征女性性别、SibSp1 和parch1是预测年龄的前 3 个重要特征。3.9 对新数据进行预测在拥有最终训练好的模型后我们可以对新的未见数据进行预测。假设X是新数据并且已经像训练过程中一样进行了类似的预处理那么我们可以使用hgb.predict(X)函数进行预测。该函数返回分类概率和预测标签。# Make prediction predict hgb.predict(X.loc[0:2,:]) # Predicted Age array([24.329363, 44.43117 , 26.974583]) # True Age: print(y[0:3]) array([22., 38., 26.])4、保存和加载模型保存和加载模型可能很有用。为了实现这一点有两个函数hgb.save()和函数hgb.load()。# Save model status hgb.save(filepathhgboost_model.pkl, overwriteTrue) # [pypickle] Pickle file saved: [hgboost_model.pkl] # [hgboost] Saving.. True # Import library when using a fresh start From hgboost import hgboost # Initialize hgboost hgb hgboost() # Load the pickle file with model parameters and trained model. results hgb.load(filepathhgboost_model.pkl) # [pypickle] Pickle file loaded: [hgboost_model.pkl] # [hgboost] Loading succesful! # Make predictions again y_pred, y_proba hgb.predict(X)5、结束语在本指南中你学习了如何通过将数据集拆分为训练集、测试集和独立验证集来训练一个具有优化超参数的鲁棒机器学习模型。超参数优化在内部循环中使用贝叶斯优化进行而外部循环使用 k 折交叉验证来评估模型对未见数据的泛化能力。这种方法有助于识别最准确和最可靠的模型。在训练任何模型之前仍然重要的是遵循标准的机器学习工作流程执行探索性数据分析EDA、清理数据、工程有意义的特征以及应用特征选择。在实践中最大的性能改进通常是在这些预处理步骤中实现的而不是在模型调优本身。HGBoost支持回归、分类、多类学习和集成提升模型全部使用相同的鲁棒优化程序。在底层它依赖 Hyperopt 进行贝叶斯超参数优化尽管近年来 Optuna 等替代方案也变得越来越流行。我希望本指南为超参数优化和鲁棒模型选择背后的工作流程提供了清晰的概述。原文链接Boosting 回归模型超参调优指南 - 汇智网