ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

集成学习三大算法详解:Bagging、Boosting与Stacking原理对比

集成学习三大算法详解:Bagging、Boosting与Stacking原理对比 别忘了点“在看”呀今天这篇是写给我们自己人看的做机器学习这一行如果你问一个从业者“你在真实项目里最常用哪个模型”回答大概率不是某个花哨的深度学习网络而是一句平淡的“调个梯度提升树或者跑个随机森林”。这两个东西都属于集成算法Ensemble Learning。圈里有人喜欢用“三个臭皮匠顶个诸葛亮”来解释它也有人管它叫“集成学习大法好”但我觉得最传神的说法还是那句七个葫芦一条心。什么意思呢单个葫芦娃打架各有各的本事但也各有各的短板可一旦七个兄弟拧成一股绳连妖怪都得绕着走。集成算法就是这个套路多个弱学习器weak learner各自为战最后通过投票、加权、叠加等方式统一决策硬生生把“一般般”变成“很能打”。这篇文章不聊花架子直接拆解集成算法里的三种主流玩法——Bagging、Boosting、Stacking——把它们的原理、流程、参数直觉、工程坑位一次说透。适合正在学机器学习基础、准备做项目实战的新手也适合已经用过随机森林或XGBoost但一直没把底层逻辑理顺的老手。1. 集成算法的整体设计思路1.1 为什么单个模型总有种“力不从心”的感觉在聊集成之前先想清楚一个问题一个模型为什么会有误差机器学习里有个经典的偏差-方差分解Bias-Variance Decomposition可以把模型的泛化误差拆成三块偏差Bias、方差Variance和不可避免的噪声Noise。偏差大说明模型太简单对训练数据的拟合能力不足典型的欠拟合。方差大说明模型太敏感训练数据稍微抖一下预测结果就剧烈波动典型的过拟合。噪声是数据本身自带的任何模型都没办法消除。单个模型的问题在于你很难同时把偏差和方差都压得很低。拿决策树举例树很浅偏差大、欠拟合树很深方差大、过拟合。你调参调到半夜无非就是在“偏差”和“方差”之间找个能接受的平衡点。但是单个模型的容量有限平衡点附近的能力上限就在那里。那怎么办呢换个思路——既然一个模型搞不定那就别让它单打独斗了。多训练几个模型让它们互相弥补、互相纠错从统计上把误差摊薄。这就是集成算法最底层的动机。我自己的理解是集成学习本质上是在用“模型数量的冗余”换取“预测结果的稳定”这种思路在工业界特别好使因为工程上你没法保证拿到的是完美数据但你总能挤出时间多跑几个模型。1.2 集成起效果的两个必要条件准一点散一点不是随便把几个模型堆在一起就能变强的。葫芦七兄弟能打胜仗是因为每个人都有自己的绝活而不是七个一模一样的葫芦娃复制粘贴。集成算法有效必须同时满足两个条件第一基学习器的准确率至少要高于随机猜测。哪怕只是比瞎蒙好一点点这个基学习器就有贡献价值。第二基学习器之间要有足够的差异性。如果所有模型犯的错都一样投票的时候错的一边还是错的那边集成就没有意义了。这两句话看似简单其实是后面所有技术细节的出发点。Bagging通过样本扰动制造差异性Boosting通过样本权重制造差异性Stacking通过模型结构差异制造差异性。你看三兄弟的分岔路从这里就开始了。理解了“准一点散一点”再看任何集成方法的设计都不会觉得突兀。1.3 三条主流路线的性格差异集成算法发展到现在主流路线就三条打分如下路线代表算法串行/并行核心目标一句话性格Bagging随机森林并行降方差各干各的最后投票老大哥风格BoostingAdaBoost、GBDT、XGBoost串行降偏差后一个盯着前一个的错连环纠错Stacking模型融合层级组合优势让聪明人集体开会再请个高管拍板接下来三章我分别展开讲。2. Bagging各打各的最后投票2.1 自助采样法每个模型看到的“世界”都不太一样Bagging的全称是Bootstrap Aggregating直译过来就是“自助采样聚合”。这里的关键词是“自助采样”Bootstrap Sampling。什么叫自助采样给你一个包含N个样本的训练集每次从里面随机抽1个样本抽完放回去再抽下一个。重复N次得到一个新的训练集。因为是有放回抽样新训练集里可能有重复样本有些原样本则一次都没出现。数学上有一个经典结论当N足够大时每个新训练集大约包含原数据集63.2%的不重复样本剩下约36.8%的样本是没被抽中的。那些没被抽中的样本有个专门的名字叫“包外样本”Out-of-Bag简称OOB它们可以天然地当作验证集来用不需要额外划分验证数据这算是Bagging附带赠送的一个大福利。在每个基学习器的训练中用一份通过自助采样得到的“副本”数据来训练。因为每份副本的数据分布都略有差异基学习器之间就自然而然地产生了差异性。最后回归任务对所有基学习器的输出取平均分类任务做多数投票或者对各类别概率求平均再取最大。就这么简单粗暴。2.2 为什么Bagging能降低方差如果你手头有一组独立同分布的随机变量每个变量的方差都是σ²那它们的平均值方差就是σ²/k。只要k足够大平均值的波动会越来越小。这就是统计学里的基本事实也是Bagging降方差的理论根基。但这里有一个容易误导人的地方Bagging里的基学习器并不是真正独立的因为它们都来自同一份原始数据的自助采样副本而且底层的模型同质比如都是决策树所以它们之间其实存在正相关性。那降方差的效果就要打折扣。相关系数ρ越高集成的方差下降越有限。所以Bagging的效果上限很大程度上取决于你能不能把基学习器之间的相关性压下去。而这正是随机森林Random Forest做得最漂亮的地方。2.3 随机森林的“双重随机”随机森林在Bagging的基础上加了第二重随机性不仅在样本层面做自助采样在特征层面也做了随机选择。具体来说每次分裂决策树的一个节点时不是从全部m个特征里找最优分裂特征而是先从全部特征中随机抽出k个特征k通常取根号m或log2m再在这k个候选特征里挑选最优分裂。这一手非常聪明。如果只用样本扰动遇到特征特别强的场景所有树都会优先用那一个强特征分裂树与树之间长得差不多相关性很高集成的方差下降效果就被削弱了。加了特征随机之后即便最强特征还在大部分树也不一定能选中它分裂时被迫使用其他特征树与树之间的差异就大了。实践里随机森林往往是决策树Bagging的一个显著升级版深层原因就在这里。2.4 为什么Bagging的最佳搭档是决策树细想一下Bagging对基学习器的要求是“高方差、低偏差”。什么意思呢基学习器得足够敏感数据一扰动学习器输出的变化要比较明显否则集成根本产生不了多样性。而决策树天然就有这个脾气树一深还原训练数据还原得特别彻底方差很高但对训练集的拟合能力也强偏差很低。如果换成线性模型或者KNN这种稳定模型你换一份自助采样副本它学出来的模型可能几乎没变化那Bagging就白搞了。所以实际工程中Bagging的基学习器基本默认决策树尤其是CART树。这不是巧合是性质匹配。实操中还有一个非常值得关注的点如果用Bagging可以让每棵树长得非常深甚至不剪枝让它充分拟合训练集把那个“高方差”的性格发挥出来然后靠集成去平抑方差。这跟Boosting恰好相反后面我会讲到。2.5 包外样本评估与实战心得我之前在某图像处理Demo项目里想快速评估随机森林的效果但又不想额外划分验证集就用了OOB评估。具体做法训练过程中记录每个样本是否被某棵树的自助采样副本包含。对样本x只用那些没有在训练时见过x的树对x做预测最后集成起来作为OOB预测。这个OOB误差和交叉验证误差高度接近但成本低很多。实际操作里直接用random forest框架的话一个参数oob_score设为True就能拿到OOB分数。这个指标特别适合做超参数粗筛比如快速比较树的数量、最大特征数哪个设置更好。用OOB先粗筛一把确定一个候选区间再拿交叉验证精调比每一步都跑交叉验证省了不知道多少时间。3. Boosting连环纠错步步为营3.1 Boosting和Bagging最大的区别Boosting跟Bagging走了完全相反的路Bagging并行建树Boosting串行建树Bagging追求降低方差Boosting追求降低偏差。Boosting的基本流程是先用初始数据训练一个弱学习器然后根据当前学习器的表现调整训练样本的权重或目标值让下一个基学习器更关注之前做错的样本。如此反复迭代最后把所有基学习器加权组合起来。这个思想可以概括成一句话后一个模型站在前一个模型的肩膀上专挑前一个的软肋打。所以你最终得到的不是一个各管一摊的团队而是一个纠错链条所有模型合在一起共同逼近一个更准确的函数形态。3.2 AdaBoost从“改权重”开始的经典版本AdaBoostAdaptive Boosting自适应提升是最早的Boosting算法之一拿到的目标不是直接预测而是“让模型把注意力放在错得最多的样本上”。它的核心流程分三步第一步给每个训练样本初始化一个权重通常都是1/N。第二步用当前带权样本训练一个基学习器计算它在训练集上的加权错误率ε。根据错误率计算这个学习器的权重α公式为α0.5×ln((1-ε)/ε)。这个权重表示“这个学习器说话的分量”。第三步根据模型是否正确预测每个样本更新样本权重。被分错的样本权重乘上e^α分对的乘上e^(-α)最后归一化。简单说错得越多的样本下一轮在样本里占的比例越大。迭代T轮后得到T个基学习器及其权重α。集成预测时每个基学习器按α加权投票。AdaBoost训练到后期样本权重的分布会变得非常极端——那些极难分类的样本权重会累积得非常夸张这既是它抗不过噪声的原因也是后面改进版本要解决的问题。3.3 换个角度看AdaBoost加性模型如果只看AdaBoost的步骤觉得像某种启发式的权重调整。但从宏观视角看AdaBoost是典型的加性模型Additive Model最终模型是一堆基学习器的加权和。它本质上是在做函数空间上的梯度下降优化的损失函数是指数损失L(y,f(x))e^(-yf(x))。这个角度非常关键因为它直接引出了GBDT的核心逻辑既然Boosting是在做函数空间梯度下降那能不能不限定损失函数任意给定一个可导损失都用梯度下降的方式去拟合一个弱学习器呢答案是能这就有了Gradient Boosting。3.4 GBDT用负梯度做“伪残差”GBDTGradient Boosting Decision Tree的训练思路和AdaBoost看起来很不一样但其实一脉相承。每一轮迭代中我们不是修改样本权重而是根据当前集成模型对每个样本的预测值计算损失函数关于预测值的负梯度然后用一棵决策树去拟合这个负梯度。当损失函数取平方损失时这个负梯度恰好等于真实值减预测值也就是残差。所以对平方损失而言GBDT每轮就是在拟合残差。但换成其他损失函数比如对数损失、Huber损失负梯度就不是残差那么简单了。所以业界管它叫“伪残差”。所有框架的负面效果都一样每轮新训练一棵树让整体的预测沿着损失下降最快的方向前进这是FLOW的求导思想在函数空间的应用。实际操作中还有个要记得的点GBDT通常用一个较小的学习率η比如0.01到0.1来缩放每一棵树的贡献即新模型旧模型η×当前树。这不是为了好玩而是为了给后面的迭代留出空间。如果学习率太大前面几轮就把损失压到很低后面继续纠错的空间被压缩很容易过拟合。这个小细节我踩过很多次坑后面在“参数直觉”里细说。3.5 树模型在Boosting里的角色差异在Bagging里我们鼓励树长得深让方差爆发出来。但在Boosting里基学习器恰恰要用“弱”的——所以实际工程里GBDT的树一般都很浅常用的max_depth是3到8。这里面的道理是Boosting的核心是靠大量弱学习器一点点纠偏每一步走小一点方向更精一点树太深单棵树拟合能力太强前面几轮就把训练集拟合得七七八八后面要么过拟合要么把噪声也学进去了。所以我自己在调GBDT类模型包括XGBoost、LightGBM时习惯性先把max_depth调小然后通过控制n_estimators和学习率来整体平衡拟合能力。树的数量不是越多越好也不是越少越好得看着验证集曲线决定。但是如果你发现验证集提升非常缓慢先别急着堆树看看是不是学习率设置得太小了。注意Boosting系模型对数据中的异常值非常敏感。原因很简单每一轮迭代都会把权重或梯度集中在“难拟合”的样本上如果这个难拟合的样本本身是噪声那Boosting就是在强行记住垃圾信息。使用前一定要做异常值筛查至少也要用对异常值不太敏感的损失函数比如Huber损失。4. Stacking让聪明人开完会高管拍板4.1 什么是Stacking如果说Bagging和Boosting解决的是“同一类模型的集成”问题那Stacking解决的是“不同类模型怎么融合”的问题。它的思路很直白先用多个异构的基学习器比如逻辑回归、KNN、决策树、SVM在训练集上分别训练每个基模型都对样本产生一个预测结果然后把这些预测结果作为新的特征拼接成一个“次级训练集”再用一个元学习器meta-learner在这个次级训练集上训练学习“不同基模型的结果如何组合最优”。听起来就像开一个评审会各个基模型是不同领域的专家每个专家先独立给意见最后有一个高管元学习器综合所有人的意见做最终决策。这个高管不关心原始特征是什么只看每个专家的意见。所以Stacking的核心是“组合权重的学习”。4.2 为什么要用交叉验证来生成“次级训练集”这是Stacking里最容易被初学者踩爆的坑。如果你让基模型在全部训练集上训练然后用它对训练集本身做预测把预测结果当作次级特征去训练元学习器那必然会发生严重的过拟合。因为基模型已经在训练集上“见过”这些样本了预测结果里带着大量“背答案”的信息元学习器学到的规律在真实数据上根本不成立。解决办法就是K折交叉验证。以5折为例把训练集分成5份每次拿4份训练基模型对剩下1份做预测。重复5次每个样本都会得到一次“模型在没看过它的情况下”的预测结果。把这些跨折预测拼接起来作为次级训练集的特征。测试集呢方法是用同一个基模型在每个折上训练出的5个版本分别对测试集做预测取平均作为测试集的次级特征。这个方法多出一大块训练开销——每个基模型要训练K次而不是1次。但没办法这属于“保命操作”不做数据就泄露模型上线就翻车。我在某跨平台系统里亲眼见过一个让人欲哭无泪的场景某同事图省事用全量训练集拟合基模型后直接在训练集上生成次级特征训练集上元模型分数漂亮得不行上线后效果直接崩盘一夜之间从90分变60分。后来改成5折交叉验证生成特征才恢复正常。4.3 基模型的多样性和元学习器的选择Stacking要想效果好基模型之间的差异性非常重要。如果你把五个一模一样的逻辑回归放在一起Stacking那跟单个逻辑回归没什么区别。实际操作中我会刻意选择不同类型的模型比如线性模型逻辑回归、岭回归、非线性核模型SVM、树模型随机森林、GBDT、近邻模型KNN、以及简单的神经网络MLP。让每一个模型从不同的角度观察数据元学习器才有可学习的素材。元学习器本身不建议太复杂。因为次级特征维度通常不高基模型个数个到几十个而且基模型的预测结果之间可能存在较强的相关性。元学习器用简单的逻辑回归或线性模型比较稳妥目的是学习组合权重而不是再一次引入大量非线性变换。如果有人把元学习器也搞成一个很强的GBDT很容易在次级特征上过拟合。另外有个实操细节Stacking里基模型的预测结果最好确保是概率值而不是硬类别标签。硬标签只有0和1信息量太低而且容易丢失各个模型内部对不确定性的度量概率值比如某样本属于正类的概率是0.73保留了更多信息元学习器可以更好地捕捉模型的置信度。分类任务中这一点非常关键。4.4 Stacking的时间成本大家得有个心理准备Stacking的时间成本大概是单独训练一个模型的好几倍具体取决于基模型数量和交叉验证折数。假设你选5个基模型、5折交叉验证那实际训练次数就是5×525次训练再加元学习器1次总计26次。还要考虑每次训练的时间可能是单模型的数倍。在时间预算紧张的工业环境里Stacking通常不是首选除非单模型已经压不动了或者你手头有充足的计算资源。我个人的经验是Stacking比较适合放在比赛冲刺阶段或上线前的最终模型融合阶段不适合放在日常实验迭代中。日常迭代用单个强模型比如LightGBM快速试错最后确定几个差异性较大的强模型做Stacking。这个顺序反过来就会让自己陷入“洗不完的试错循环”。5. 三种集成方案横向对比5.1 关键维度对照维度BaggingBoostingStacking基学习器同质通常是决策树同质通常是浅决策树异质多种模型训练方式并行串行层级主要降低方差偏差组合误差对噪声敏感度较低很高中等训练成本中中高高可解释性尚可特征重要性尚可特征重要性较差最常用场景高方差数据特征多结构化表格数据比赛冲刺、精度极限5.2 如何根据项目选型如果你是做结构化表格数据、特征里有大量数值和类别变量目标是最小化预测误差那Boosting系尤其是LightGBM或XGBoost通常是默认首选我踩过的大部分表格类项目最后都是这俩在撑场子。如果数据噪声比较大特征维度很高而且你比较关注训练稳定性那随机森林这类Bagging方案往往比单棵决策树好得多而且不容易过拟合。如果你已经是多轮比赛老兵对粗糙度不敏感那就考虑Stacking收尾。这三种方案不是互斥的。事实上很多成熟方案是“两层套娃”底层用随机森林上层再做Boosting或者先用Boosting跑出一个强模型再和别的模型做Stacking。集成算法本来就是用来灵活组合的不用拘泥于“只能用某一种”。6. 工程实战中的坑位与排查清单6.1 特征扰动与样本扰动的边界提到Bagging大家容易忽略一个点Bagging里的基学习器不仅可以用样本扰动还可以用特征扰动。随机森林同时用了两者。但在某些场景里样本扰动带来的收益已经很小比如样本量非常大、采样后每份子集长得差不多这时候可以试试加大特征扰动从全部特征变成随机抽一部分特征训练每棵树。我这里说一个不太常见的做法每棵树随机用80%的特征训练会比固定用全部特征更容易制造多样且对缺失特征的鲁棒性也更好。6.2 Boosting类模型训练时的经典报错与对策我在实际项目中遇到过几个很典型的Boosting报错列一下排查思路损失不降训练集上误差率始终居高不下。先查学习率是不是太大或太小。学习率太大模型在迭代过程中震荡不收敛学习率太小迭代步数不够还没到极小值就结束了。我一般从0.05到0.1起步结合早停机制动态决定迭代轮数。验证集上比训练集差一大截。这通常是过拟合的信号。除了调小最大深度外还要查一下是否加足了正则化参数叶子节点权重、L1/L2正则。XGBoost和LightGBM都有对应的正则项别只用默认值。特征重要性畸变个别类别型特征被疯狂使用。检查类别特征的处理方式分箱切分过细容易导致模型抓住噪声。换成学习率更低、迭代更多的方式可能会改善。6.3 Stacking里的“时间放大器”问题Stacking有一个特别坑的工程问题如果你用5个基模型、5折交叉验证那相当于把单模型训练成本乘以25。如果每个基模型训练本来就要1小时Stacking一套跑下来将近一天再加上调参迭代一不留神就变成“训练一周、崩溃一秒”。我建议在进入Stacking之前先对每个基模型做严格的时间预算评估能并行就并行多个基模型可以并发训练实在不行就减少折数到3折或者选更轻量的基模型比如用逻辑回归替换深度网络。6.4 别忘了做加权平均这个“穷人版集成”最后分享一个压箱底的经验在考虑上复杂Stacking之前先试试加权平均集成。这是一个成本极低但效果往往出乎意料的方法把两个或三个强模型的概率预测或回归预测值做加权平均权重用验证集搜索。做这个操作大概只需要10分钟有时候效果已经能逼近完整的Stacking。因为很多基模型之间的误差确实存在互补性一个简单的线性融合就足以把涨点收进口袋。我自己在好几个项目里的体会是集成算法的价值不在于多花哨而在于“把不同模型的优点组合起来”。好比你带团队每个组员都未必是全方位的顶尖高手但只要各有所长、相互信任、目标一致最后做出的成绩一定比任何一个人单兵作战都好。七个葫芦娃能赢靠的不是某一个娃的神力而是七个人一条心。做模型也是这个道理。从最小可用起步先用单模型跑通基线再上Bagging或Boosting看看增益最后再考虑Stacking。每一步都记录训练时间和验证集分数清晰知道自己每一步在干嘛踩坑也踩得明明白白。集成学习这条路真不复杂贵在把基础原理想透再动手。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表