ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

集成学习完全指南:从Bagging到XGBoost、LightGBM与CatBoost

集成学习完全指南:从Bagging到XGBoost、LightGBM与CatBoost 做竞赛、搞建模或者调模型调到头秃的朋友一定绕不开集成学习。我在实际项目里试过单一模型死磕到极致最后评分纹丝不动反而是一顿 bagging、boosting 组合拳下去线上指标直接涨了一截。这篇总结想把我对集成学习从原理到代码的理解完整梳理一遍覆盖 bagging、随机森林、AdaBoost、GBDT、XGBoost、LightGBM 和 CatBoost把每个算法的动机、数学直觉、关键参数和真实代码一次性讲清楚。这篇文章适合正在入门机器学习、准备算法面试、或者已经在用 sklearn/xgboost 但不知道背后在发生什么的人。我不打算讲成教科书尽量用实际场景和踩坑经历来说话。毕竟集成学习的核心思想其实特别朴素一个模型拿不准的事多叫几个模型投票或者接力整体就能稳很多。但“多叫几个”这件事背后有门道。1. 集成学习的设计思路与算法谱系集成学习之所以有效根子在于“偏差-方差”这对矛盾。单一决策树如果长得太深过拟合风险高方差大如果长得太浅拟合能力不够偏差大。单模型要么偏科要么不稳定而集成学习就是通过组合多个基学习器来同时压低偏差和方差或者在不同维度上做补偿。1.1 从偏差-方差分解看两个流派偏差描述模型预测值和真实值的差距方差描述模型在训练集变动时的波动程度。Bagging 流派的核心思路是降低方差对训练数据进行有放回采样训练出多个独立的模型最后取平均或投票。即使每个模型方差大只要它们之间的误差相关性较低平均之后方差就会显著下降。Boosting 流派则把重心放在降低偏差上逐个训练模型每个新模型重点学习前面模型没做对的部分最后把所有模型加权组合起来。这类方法能一步步把拟合能力撑上去但方差控制不如 bagging 自然所以实际使用时常搭配正则化、学习率、早停等手段来抑制过拟合。1.2 基学习器与样本权重的配合不管是 bagging 还是 boosting基学习器最常用的都是决策树。原因是决策树对特征尺度不敏感能够自动处理非线性关系而且可以很方便地扩展成随机森林或提升树。逻辑回归、KNN 这类模型也可以做基学习器但实际工程里很少见因为集成带来的收益没有树模型明显。从算法谱系上梳理一下bagging 的典型代表是随机森林boosting 的典型代表是 AdaBoost、GBDT、XGBoost、LightGBM、CatBoost。前者的关键词是“并行训练平均结果”后者的关键词是“串行迭代逐步纠错”。理解了这条主线后面所有细节都能挂上去。1.3 为什么集成模型几乎成了默认选择在表格型数据上集成树模型的表现往往优于精心调参的单一深度学习模型。这不是玄学而是因为树模型天然擅长处理表格数据中的特征交互和缺失模式而集成机制又弥补了单棵树的稳定性不足。我在实际项目里的体感是先用随机森林快速建立基线然后上 LightGBM 或 XGBoost 精调大多数情况下分数就能达到预期。偶尔遇到类别特征特别多或者特征分布特别嘈杂的数据CatBoost 会表现得更好。这套流程已经成为团队的标准操作方案。2. Bagging 与随机森林并行集成的基石Bagging 这个名字来自 Bootstrap Aggregating。Bootstrap 是有放回抽样Aggregating 是聚合。它的做法说起来很简单从原始训练集里随机有放回地抽取多个子集每个子集训练一个模型最终预测时回归取平均、分类取投票。2.1 Bagging 为什么能降低方差有放回抽样带来的效果是每个子集和原始数据集有一定重叠但又不完全相同。这样得到的模型之间存在差异而差异正是降低方差的前提。数学上可以证明如果 N 个独立同分布的随机变量方差是 σ²它们的平均值方差就是 σ²/N。虽然基模型之间并不完全独立但只要有相关性小于 1取平均就能让整体方差下降。这一结论的直觉是每个模型都会犯不同的错把它们的错误平均掉一部分剩下的就是共识部分。实际使用中Bagging 对高方差模型比如深决策树、KNN的提升最显著对低方差模型比如线性模型提升不明显。2.2 随机森林的“双重随机性”随机森林在 bagging 的基础上加了一个关键改动每次分裂时不是搜索所有特征而是随机抽取一部分特征作为候选。这个做法让模型之间的差异进一步加大也间接降低树之间的相关性方差下降的效果更好。用我自己的话说就是bagging 只是让每棵树看到不同的样本随机森林还让每棵树看到不同的特征视角。这也是为什么随机森林比单纯的 bagging 决策树效果更稳定。随机森林回归算法的标准流程可以概括为从训练集中有放回抽样生成 n 个样本子集。对每个子集训练一棵决策树每次分裂时随机选取 m 个特征中最优的一个。重复训练 n_estimators 棵树。回归预测时对每棵树的输出取平均分类时采取投票或按概率平均。决策树和随机森林的关系可以这样理解决策树是砖头随机森林是盖好的墙。单看一块砖可能不够结实但很多砖按规则垒起来墙就稳了。2.3 随机森林回归与分类代码实战先用 sklearn 展示随机森林回归模型的基本用法我用的示例数据集是经典的波士顿房价替代方案sklearn 已经移除波士顿数据集用加州房价数据来演示。from sklearn.datasets import fetch_california_housing from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import mean_squared_error data fetch_california_housing() X_train, X_test, y_train, y_test train_test_split( data.data, data.target, test_size0.2, random_state42 ) rf RandomForestRegressor( n_estimators200, max_depth12, min_samples_leaf4, max_features0.7, n_jobs-1, random_state42, ) rf.fit(X_train, y_train) pred rf.predict(X_test) print(RMSE:, mean_squared_error(y_test, pred, squaredFalse))这里几个参数是实际调参时的重点。n_estimators太小时方差压不下来一般 100 到 500 之间比较常见超过一定数量收益就递减了。max_features控制每次分裂考虑的特征数回归里常用特征总数的三分之一左右分类里常用根号特征数。min_samples_leaf则控制叶子节点最少样本数设得大一点能明显抑制过拟合但也不能太大否则欠拟合。我对随机森林最常用的一句评价是它是个几乎没有太多玄学参数的模型默认参数下就有不错表现特别适合作为项目基线。但它也有明显的短板——对噪声特征敏感对特征含义的解释性远不如单棵决策树。如果项目要求很强的可解释性就需要权衡。2.4 Bagging 的一种手写最小实现学术上理解更透彻的方法是自己手写一遍 bagging 流程。下面我用 numpy 和 sklearn 的决策树封装一个最小版本帮你直观感受“真有放回采样”的过程。import numpy as np from sklearn.tree import DecisionTreeRegressor class SimpleBaggingRegressor: def __init__(self, n_estimators50, max_samples0.8, max_depth6): self.n_estimators n_estimators self.max_samples max_samples self.max_depth max_depth self.trees [] def fit(self, X, y): n len(X) sample_size int(n * self.max_samples) for _ in range(self.n_estimators): idx np.random.choice(n, sample_size, replaceTrue) tree DecisionTreeRegressor(max_depthself.max_depth) tree.fit(X[idx], y[idx]) self.trees.append(tree) def predict(self, X): preds np.mean([tree.predict(X) for tree in self.trees], axis0) return preds这个实现和 sklearn 的 BaggingRegressor 差了很远但核心思路完全一致。你把这个类放到实验里跑一下就能看到即便每个决策树都长得比较浅bagging 之后的整体效果依然稳定。这就是并行集成最朴素的力量。3. AdaBoost 到 GBDT提升方法的进化路径如果说 bagging 是靠“组合”来降低方差那 boosting 就是靠“纠错”来降低偏差。boosting 每次迭代都会重点关注前一轮分类错误的样本逐步把整体预测边界修得更好。3.1 AdaBoost 的样本权重迭代AdaBoost 的想法很直观每一轮训练结束后增加被分错样本的权重减少被分对样本的权重然后带着这套权重继续训练下一个弱学习器。这样每个新学习器都会把注意力集中在之前搞不定的那种样本上。最终预测时每个学习器按照其分类精度进行加权投票。用带权重的逻辑来理解分类精度高的弱学习器在最终投票里嗓门更大分类精度很低的即使没被淘汰话语权也小。我早期学 AdaBoost 的时候一直有一个疑问弱学习器怎么接收权重答案在于不同框架的处理方式不同。sklearn 里的 AdaBoostClassifier 会直接让基学习器的 fit 方法接收 sample_weight 参数而在理论推导里权重是通过重采样来体现的。下面是 sklearn 的 AdaBoost 分类示例from sklearn.ensemble import AdaBoostClassifier from sklearn.tree import DecisionTreeClassifier from sklearn.datasets import make_classification from sklearn.model_selection import cross_val_score X, y make_classification( n_samples1000, n_features20, n_informative15, random_state42, ) base DecisionTreeClassifier(max_depth1) ada AdaBoostClassifier( estimatorbase, n_estimators200, learning_rate0.5, random_state42, ) scores cross_val_score(ada, X, y, cv5, scoringaccuracy) print(CV Acc:, scores.mean())树深设为 1 的决策树也叫“树桩”只做一个特征的判断属于典型的弱学习器。有人会问既然每棵树都这么弱组合起来怎么会强答案就在 sample_weight 的迭代策略里每一轮都在补短板补到最后边界就被修得很精细了。3.2 GBDT 如何用负梯度定义“错误”GBDT 的全称是 Gradient Boosting Decision Tree。它把 boosting 思想推广到了任意可微损失函数上。核心思路是每一轮训练一棵决策树去拟合当前损失函数的负梯度方向。在平方损失场景下负梯度刚好等于残差在其他损失函数下负梯度是残差的广义化。这个思想的精妙之处在于我们不需要为每个损失函数去设计专门算法只需要算出负梯度后续的树拟合流程完全一样。因此 GBDT 能统一处理回归、二分类、多分类、排序等任务只要损失函数可导。GBDT 的训练过程可以概括为用一个常数或平均值初始化模型。计算当前模型在训练样本上的负梯度。用一棵决策树拟合这个负梯度构造出树结构。沿着树的输出方向更新模型通常乘以学习率。重复步骤 2 到 4直到达到预设的树数量或验证集指标不再提升。3.3 手写一个最小 GBDT 回归来理解残差拟合为了说明 GBDT 的本质我写过一个最简版本的梯度提升回归器。它没有做复杂的剪枝仅仅演示“拟合残差”这个过程。import numpy as np from sklearn.tree import DecisionTreeRegressor class SimpleGBRT: def __init__(self, n_estimators50, learning_rate0.1, max_depth2): self.n_estimators n_estimators self.learning_rate learning_rate self.trees [] self.base_pred None def fit(self, X, y): self.base_pred np.mean(y) current np.full(len(y), self.base_pred) for _ in range(self.n_estimators): residual y - current tree DecisionTreeRegressor(max_depthself.max_depth) tree.fit(X, residual) self.trees.append(tree) current self.learning_rate * tree.predict(X) def predict(self, X): pred np.full(len(X), self.base_pred) for tree in self.trees: pred self.learning_rate * tree.predict(X) return pred注意这里每棵树拟合的是y - current也就是残差。对平方损失来说这就是负梯度。如果你把这个类在带噪声的曲线数据上跑一下会发现 n_estimators 越大、学习率越小拟合曲线的细腻程度越高。这也解释了 GBDT 需要同时控制学习率和树数量树太多而且学习率太高很容易过拟合。实际上 sklearn 的GradientBoostingRegressor就是在这个思想上做了大量优化比如对每棵树乘收缩系数、子采样、分子区域用线性规划求最优输出值等。你理解了最小版本再去看官方文档里的参数就全都能对上了。4. XGBoost、LightGBM、CatBoost三大梯度提升框架的对比与实战到了工程应用阶段我们一般不再自己去写方案而是直接使用高度优化的框架。XGBoost、LightGBM、CatBoost 都属于 GBDT 的工程化变体但在优化策略和适用场景上有明显差异。4.1 XGBoost二阶导加正则化的工程范本XGBoost 对 GBDT 最重要的改进是加入了正则项并且对损失函数做二阶泰勒展开。一阶导数告诉我们该往哪个方向走二阶导数还告诉我们应该用多大胆的步子。这个信息让每棵树的叶子节点输出值可以直接用解析方式求解整体收敛路径更稳健。XGBoost 在搜索最优分裂点时使用的是预排序加加权分位数近似。简单来说它会对特征值进行排序缓存梯度统计量然后寻找最大增益的分裂点。这个过程准确度高但排序的代价也高所以 XGBoost 的训练速度通常比 LightGBM 慢一些。XGBoost 很著名的功能是它自带缺失值处理在寻找分裂节点时如果样本特征缺失模型会自动学习缺失值应该往左还是往右走。这比手动填充均值要精细得多。我在实际项目里发现xgboost 会处理空值这件事非常实用。传统处理流程要先做缺失值填充如果填充策略不恰当反而引入噪声。XGBoost 的稀疏感知算法会自动为缺失值学一个最优的方向这也是为什么同样的数据直接丢给 XGBoost 往往不会太差。下面是一个 xgboost 二分类模型的完整示例包括早停设置和特征重要性查看import xgboost as xgb from sklearn.datasets import make_classification from sklearn.model_selection import train_test_split from sklearn.metrics import roc_auc_score X, y make_classification( n_samples2000, n_features30, n_informative20, n_redundant5, random_state42, ) X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42 ) dtrain xgb.DMatrix(X_train, labely_train) dtest xgb.DMatrix(X_test, labely_test) params { objective: binary:logistic, eval_metric: auc, eta: 0.05, max_depth: 5, subsample: 0.8, colsample_bytree: 0.7, lambda: 1.0, } bst xgb.train( params, dtrain, num_boost_round1000, evals[(dtest, test)], early_stopping_rounds50, verbose_eval50, ) pred bst.predict(dtest) print(AUC:, roc_auc_score(y_test, pred)) print(Feature importance:, bst.get_score(importance_typegain)[:5])这里eta就是学习率它和num_boost_round是一对组合学习率设小一点训练轮数就要相应加大。colsample_bytree控制每棵树随机选取的特征比例是 XGBoost 里降低方差的重要参数。lambda是 L2 正则化系数用于控制叶子节点权重衰减。xgb 可以做 nonlinear feature transformation指的是通过对特征分裂点进行自动分段让目标变量和特征的复杂非线性关系被捕捉。这种“非线性特征变换”能力来自树模型天然的特征交互学习不需要我们手动去做多项式特征或分箱特征。换个角度来说树模型本身就是一种可学习的特征变换器。4.2 LightGBM直方图加速和 Leaf-wise 生长LightGBM 和 XGBoost 最大的区别在于分裂点的搜索策略。LightGBM 使用直方图算法把连续特征离散化成了固定数量的桶在桶级别上统计梯度信息大幅减少了计算量。同时它用互斥特征绑定技术合并稀疏特征进一步降低内存占用。另外一个显著差异是树的生长方式。XGBoost 一般按层生长Level-wise而 LightGBM 采用叶子生长Leaf-wise每一轮从当前所有叶子节点中选择分裂增益最大的那个叶子来分裂。这样做的好处是可以在相同树深度下获得更好的拟合效果缺点是如果不限制叶子数量和树深度很容易过拟合。所以 LightGBM 提供了两个非常关键的参数num_leaves和min_data_in_leaf。实际调参时不是先去调学习率而是先把num_leaves控制在一个合理范围比如 31 到 127 之间然后设置min_data_in_leaf来防止过小叶子继续分裂。LightGBM 的 rank 和 xendcg 也是竞赛里经常被提到的问题。LightGBM 支持排序任务目标函数是 LambdaRank评价指标常用 ndcg对应名字里有 xendcg 相关度量。做搜索排序、推荐排序任务时LightGBM Ranker 的用法和分类回归略有不同import lightgbm as lgb import numpy as np from sklearn.datasets import make_regression X, y make_regression(n_samples500, n_features10, random_state42) groups [100] * 5 lgb_train lgb.Dataset(X, labely, groupgroups) params { objective: lambdarank, metric: ndcg, ndcg_eval_at: [1, 3, 5], learning_rate: 0.05, num_leaves: 31, min_data_in_leaf: 20, } model lgb.train( params, lgb_train, num_boost_round100, )这里group指定每个查询下有多少条样本排序模型的输入数据必须是按 query 分组的。训练完成后的预测结果是一个分数按分数排序得到最终列表。LightGBM 保存到本地 txt 的模型文件也是实际工作中绕不开的问题。模型本质是一堆文本格式的树结构你可以直接用model.save_model(model.txt)保存再用model lgb.Booster(model_filemodel.txt)加载。这个 txt 文件里能直观看到每棵树的树结构比如分裂特征、分裂阈值和叶子节点输出值。有人问我 C# 调用 Python 生成的 lightgbm 的 txt 模型这个问题。可行的做法是用 Python 端把模型保存为 txt 或 JSON然后 C# 项目中通过 LightGBM 的 C API 加载这个模型文件或者使用 LightGBMSharp 这类封装库。关键是模型文件格式是跨语言的不依赖 Python 运行时这也是训练和推理解耦的基础。我补充一个 Python 保存模型再检查树个数的示例import lightgbm as lgb model lgb.LGBMRegressor(n_estimators100, num_leaves31) model.fit(X_train, y_train) model.booster_.save_model(lgb_model.txt) loaded lgb.Booster(model_filelgb_model.txt) # 查看树个数 print(Tree count:, loaded.num_trees())可能有人担心保存成 txt 文件会丢失某些信息。其实不会save_model会完整保存树结构、目标函数、特征名称等关键信息加载后可以直接用于预测。之所以默认后缀是 txt正是因为它是文本格式方便跨平台使用和手动查看。4.3 CatBoost有序提升与类别特征内建处理CatBoost 最招牌的能力是自动处理分类特征。你不需要手动做 one-hot 编码只要在训练时传入cat_features参数它内部会基于目标统计和有序提升原则对类别特征做编码减少信息损失。另一个特点是它采用对称树结构每棵树的每一层使用相同的分裂特征和分裂阈值。这个限制看似会让单棵树表达能力下降但配合有序提升后整体模型的泛化性能往往更好而且在推理时可以做大幅度的加速和向量化。CatBoost 的有序提升针对的是 GBDT 里的一个隐藏问题在每一轮用当前模型打预测时训练样本的预测值往往已经“偷看”了自身标签导致梯度估计产生偏移。CatBoost 通过随机置换样本顺序用序列中前一部分样本对后续样本做预测从而减少这种偏移。我用 CatBoost 处理含大量类别特征的数据集时体感确实比手动编码更省心泛化也更好。它在金融风控、用户行为预测这类场景里表现很亮眼。下面是一个带类别特征的示例from catboost import CatBoostClassifier import pandas as pd df pd.DataFrame({ feature_num: [1.0, 2.0, 3.0, 4.0, 5.0], feature_cat: [A, B, A, C, B], label: [0, 1, 0, 1, 1], }) X df.drop(columnslabel) y df[label] model CatBoostClassifier( iterations100, learning_rate0.1, depth6, cat_features[feature_cat], verbose50, ) model.fit(X, y)注意cat_features需要传入类别特征的列名或索引。CatBoost 还有一个特点是对 GPU 训练支持友好在数据集较大的情况下可以明显提升训练速度。四大框架横向对比如下框架分裂查找方式树的生长方式类别特征处理缺失值处理核心优势XGBoost预排序分位数近似Level-wise需手动编码自动学习路径精度高、文档丰富、生态成熟LightGBM直方图Leaf-wise需手动编码自动处理训练快、内存低、支持排序CatBoost预排序目标编码对称树内建最优处理自动处理类别特征效果极佳、泛化稳定随机森林CART 分裂全部叶节点并行需手动编码需预处理快速基线、方差低4.4 三类框架的统一使用范式无论是 XGBoost、LightGBM 还是 CatBoost其实都遵循同一套训练范式构建 Dataset设置参数训练评估预测调参。掌握一个之后切换到另一个成本非常低。技术上的差异主要体现在训练速度和预测性能上。它们的相同点更多都是 GBDT 的改进版存在“学习率、树数量、树复杂度”这一组核心超参。都支持早停用验证集指标控制训练轮数。都输出特征重要性可以用于特征选择。都支持 GPU 训练在大数据集上能够明显缩短实验周期。落到实处你在项目里的选择逻辑可以很简单想要快速验证的时候先上随机森林作为 baseline。追求最优精度且特征数量中等、数据量不是特别大的时候可以试 XGBoost。数据量很大且特征很多优先 LightGBM。数据里有很多高基数类别特征并且不想做繁琐编码时直接用 CatBoost。5. 常见问题与排查技巧实录写了这么多年代码训练了无数个集成模型下面这些问题是我实际踩过的坑。整理成速查表直接参考。5.1 为什么 xgboost 会处理空值但我手动填充效果反而更差XGBoost 的空值处理思路是在分裂时自动学两个方向缺失值样本究竟去左子树还是右子树以损失函数最小为准。手动填充均值或中位数时等于帮模型做了一个不够好的决定限制了模型的灵活性。所以如果你的数据缺失机制比较复杂先用 XGBoost 默认方案跑一版看过效果后再考虑要不要手动填充。5.2 LightGBM 的叶子生长策略为什么容易过拟合Leaf-wise 生长在每一轮都选增益最大的叶子分裂训练误差可以降得特别快但同时也更容易抓住局部噪声。解决办法很直接限制num_leaves同时设置min_data_in_leaf比如 20 以上。另外一个常用技巧是调低bagging_fraction和feature_fraction增加随机性防止模型过度记忆训练集。5.3 LightGBM 保存到本地的 txt 有什么特点txt 模型文件可以直接打开查看树结构方便排查“模型是否学习了异常分裂点”这类问题。它也可以被 C API 或其他语言加载因此你在 Python 里训练好的模型完全可以在服务端用 C# 加载预测。需要强调的是跨语言加载时保持特征列顺序一致非常关键否则预测结果就会难以理解。5.4 XGBoost 的非线性特征变换能力如何落地树模型会把连续特征自动离散化成一系列分裂点每个分裂点对应一个条件判断因此相当于自动构造了一组非线性转换后的特征。如果后续要把树模型和线性模型做融合可以用tree_predict得到每棵树对样本的叶节点位置转成 one-hot 特征后传给线性模型这种方式在 CTR 预估中经常用。5.5 随机森林回归和 XGBoost 回归如何选择随机森林回归的优势是训练快、无需太多调参、不容易过拟合适合作为基线。XGBoost 回归的优势是有学习率控制、有正则项、可以早停能够利用多轮迭代逼近更复杂的函数。建议先用随机森林建立预测值范围再切换 XGBoost 精调观察验证集指标是否真正改善。5.6 决策树和随机森林里的“随机”到底有什么区别决策树分裂时会在全部特征中选出最优分裂点随机森林则只在随机抽取的特征子集里找最优。这个差异会直接降低模型方差也是随机森林在保持较高准确率的同时不那么容易过拟合的原因。5.7 如何用 LightGBM 做排序任务rank 和 xendcgLightGBM 的排序目标函数是 lambdarank评价指标里 ndcg 是更常用的指标。使用lgb.Dataset(..., group...)时必须保证样本按 query 分组连续存放。ndcg_eval_at可以配置要看前几名例如 [1, 3, 5] 表示分别计算 NDCG1、NDCG3、NDCG5。训练完成后输出的是分数按分数降序排列得到最终排序结果。5.8 模型调参顺序有没有通用路径我常用的一套路径如下学习率先定在 0.1树数量通过早停自动决定。调树的复杂度参数如max_depth或num_leaves、min_data_in_leaf。调采样比例如subsample、colsample_bytree、bagging_fraction、feature_fraction。最后调正则化参数如 XGBoost 的lambda、alphaLightGBM 的lambda_l1、lambda_l2。验证稳定后再把学习率降到 0.01增大迭代轮数做一轮精细训练。这个顺序的背后逻辑是先粗调结构复杂度再引入随机性最后用正则化收尾。如果一开始就调正则化参数很难判断模型当前是欠拟合还是过拟合。5.9 特征重要性怎么解读才不踩坑XGBoost 的get_score(importance_typegain)返回的是每个特征作为分裂节点带来的平均增益数值越大说明该特征对损失下降贡献越大。LightGBM 的feature_importance(importance_typegain)逻辑类似。但注意只要某个特征被用于分裂其重要性通常都很高哪怕它只是和另一个重要特征高度相关。所以特征重要性更适合做筛查不适合直接做因果判断。5.10 树个数设置到多少才算合适树个数取决于学习率和问题复杂度。通常做法不是拍脑袋设一个固定值而是设置比较大的num_boost_round配合验证集做早停。如果早停轮数是 50意思是验证集指标连续 50 轮没有提升就停止训练这样树个数就是一个数据自适应结果而不是人为设定的随机数。最后想说的实际经验我在试这些集成算法时踩过不少坑比如一开始调 LightGBM 的num_leaves调到几百训练误差确实很低但线上测试回归很严重又比如一开始在类别特征上手动做 one-hot导致高基数特征爆炸后来换 CatBoost 省了非常多事。调试到后面你会发现集成学习不是“哪个算法更先进”的问题而是“哪个算法更匹配数据形态”的问题。对于新项目我现在的流程是先随机森林给出一个可靠的基线然后根据数据规模选择 LightGBM 或 XGBoost 精调遇到高基数类别特征就试 CatBoost。整个过程不看魔法看经验累积。希望这篇整理能帮你少走一些弯路也欢迎在实践中根据数据和业务做调整。
返回列表