4.2 模型集成方法深入 本节摘要:模型集成通过组合多个基学习器来获得比单个模型更稳、更准的预测。它分三大流派:Bagging 用自助抽样并行训练同质模型,靠平均来压低方差;Boosting 串行训练,后一个模型专门纠正前一个的错,靠迭代来压低偏差;Stacking 则训练一个元学习器,去学习"怎么把不同模型的输出再组合一次"。理解这三者的机制差异,以及它们各自在偏差和方差之间做的取舍,是选型的关键。 上手前先明确 阅读完本节,你应当能够: 用"偏差-方差"这套语言解释为什么单个模型会欠拟合或过拟合。 区分 Bagging、Boosting、Stacking 的训练方式和适用场景。 说清随机森林在 Bagging 基础上多加了哪一层随机性。
本节摘要:模型集成通过组合多个基学习器来获得比单个模型更稳、更准的预测。它分三大流派:Bagging 用自助抽样并行训练同质模型,靠平均来压低方差;Boosting 串行训练,后一个模型专门纠正前一个的错,靠迭代来压低偏差;Stacking 则训练一个元学习器,去学习"怎么把不同模型的输出再组合一次"。理解这三者的机制差异,以及它们各自在偏差和方差之间做的取舍,是选型的关键。
阅读完本节,你应当能够:
先跑一个我们都能复现的现象:拿一棵完全生长的决策树去拟合有噪声的数据,训练集上它能做到几乎零误差,可一换到测试集就原形毕露。为什么?因为它把噪声也当成了规律,记住了每一个孤例的脾气。这叫过拟合,根源是方差太大——数据换一批,这棵树就判若两人。
反过来,一棵深度只有一层的决策树桩又太钝,连基本的趋势都抓不住,训练集测试集都不行。这叫欠拟合,根源是偏差太大——模型家族本身就表达不了这个数据的规律。
单个模型总在这两端之间晃。集成的思路很朴素:别把宝押在一个模型身上。多找几个模型,让它们互相纠错、互相平均,整体反而稳下来。至于怎么"纠错"、怎么"平均",三大流派给出了三种完全不同的答案。
Bagging 全称 Bootstrap Aggregating,自助抽样聚合。做法是:从原始训练集里有放回地抽多个子集,每个子集训练一个基学习器,最后分类靠投票、回归靠平均。关键在"有放回"——这意味着有的样本会被抽到多次,有的样本一次都抽不到,每个基学习器看到的数据都不一样,于是它们犯的错也各不相同,平均之后错就抵消了。
它主要降方差。基学习器越"高方差"(比如完全生长的决策树),Bagging 的收益越大。训练可以并行,这是它相对 Boosting 的一大工程优势。
Boosting 反着来。它不并行,而是一轮接一轮地训练,每一轮的新模型都盯着上一轮模型犯错的样本——要么给错样本加权,要么直接去拟合上一轮的残差。AdaBoost 走前一条路,梯度提升走后一条路。
它主要降偏差。因为每一步都在逼近真实值,模型的表达能力被一点点榨出来。代价是串行,没法并行,训练时间更长。
Stacking 更聪明也更容易过拟合。它先训练一批不同类型的基模型(逻辑回归、决策树、支持向量机各来一个),再训练一个元学习器,去学习"这几个模型的输出该怎么加权、怎么组合才最准"。元学习器输入的是基模型的预测值,输出最终预测。
它跟 Voting 投票的区别在于:投票是人工定规则(硬投票多数决、软投票概率平均),Stacking 是让模型自己去学组合规则。好处是更灵活,坏处是数据不够时,元学习器很容易过拟合,需要交叉验证兜底。

在 Stacking 之前,还有种更简单的异质组合叫 Voting。它不训练元模型,直接用固定规则合并多个不同模型的预测——硬投票看多数票,软投票把各模型的类别概率取平均再取最大。软投票通常更准,因为它用上了置信度信息,而不是只看最终标签。
Voting 和 Stacking 的区别一句话:Voting 的合并规则是人工写死的,Stacking 的合并规则是让元模型学出来的。数据充足、想榨干异质模型的互补性,上 Stacking;数据一般、求稳求简单,Voting 就够。
理解"偏差-方差"这四个字,选型就不再靠感觉。我们把两类错误拆开看:
理想模型两者都低,但现实里它们常常此消彼长——调高复杂度,偏差降、方差升;调低复杂度,反过来。集成的意义就在这:Bagging 用"多个神经质模型取平均"来压方差,Boosting 用"弱模型层层逼近"来压偏差。
一个可落地的判断口诀:
| 症状 | 判断 | 先试谁 |
|---|---|---|
| 训练集好、测试集差 | 方差大,过拟合 | 随机森林、Bagging |
| 训练集测试集都差 | 偏差大,欠拟合 | 梯度提升、Boosting |
| 多个异质模型各有所长 | 想取长补短 | Stacking |
| 模型要可解释、要快 | 约束多 | 优先浅树或单模型 |
💡 关键直觉:别把集成当成"无脑堆模型"。它是对症下药——过拟合了用 Bagging 压一压,欠拟合了用 Boosting 提一提。方向搞反了,堆再多模型也是白堆。
知道原理后,上手其实就一两行。随机森林在 Bagging 基础上多加了"随机选特征"这一层,每个节点分裂时只在随机抽出的特征子集里挑最优,让树与树之间更不一样。
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier rf = RandomForestClassifier(n_estimators=100, max_features="sqrt", random_state=42) gb = GradientBoostingClassifier(n_estimators=100, learning_rate=0.1, max_depth=3, random_state=42) rf.fit(X_train, y_train) gb.fit(X_train, y_train)
这两行背后藏着两个最该调的参数。随机森林的核心是 n_estimators(树的数量)和 max_features(每次分裂考虑的特征数);梯度提升的核心是 n_estimators 与 learning_rate 这对联动参数。
n_estimators 加树,效果先升后平,成本线性涨。我的经验是从 100 起步,看误差曲线是否已经走平,平了就停。max_features 决定随机性强度,分类任务用 sqrt(特征数开方),回归任务常用全部特征或一个较大比例,是两条经过验证的默认值。
梯度提升里 learning_rate 和 n_estimators 是一根绳上的蚂蚱。学习率小,每棵树只迈一小步,需要更多树才能收敛,但通常更稳、更不容易过拟合;学习率大,几步就冲到位,却容易冲过头。所以调参时别单独调一个——学习率调小,树的数量就要相应调大,两者一起动。
⚠️ 常见坑:把
n_estimators拉到几千、learning_rate压到 0.001,指望"堆得越多越准"。结果训练时间爆炸,测试集却没再提升,甚至因为对噪声过度拟合而变差。正确姿势是配合早停或验证曲线,在误差走平处收手。
⚠️ 常见坑:拿 Bagging 去解决欠拟合。Bagging 只压方差,不降偏差——如果基模型本身太弱、训练集都拟合不好,并行再多个弱模型,平均出来的还是弱。欠拟合先去提升基模型能力,或者换成 Boosting。
Stacking 上手也不难,但它有个绕不开的坑:元模型拿到的输入是基模型在训练集上的预测,而基模型早就"见过"这些训练样本了,输出会偏乐观。直接喂给元模型,等于让它学一份带答案的考卷。解法是交叉验证——基模型的预测用交叉验证的方式生成,让元模型看到的每个预测都来自"没在对应样本上训练过"的模型。
from sklearn.ensemble import StackingClassifier from sklearn.linear_model import LogisticRegression from sklearn.tree import DecisionTreeClassifier from sklearn.svm import SVC base = [ ("lr", LogisticRegression(max_iter=1000)), ("dt", DecisionTreeClassifier(max_depth=3)), ("svc", SVC(probability=True)), ] stack = StackingClassifier(estimators=base, final_estimator=LogisticRegression(), cv=5) stack.fit(X_train, y_train)
这里 cv=5 就是那个防过拟合的开关。不设它,Stacking 在中小数据集上很容易翻车;设了它,基模型预测才干净,元模型才学得到真东西。
选型这件事,与其背一长串规则,不如先走一遍下面的判断流。核心就一步:先分清你的模型是欠拟合还是过拟合,方向对了,方法自然就出来了。
第一,看基模型是"太神经"还是"太笨"。太神经(过拟合)上随机森林,太笨(欠拟合)上梯度提升。
第二,看工程约束。要并行、要快、要部署简单,Bagging 系优先;能接受更长的串行训练、追求更高精度上限,Boosting 系优先。
第三,看数据量。Stacking 最吃数据,数据不够时它那层元学习器容易过拟合,收益还抵不过复杂度;数据充足、又想融合逻辑回归、树、支持向量机这些异质模型的所长,才值得上 Stacking。
最后补一句关于解释性:集成模型普遍比单棵决策树难解释,这是个实打实的代价。如果下游要拿模型给业务方讲"为什么这么判",先问一句——值不值得为了那两三个点的提升,丢掉可解释性。很多时候,一棵调好的浅树或一个逻辑回归,才是更务实的选择。
集成不是免费的午餐,把账算清楚再上也不迟。第一个代价是训练成本:随机森林要训上百棵树、梯度提升要串行训几百棵,算力和时间都比单模型成倍上涨;随机森林相对省心,是因为树与树之间能并行,梯度提升就只能一棵一棵排队。第二个代价是可解释性下降:一棵浅决策树能画出一条清晰的 if-else 路径,换成一个百棵树的森林,往往只能给你一张"特征重要性排序",业务方追着问"这一单为什么这么判"时,你很难给出一个干脆的答案。第三个代价是边际收益递减:第一棵树带来的提升最大,越往后越平,堆到最后常常是拿几倍的训练时间去换零点几个点的准确率,甚至因为对噪声追得太紧而反噬。所以我们的习惯是,先用一个调好的强单模型跑出基线,再用集成去够更高的上限,而不是一上来就上最重的家伙。
随机森林和梯度提升,谁更强?
没有绝对答案。数据干净、特征量适中时,梯度提升的精度上限通常更高;数据噪声大、要快速出结果、要并行训练时,随机森林更稳。两个都跑一遍,用验证集说话,比背"谁更强"的结论靠谱。
基学习器数量越多越好吗?
不是。数量到某个点后收益递减,训练成本却线性涨。正确做法是画一条"数量对验证误差"的曲线,误差走平就停,别盲目堆到几千棵。
集成方法再强,也救不了烂特征。下一节我们回到数据的源头——特征工程,看看哪些高级技巧能真正把模型的效果上限往上抬。