10 集成学习——《数据挖掘(主编:吕欣 王梦宁)》读书笔记
10 集成学习——《数据挖掘(主编:吕欣 王梦宁)》读书笔记
本文为《数据挖掘(主编:吕欣 王梦宁)》中“集成学习”相关内容的读书笔记。本文主要整理集成学习的基本思想、常见集成策略、随机森林、AdaBoost、GBDT、XGBoost、LightGBM 以及 Stacking 等内容,并结合个人理解补充模型选择、调参思路和实践注意事项。
本文不是对教材内容的简单复述,而是在学习基础上进行重新梳理和总结。
一、为什么需要集成学习
在机器学习建模过程中,单个模型往往会受到自身能力的限制。
例如,单棵决策树虽然解释性强,但容易过拟合;
逻辑回归模型结构简单,但可能无法捕捉复杂非线性关系;
KNN 对局部数据敏感,但在高维数据中效果可能下降。
集成学习的基本思想是:
与其依赖一个模型做判断,不如让多个模型共同参与决策。
这和现实生活中的“多人讨论”类似。
如果每个人的判断都有一定准确性,并且他们的判断角度不完全相同,那么综合多个人的意见,往往比只听一个人的意见更加可靠。
因此,集成学习的核心并不是简单地“模型越多越好”,而是要同时关注两个方面:
- 单个基学习器要有一定准确性;
- 不同基学习器之间要有一定差异性。
如果所有模型都犯同样的错误,那么即使集成很多模型,也不能明显提升效果。
二、集成学习的核心思想
我认为集成学习可以从三个问题理解:
- 如何生成多个模型;
- 如何让多个模型之间产生差异;
- 如何把多个模型的结果合并起来。
其中,第二点非常关键。
如果所有基学习器使用完全相同的数据、相同的特征、相同的算法和相同的参数,那么它们的预测结果可能非常接近,这样集成的意义就不大。
因此,集成学习通常会通过以下方式制造差异:
- 对样本进行随机采样;
- 对特征进行随机选择;
- 使用不同类型的模型;
- 调整不同模型参数;
- 让后一个模型关注前一个模型的错误;
- 使用不同训练集划分方式。
集成学习的优势就在于,它能够通过多个模型之间的互补关系,提高整体模型的泛化能力。
三、弱学习器与强学习器
在集成学习中,经常会提到弱学习器和强学习器。
弱学习器是指性能略好于随机猜测的模型。
例如,在二分类问题中,随机猜测的准确率大约是 50%,如果一个模型的准确率略高于 50%,就可以看作一个弱学习器。
强学习器则是具有较好预测能力和泛化能力的模型。
集成学习的重要思想是:
多个弱学习器通过合理组合,可以形成一个强学习器。
这也是 Boosting 类算法的基础思想。
需要注意的是,弱学习器并不代表“模型很差”,而是指单个模型能力有限,但仍然能够提供有效信息。
在集成学习中,简单模型反而常常更适合作为基学习器,因为它们不容易单独过拟合。
四、集成学习的主要类型
根据基学习器之间的关系,集成学习大致可以分为以下几类:
- Bagging;
- Boosting;
- Stacking;
- Blending;
- Voting。
不同方法的核心区别在于模型之间是否独立、是否按顺序训练,以及最终结果如何融合。
五、Bagging:通过并行建模降低方差
Bagging 的全称是 Bootstrap Aggregating。
它的主要思想是:
从原始训练集中进行有放回抽样,构造多个不同的训练子集,然后分别训练多个基学习器,最后对结果进行投票或平均。
Bagging 中的多个基学习器通常可以并行训练,因为它们之间没有严格的先后依赖关系。
Bagging 的关键在于“随机抽样”。
由于每个模型看到的数据不完全相同,因此模型之间会存在差异。
多个模型组合后,可以降低单个模型带来的不稳定性。
Bagging 更擅长降低模型方差,因此适合处理容易过拟合的模型,例如决策树。
六、Bagging 的基本流程
Bagging 的基本流程可以概括为以下几步:
- 从原始训练集中进行有放回抽样;
- 得到多个不同的训练子集;
- 在每个训练子集上训练一个基学习器;
- 对分类任务使用投票法;
- 对回归任务使用平均法;
- 得到最终预测结果。
对于分类问题,常用多数投票:
模型1:类别A
模型2:类别B
模型3:类别A
最终结果:类别A
对于回归问题,常用预测值平均:
y^=1M∑m=1My^m \hat{y}=\frac{1}{M}\sum_{m=1}^{M}\hat{y}_m y^=M1m=1∑My^m
其中,MMM 表示基学习器数量,y^m\hat{y}_my^m 表示第 mmm 个模型的预测结果。
七、袋外数据 OOB 的理解
在 Bagging 中,由于是有放回抽样,所以每次抽样时,并不是所有样本都会被选中。
那些没有被某个模型抽中的样本,称为袋外样本,即 Out-of-Bag Samples,简称 OOB。
OOB 样本可以用来估计模型的泛化误差。
这样即使不单独划分验证集,也可以对模型效果进行评估。
这是 Bagging 的一个很实用的特点。
在随机森林中,也可以通过设置参数启用 OOB 评估。
from sklearn.ensemble import RandomForestClassifier
model = RandomForestClassifier(
n_estimators=100,
oob_score=True,
random_state=42
)
八、随机森林的基本思想
随机森林是 Bagging 思想的典型代表。
它由多棵决策树组成,每棵树在训练时都会引入随机性。
随机森林的随机性主要来自两个方面:
- 样本随机;
- 特征随机。
样本随机是指每棵树使用有放回抽样得到的训练子集。
特征随机是指每次节点分裂时,不是从所有特征中选择最优特征,而是从随机抽取的一部分特征中选择最优特征。
这两个随机机制可以降低树与树之间的相关性,从而提升集成效果。
九、随机森林的优点
随机森林具有以下优点:
- 对非线性关系具有较强建模能力;
- 不容易过拟合;
- 可以处理较高维度的数据;
- 对异常值和噪声具有一定鲁棒性;
- 可以用于分类任务,也可以用于回归任务;
- 可以输出特征重要性;
- 对数据预处理要求相对较低。
随机森林在很多数据挖掘任务中都是一个非常实用的基准模型。
如果不知道一开始该选择什么模型,随机森林通常是一个不错的尝试对象。
十、随机森林的不足
虽然随机森林效果稳定,但也存在一些不足。
第一,模型解释性不如单棵决策树。
单棵决策树可以清楚展示判断路径,而随机森林包含大量树,整体结构更复杂。
第二,模型体积可能较大。
如果树的数量很多、树的深度较大,模型会占用较多内存。
第三,预测速度可能较慢。
因为预测时需要让多棵树分别输出结果,然后再进行汇总。
第四,对于特别稀疏的高维数据,随机森林不一定是最优选择。
例如文本分类中,线性模型或梯度提升模型有时更合适。
十一、随机森林代码示例
分类任务:
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
X_train, X_test, y_train, y_test = train_test_split(
X, y,
test_size=0.2,
random_state=42
)
model = RandomForestClassifier(
n_estimators=100,
max_depth=None,
random_state=42
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
acc = accuracy_score(y_test, y_pred)
print("Accuracy:", acc)
回归任务:
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error
model = RandomForestRegressor(
n_estimators=100,
random_state=42
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
mse = mean_squared_error(y_test, y_pred)
print("MSE:", mse)
十二、Boosting:通过串行学习逐步修正错误
Boosting 是另一类重要的集成学习方法。
与 Bagging 不同,Boosting 中的基学习器通常是串行训练的。
也就是说,后一个模型会受到前一个模型的影响。
Boosting 的核心思想是:
让新的模型重点学习前面模型没有学好的部分。
如果某些样本在前一轮被错误分类,那么在下一轮训练中,这些样本会被赋予更高的重要性。
这样模型会逐渐关注难分类样本,最终形成一个更强的整体模型。
Boosting 更擅长降低偏差,因此常用于提升模型拟合能力。
十三、Bagging 与 Boosting 的区别
Bagging 和 Boosting 都属于集成学习,但二者思想不同。
| 对比维度 | Bagging | Boosting |
|---|---|---|
| 训练方式 | 并行训练 | 串行训练 |
| 样本处理 | 有放回抽样 | 调整样本权重或拟合残差 |
| 关注重点 | 降低方差 | 降低偏差 |
| 基学习器关系 | 相对独立 | 前后依赖 |
| 典型算法 | 随机森林 | AdaBoost、GBDT、XGBoost、LightGBM |
| 适合模型 | 容易过拟合的模型 | 较弱但稳定的模型 |
我的理解是:
Bagging 更像是让多个模型独立投票;Boosting 更像是让模型接力纠错。
十四、AdaBoost 的基本思想
AdaBoost 是 Boosting 中比较经典的算法。
它的主要思想是不断调整样本权重。
被前一轮模型分类错误的样本,在下一轮中会获得更高权重;
被正确分类的样本,权重会相对降低。
这样,后续模型会更加关注之前容易出错的样本。
AdaBoost 的最终预测结果不是简单投票,而是对不同弱学习器进行加权组合。
表现好的弱学习器权重大,表现差的弱学习器权重小。
十五、AdaBoost 的基本流程
AdaBoost 的基本流程可以概括为:
- 初始化每个训练样本的权重;
- 训练一个弱分类器;
- 计算该弱分类器的错误率;
- 根据错误率计算该分类器的权重;
- 提高被错误分类样本的权重;
- 降低被正确分类样本的权重;
- 重复训练多个弱分类器;
- 将所有弱分类器加权组合得到最终模型。
样本初始权重通常为:
wi=1n w_i=\frac{1}{n} wi=n1
其中,nnn 表示训练样本数量。
分类器错误率为:
em=∑i=1nwiI(Gm(xi)≠yi) e_m=\sum_{i=1}^{n}w_i I(G_m(x_i)\neq y_i) em=i=1∑nwiI(Gm(xi)=yi)
其中,I(⋅)I(\cdot)I(⋅) 是指示函数,分类错误时取 1,分类正确时取 0。
分类器权重为:
αm=12ln1−emem \alpha_m=\frac{1}{2}\ln \frac{1-e_m}{e_m} αm=21lnem1−em
当错误率越低时,αm\alpha_mαm 越大,说明该分类器在最终模型中的作用越大。
十六、AdaBoost 的优点和不足
AdaBoost 的优点包括:
- 思想清晰,容易理解;
- 能够把多个弱分类器组合成强分类器;
- 对简单模型有较好的提升效果;
- 不容易出现特别复杂的参数设置。
但是,AdaBoost 也存在明显不足:
- 对异常值和噪声比较敏感;
- 如果错误样本本身是噪声,模型会反复关注这些噪声;
- 数据类别重叠严重时,效果可能下降;
- 对基学习器的选择比较依赖。
因此,在使用 AdaBoost 时,需要关注数据质量。
如果数据中存在大量错误标注或异常样本,AdaBoost 可能会把注意力集中到这些不可靠样本上。
十七、AdaBoost 代码示例
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
base_model = DecisionTreeClassifier(
max_depth=1,
random_state=42
)
model = AdaBoostClassifier(
estimator=base_model,
n_estimators=100,
learning_rate=0.5,
random_state=42
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
acc = accuracy_score(y_test, y_pred)
print("Accuracy:", acc)
需要注意的是,在新版 sklearn 中,基学习器参数通常使用 estimator;旧版本中可能使用 base_estimator。
十八、GBDT 的基本思想
GBDT 的全称是 Gradient Boosting Decision Tree,即梯度提升决策树。
它也是 Boosting 思想的一种重要实现。
与 AdaBoost 主要调整样本权重不同,GBDT 更强调拟合前一轮模型的误差。
每一轮新加入的树,都是为了修正当前模型还没有预测好的部分。
GBDT 的核心思想可以理解为:
当前模型预测得不够好,就再训练一棵树去拟合它的残差或负梯度。
因此,GBDT 是一种逐步加法模型。
十九、GBDT 的加法模型理解
GBDT 的模型可以写成:
FM(x)=∑m=1Mηhm(x) F_M(x)=\sum_{m=1}^{M}\eta h_m(x) FM(x)=m=1∑Mηhm(x)
其中:
- FM(x)F_M(x)FM(x) 表示最终模型;
- MMM 表示树的数量;
- hm(x)h_m(x)hm(x) 表示第 mmm 棵树;
- η\etaη 表示学习率。
每一轮模型更新可以表示为:
Fm(x)=Fm−1(x)+ηhm(x) F_m(x)=F_{m-1}(x)+\eta h_m(x) Fm(x)=Fm−1(x)+ηhm(x)
这里的学习率 η\etaη 用于控制每棵树对最终结果的影响。
学习率越小,模型学习越慢,但通常泛化能力更稳定;
学习率越大,模型学习越快,但可能更容易过拟合。
二十、GBDT 中残差的直观理解
在平方损失下,GBDT 可以理解为每一轮拟合残差。
例如,真实值为 100,当前模型预测为 70,那么残差为:
100 - 70 = 30
下一棵树就会尝试学习这个 30。
如果下一棵树预测残差为 25,那么新的预测结果就接近:
70 + 25 = 95
通过一轮一轮修正,模型预测值逐渐接近真实值。
这就是 GBDT 的直观思想。
二十一、GBDT 的优点和不足
GBDT 的优点包括:
- 能够处理复杂的非线性关系;
- 预测精度通常较高;
- 对特征缩放不敏感;
- 可以用于分类和回归任务;
- 能够捕捉特征之间的交互关系。
GBDT 的不足包括:
- 训练过程通常不能完全并行;
- 参数较多,需要调参;
- 对异常值和噪声仍需关注;
- 在高维稀疏数据上效率可能不如线性模型;
- 数据量极大时训练成本较高。
因此,GBDT 适合结构化表格数据,但并不一定适合所有场景。
二十二、GBDT 代码示例
分类任务:
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.metrics import accuracy_score
model = GradientBoostingClassifier(
n_estimators=100,
learning_rate=0.1,
max_depth=3,
random_state=42
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
acc = accuracy_score(y_test, y_pred)
print("Accuracy:", acc)
回归任务:
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.metrics import mean_squared_error
model = GradientBoostingRegressor(
n_estimators=100,
learning_rate=0.1,
max_depth=3,
random_state=42
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
mse = mean_squared_error(y_test, y_pred)
print("MSE:", mse)
二十三、XGBoost 的基本思想
XGBoost 是对 GBDT 的重要改进。
它仍然属于梯度提升树模型,但在工程实现和模型控制方面做了大量优化。
XGBoost 的优势主要体现在:
- 引入正则化项;
- 支持列采样;
- 支持并行计算;
- 支持缺失值处理;
- 支持稀疏数据;
- 训练速度较快;
- 泛化能力较强。
可以理解为:
XGBoost 是在 GBDT 思想基础上,更重视效率、泛化和工程可用性的版本。
二十四、XGBoost 的目标函数理解
XGBoost 的目标函数通常由两部分组成:
- 损失函数;
- 正则化项。
可以表示为:
Obj=∑i=1nl(yi,y^i)+∑m=1MΩ(fm) Obj = \sum_{i=1}^{n}l(y_i,\hat{y}_i)+\sum_{m=1}^{M}\Omega(f_m) Obj=i=1∑nl(yi,y^i)+m=1∑MΩ(fm)
其中:
- l(yi,y^i)l(y_i,\hat{y}_i)l(yi,y^i) 表示模型预测误差;
- Ω(fm)\Omega(f_m)Ω(fm) 表示对树复杂度的惩罚;
- MMM 表示树的数量。
正则化项的作用是限制模型过于复杂,从而降低过拟合风险。
这也是 XGBoost 相比传统 GBDT 更稳定的重要原因之一。
二十五、XGBoost 的特点
XGBoost 的主要特点包括:
1. 正则化控制模型复杂度
XGBoost 会对树的复杂度进行惩罚,使模型不容易过拟合。
2. 支持列采样
每次建树时可以只使用部分特征,减少模型对某些特征的依赖。
3. 支持并行优化
虽然树之间仍然是逐轮生成的,但在寻找最佳分裂点等环节可以并行处理。
4. 能处理缺失值
XGBoost 可以自动学习缺失值的默认分裂方向,因此对缺失值具有一定适应能力。
5. 适合结构化数据
在很多表格数据任务中,XGBoost 表现非常优秀。
二十六、XGBoost 代码示例
from xgboost import XGBClassifier
from sklearn.metrics import accuracy_score
model = XGBClassifier(
n_estimators=200,
learning_rate=0.05,
max_depth=4,
subsample=0.8,
colsample_bytree=0.8,
random_state=42,
eval_metric="logloss"
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
acc = accuracy_score(y_test, y_pred)
print("Accuracy:", acc)
回归任务:
from xgboost import XGBRegressor
from sklearn.metrics import mean_squared_error
model = XGBRegressor(
n_estimators=200,
learning_rate=0.05,
max_depth=4,
subsample=0.8,
colsample_bytree=0.8,
random_state=42
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
mse = mean_squared_error(y_test, y_pred)
print("MSE:", mse)
二十七、LightGBM 的基本思想
LightGBM 是一种高效的梯度提升框架,主要目标是提高 GBDT 在大规模数据和高维特征场景下的训练效率。
它的特点可以概括为:
- 训练速度快;
- 内存占用低;
- 支持大规模数据;
- 支持类别特征;
- 支持并行学习;
- 在表格数据中表现优秀。
LightGBM 的提出主要是为了解决传统 GBDT 在大数据、高维数据中训练效率不足的问题。
二十八、LightGBM 的关键技术
LightGBM 中有几个重要技术:
- 直方图算法;
- GOSS;
- EFB;
- Leaf-wise 生长策略。
下面分别理解。
二十九、直方图算法
传统决策树在寻找最佳分裂点时,需要遍历大量连续特征取值。
LightGBM 使用直方图算法,将连续特征离散成若干个桶,也就是 bins。
这样做的好处是:
- 减少候选分裂点数量;
- 降低计算复杂度;
- 降低内存占用;
- 提高训练速度。
例如,原本年龄是连续值:
18, 19, 23, 24, 31, 45, 60
可以被分到几个区间中:
[18, 25), [25, 40), [40, 60]
模型不再直接遍历每一个具体取值,而是在分箱后寻找较优分裂点。
三十、GOSS 的理解
GOSS 的全称是 Gradient-based One-Side Sampling,即基于梯度的单边采样。
它的核心思想是:
梯度大的样本通常代表模型当前预测得不好,应该优先保留;梯度小的样本说明模型已经学得较好,可以适当采样。
因此,GOSS 会保留梯度较大的样本,同时从梯度较小的样本中随机抽取一部分,并对其进行加权修正。
这样既保留了重要样本,又减少了训练数据量,从而提高训练速度。
三十一、EFB 的理解
EFB 的全称是 Exclusive Feature Bundling,即互斥特征捆绑。
它主要用于处理高维稀疏特征。
在实际数据中,有些特征很少同时取非零值。
例如在独热编码之后,多个类别特征之间可能是互斥的。
EFB 会将这些互斥特征合并到一个特征中,从而减少特征数量。
这样可以降低计算量,同时尽量不损失信息。
三十二、Leaf-wise 生长策略
传统决策树经常采用 Level-wise 生长方式,也就是一层一层地生长。
LightGBM 使用 Leaf-wise 生长策略。
它每次选择增益最大的叶子节点进行分裂。
这种方式通常可以更快降低损失,提高模型精度。
但是,Leaf-wise 也更容易生成较深的树,导致过拟合。
因此,LightGBM 通常需要设置 max_depth 或 num_leaves 来限制模型复杂度。
三十三、LightGBM 代码示例
from lightgbm import LGBMClassifier
from sklearn.metrics import accuracy_score
model = LGBMClassifier(
n_estimators=300,
learning_rate=0.05,
num_leaves=31,
max_depth=-1,
subsample=0.8,
colsample_bytree=0.8,
random_state=42
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
acc = accuracy_score(y_test, y_pred)
print("Accuracy:", acc)
回归任务:
from lightgbm import LGBMRegressor
from sklearn.metrics import mean_squared_error
model = LGBMRegressor(
n_estimators=300,
learning_rate=0.05,
num_leaves=31,
subsample=0.8,
colsample_bytree=0.8,
random_state=42
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
mse = mean_squared_error(y_test, y_pred)
print("MSE:", mse)
三十四、XGBoost 与 LightGBM 的区别
XGBoost 和 LightGBM 都是优秀的梯度提升模型,但侧重点不同。
| 对比维度 | XGBoost | LightGBM |
|---|---|---|
| 树生长策略 | 通常按层生长 | 按叶生长 |
| 训练速度 | 较快 | 通常更快 |
| 内存占用 | 相对较高 | 相对较低 |
| 大规模数据 | 表现较好 | 更适合大规模数据 |
| 防过拟合 | 正则化较完善 | 需要注意叶子数量和深度 |
| 稳定性 | 较稳定 | 参数设置不当时易过拟合 |
我的理解是:
XGBoost 更像是稳健型选手,LightGBM 更像是效率型选手。
在数据量较大、特征较多时,LightGBM 往往更有优势。
在希望模型更加稳定、调参风险较低时,XGBoost 也是很好的选择。
三十五、Voting 投票法
Voting 是一种简单直接的集成方法。
它将多个模型的预测结果进行投票,最终选择票数最多的类别。
Voting 可以分为两种:
- 硬投票;
- 软投票。
硬投票只看最终分类结果。
模型1:A
模型2:A
模型3:B
最终结果:A
软投票则考虑每个模型预测各类别的概率。
例如:
模型1:A 的概率 0.7
模型2:A 的概率 0.6
模型3:A 的概率 0.4
平均后:A 的概率 0.57
软投票通常比硬投票更充分地利用模型信息。
三十六、Voting 代码示例
from sklearn.ensemble import VotingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC
model1 = LogisticRegression(max_iter=1000)
model2 = RandomForestClassifier(n_estimators=100, random_state=42)
model3 = SVC(probability=True, random_state=42)
voting_model = VotingClassifier(
estimators=[
("lr", model1),
("rf", model2),
("svc", model3)
],
voting="soft"
)
voting_model.fit(X_train, y_train)
y_pred = voting_model.predict(X_test)
Voting 的优点是简单、直观。
但它的效果依赖于基模型是否足够多样化。
如果几个模型预测结果高度相似,Voting 的提升可能并不明显。
三十七、Stacking 的基本思想
Stacking 是一种更高级的集成方法。
它不是简单地平均或投票,而是再训练一个模型来学习如何融合多个模型的结果。
Stacking 通常包含两层:
第一层是多个基学习器。
第二层是元学习器,也可以称为次级学习器。
第一层模型先对数据进行预测,然后将这些预测结果作为新的特征,输入给第二层模型。
也就是说,Stacking 学习的是:
哪些模型在什么情况下更可信。
三十八、Stacking 的流程
Stacking 的基本流程如下:
- 训练多个不同类型的基模型;
- 使用交叉验证生成基模型的预测结果;
- 将这些预测结果作为新特征;
- 训练一个元模型;
- 用元模型输出最终预测结果。
需要注意的是,Stacking 中非常重要的一点是防止数据泄露。
如果直接用训练集训练基模型,再用同一训练集预测得到结果训练元模型,就可能导致元模型看到过于乐观的预测结果。
因此,实际使用 Stacking 时,通常需要使用交叉验证生成 out-of-fold 预测。
三十九、Stacking 代码示例
from sklearn.ensemble import StackingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
base_models = [
("rf", RandomForestClassifier(n_estimators=100, random_state=42)),
("gbdt", GradientBoostingClassifier(random_state=42)),
("svc", SVC(probability=True, random_state=42))
]
meta_model = LogisticRegression(max_iter=1000)
model = StackingClassifier(
estimators=base_models,
final_estimator=meta_model,
cv=5
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
acc = accuracy_score(y_test, y_pred)
print("Accuracy:", acc)
Stacking 的效果通常不错,但计算成本较高,并且更容易因为使用不当造成数据泄露。
四十、Blending 的基本思想
Blending 与 Stacking 类似,都是用一个次级模型融合多个基模型的输出。
区别在于,Blending 通常会从训练集中划分出一部分验证集。
基模型先在训练子集上训练,然后在验证集上预测,再用这些预测结果训练次级模型。
Blending 的优点是实现简单,训练成本相对较低。
缺点是会占用一部分训练数据作为验证集,因此当数据量较小时,可能不如 Stacking 稳定。
简单理解:
Stacking:通常使用交叉验证生成二层训练数据
Blending:通常使用固定验证集生成二层训练数据
四十一、Pasting 的理解
Pasting 和 Bagging 类似,都是通过采样构造多个训练子集。
二者区别在于:
- Bagging 是有放回抽样;
- Pasting 是无放回抽样。
Pasting 在大数据场景中比较有意义。
因为数据量本身已经很大,不一定需要有放回抽样,也能让不同模型看到不同的数据子集。
这样可以减少训练成本,同时保持一定的模型差异性。
四十二、集成策略总结
不同集成策略可以总结如下:
| 方法 | 核心思想 | 代表算法 |
|---|---|---|
| Bagging | 多个模型并行训练,投票或平均 | 随机森林 |
| Boosting | 后续模型修正前面模型的错误 | AdaBoost、GBDT、XGBoost |
| Voting | 多个模型直接投票或概率平均 | VotingClassifier |
| Stacking | 用元模型学习如何融合基模型 | StackingClassifier |
| Blending | 用验证集训练融合模型 | 常用于比赛建模 |
| Pasting | 无放回抽样构造多个训练集 | 大数据子样本训练 |
我的理解是:
Bagging 解决的是“单个模型不稳定”的问题;Boosting 解决的是“模型能力不够强”的问题;Stacking 解决的是“不同模型如何优势互补”的问题。
四十三、集成学习中的模型选择
不同集成模型适合不同场景。
如果数据量不大,希望模型稳定,可以优先尝试随机森林。
如果数据是结构化表格数据,并且追求较高预测精度,可以尝试 GBDT、XGBoost 或 LightGBM。
如果数据噪声较大,不建议一开始就使用对错误样本非常敏感的 AdaBoost。
如果已经训练了多个表现不错但风格不同的模型,可以考虑 Voting 或 Stacking。
如果数据规模很大、特征很多,可以优先考虑 LightGBM。
四十四、集成学习调参思路
集成学习模型通常参数较多,调参时不能盲目搜索。
可以从以下几个方面入手。
1. 树的数量
常见参数:
n_estimators
树越多,模型能力通常越强,但训练时间也越长。
当树的数量增加到一定程度后,效果提升会变得有限。
2. 学习率
常见参数:
learning_rate
学习率越小,每棵树贡献越小,模型学习更慢,但可能更稳定。
学习率越大,模型学习更快,但可能更容易过拟合。
通常可以采用:
较小 learning_rate + 较大 n_estimators
3. 树的深度
常见参数:
max_depth
树越深,模型越复杂,越容易拟合复杂关系。
但树太深也容易过拟合。
4. 叶子节点数量
LightGBM 中常用:
num_leaves
num_leaves 越大,模型越复杂。
在 LightGBM 中需要特别关注这个参数。
5. 样本采样比例
常见参数:
subsample
通过每次只使用部分样本,可以增加模型随机性,降低过拟合风险。
6. 特征采样比例
常见参数:
colsample_bytree
每次建树只使用部分特征,可以减少模型对少数强特征的依赖。
四十五、集成学习的常见问题
1. 模型变复杂但效果没有提升
有时增加模型数量或使用更复杂算法,效果并不会明显提升。
原因可能是:
- 特征质量不高;
- 数据噪声较大;
- 训练集和测试集分布不一致;
- 模型已经达到当前数据的信息上限;
- 存在数据泄露或评估方式不合理。
因此,不能迷信复杂模型。
2. 训练集效果很好,测试集效果较差
这通常说明模型过拟合。
解决方法包括:
- 降低树深度;
- 增加正则化;
- 减小学习率;
- 使用样本采样;
- 使用特征采样;
- 增加训练数据;
- 清理异常值。
3. 模型训练速度太慢
可以考虑:
- 减少树的数量;
- 降低树深度;
- 使用 LightGBM;
- 减少特征数量;
- 使用采样;
- 使用并行计算。
4. 模型解释困难
集成学习模型通常比简单模型更难解释。
可以使用以下方式辅助理解:
- 查看特征重要性;
- 使用部分依赖图;
- 使用 SHAP 方法;
- 对关键样本进行局部解释;
- 与简单模型结果进行对比。
四十六、集成学习与特征工程的关系
集成学习模型很强,但并不代表可以忽视特征工程。
对于树模型来说,虽然它们能够自动捕捉部分非线性关系和特征交互,但特征质量仍然非常重要。
例如:
- 缺失值是否有实际含义;
- 类别变量是否合理编码;
- 时间变量是否提取出小时、星期、月份等信息;
- 异常值是否需要处理;
- 高基数类别变量是否需要特殊编码;
- 是否存在数据泄露特征。
好的特征可以让模型更容易学习到规律。
我的理解是:
集成学习决定模型如何学习,特征工程决定模型能学到什么。
四十七、集成学习中的评估方法
在使用集成学习时,合理的评估方法非常重要。
常见评估方式包括:
- 留出法;
- K 折交叉验证;
- 分层抽样;
- 时间序列切分;
- OOB 评估。
如果是分类任务,可以关注:
- Accuracy;
- Precision;
- Recall;
- F1-score;
- AUC。
如果是回归任务,可以关注:
- MAE;
- MSE;
- RMSE;
- R²。
需要注意的是,不同任务的评价指标不同,不能只看准确率。
例如,在欺诈检测、疾病预测等类别不平衡问题中,准确率可能具有误导性。
此时,Recall、F1-score 或 AUC 可能更重要。
四十八、集成学习实践流程
我认为,一个完整的集成学习建模流程可以包括以下步骤:
- 明确任务类型,是分类还是回归;
- 进行数据清洗和缺失值处理;
- 进行特征工程;
- 划分训练集、验证集和测试集;
- 先建立简单基准模型;
- 尝试随机森林、GBDT 等集成模型;
- 通过交叉验证评估模型;
- 调整关键参数;
- 分析特征重要性;
- 检查是否过拟合;
- 在测试集上进行最终评估;
- 保存模型并记录实验结果。
这个流程可以避免直接上复杂模型而不知道问题出在哪里。
四十九、不同算法的适用场景
| 算法 | 适用场景 | 注意事项 |
|---|---|---|
| 随机森林 | 稳定基准模型、非线性数据 | 模型较大,解释性一般 |
| AdaBoost | 弱分类器组合、简单任务 | 对噪声敏感 |
| GBDT | 中小规模结构化数据 | 训练较慢,需要调参 |
| XGBoost | 表格数据、高精度建模 | 小样本需防过拟合 |
| LightGBM | 大规模数据、高维特征 | 参数设置不当易过拟合 |
| Voting | 多个模型结果融合 | 基模型要有差异 |
| Stacking | 模型比赛、复杂融合 | 注意数据泄露 |
五十、本章学习总结
通过本章学习,我认识到集成学习并不是简单地堆叠多个模型,而是一种利用多个模型互补关系提升泛化能力的方法。
Bagging 强调并行训练多个模型,通过随机采样降低模型方差。
随机森林是 Bagging 的典型代表,它通过样本随机和特征随机提高模型稳定性。
Boosting 强调串行训练模型,让后续模型关注前面模型的错误。
AdaBoost 通过调整样本权重实现纠错,GBDT 通过拟合负梯度或残差逐步优化模型。
XGBoost 和 LightGBM 则是在 GBDT 基础上的进一步发展。
XGBoost 更重视正则化、工程优化和泛化能力;LightGBM 更强调速度、低内存和大规模数据处理能力。
Stacking 和 Voting 则体现了另一种融合思想,即通过不同模型之间的互补提升最终表现。
整体来看,集成学习是一类非常实用的机器学习方法,尤其适合结构化表格数据任务。
五十一、个人理解
我认为,集成学习最重要的思想不是“模型数量多”,而是“模型之间能互补”。
如果多个模型都从同一个角度学习数据,那么它们的错误也可能非常相似,集成后提升有限。
真正有效的集成,应该让不同模型从不同角度捕捉数据规律。
例如:
- 随机森林通过随机样本和随机特征制造差异;
- AdaBoost 通过关注错误样本制造学习重点差异;
- GBDT 通过不断拟合残差逐步修正模型;
- Stacking 通过元学习器学习不同模型的融合方式。
这说明,集成学习的关键是“差异性”和“有效组合”。
同时,我也认识到,集成学习虽然强大,但并不能替代数据理解。
如果数据本身质量差、特征设计不合理、训练集和测试集分布差异大,那么即使使用复杂的集成模型,也很难得到可靠结果。
因此,在实际建模中,不能把全部希望寄托在模型上。
应该先理解数据,再选择模型,最后通过合理评估和调参优化模型。
我的总结是:
集成学习的本质,是用多个模型的差异性换取整体预测的稳定性和准确性。
五十二、参考代码汇总
1. 随机森林分类
from sklearn.ensemble import RandomForestClassifier
model = RandomForestClassifier(
n_estimators=100,
max_depth=None,
random_state=42
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
2. 随机森林回归
from sklearn.ensemble import RandomForestRegressor
model = RandomForestRegressor(
n_estimators=100,
random_state=42
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
3. AdaBoost 分类
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier
base_model = DecisionTreeClassifier(
max_depth=1,
random_state=42
)
model = AdaBoostClassifier(
estimator=base_model,
n_estimators=100,
learning_rate=0.5,
random_state=42
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
4. GBDT 分类
from sklearn.ensemble import GradientBoostingClassifier
model = GradientBoostingClassifier(
n_estimators=100,
learning_rate=0.1,
max_depth=3,
random_state=42
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
5. GBDT 回归
from sklearn.ensemble import GradientBoostingRegressor
model = GradientBoostingRegressor(
n_estimators=100,
learning_rate=0.1,
max_depth=3,
random_state=42
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
6. XGBoost 分类
from xgboost import XGBClassifier
model = XGBClassifier(
n_estimators=200,
learning_rate=0.05,
max_depth=4,
subsample=0.8,
colsample_bytree=0.8,
random_state=42,
eval_metric="logloss"
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
7. XGBoost 回归
from xgboost import XGBRegressor
model = XGBRegressor(
n_estimators=200,
learning_rate=0.05,
max_depth=4,
subsample=0.8,
colsample_bytree=0.8,
random_state=42
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
8. LightGBM 分类
from lightgbm import LGBMClassifier
model = LGBMClassifier(
n_estimators=300,
learning_rate=0.05,
num_leaves=31,
subsample=0.8,
colsample_bytree=0.8,
random_state=42
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
9. LightGBM 回归
from lightgbm import LGBMRegressor
model = LGBMRegressor(
n_estimators=300,
learning_rate=0.05,
num_leaves=31,
subsample=0.8,
colsample_bytree=0.8,
random_state=42
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
10. Voting 分类器
from sklearn.ensemble import VotingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC
model1 = LogisticRegression(max_iter=1000)
model2 = RandomForestClassifier(n_estimators=100, random_state=42)
model3 = SVC(probability=True, random_state=42)
voting_model = VotingClassifier(
estimators=[
("lr", model1),
("rf", model2),
("svc", model3)
],
voting="soft"
)
voting_model.fit(X_train, y_train)
y_pred = voting_model.predict(X_test)
11. Stacking 分类器
from sklearn.ensemble import StackingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.svm import SVC
base_models = [
("rf", RandomForestClassifier(n_estimators=100, random_state=42)),
("gbdt", GradientBoostingClassifier(random_state=42)),
("svc", SVC(probability=True, random_state=42))
]
meta_model = LogisticRegression(max_iter=1000)
model = StackingClassifier(
estimators=base_models,
final_estimator=meta_model,
cv=5
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
12. 模型评价
from sklearn.metrics import accuracy_score, classification_report
acc = accuracy_score(y_test, y_pred)
print("Accuracy:", acc)
print(classification_report(y_test, y_pred))
13. 回归模型评价
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
mae = mean_absolute_error(y_test, y_pred)
mse = mean_squared_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)
print("MAE:", mae)
print("MSE:", mse)
print("R2:", r2)
14. 特征重要性查看
import pandas as pd
importance = model.feature_importances_
feature_importance = pd.DataFrame({
"feature": X_train.columns,
"importance": importance
})
feature_importance = feature_importance.sort_values(
by="importance",
ascending=False
)
print(feature_importance)
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)