10 集成学习——《数据挖掘(主编:吕欣 王梦宁)》读书笔记

本文为《数据挖掘(主编:吕欣 王梦宁)》中“集成学习”相关内容的读书笔记。本文主要整理集成学习的基本思想、常见集成策略、随机森林、AdaBoost、GBDT、XGBoost、LightGBM 以及 Stacking 等内容,并结合个人理解补充模型选择、调参思路和实践注意事项。

本文不是对教材内容的简单复述,而是在学习基础上进行重新梳理和总结。


一、为什么需要集成学习

在机器学习建模过程中,单个模型往往会受到自身能力的限制。

例如,单棵决策树虽然解释性强,但容易过拟合;
逻辑回归模型结构简单,但可能无法捕捉复杂非线性关系;
KNN 对局部数据敏感,但在高维数据中效果可能下降。

集成学习的基本思想是:

与其依赖一个模型做判断,不如让多个模型共同参与决策。

这和现实生活中的“多人讨论”类似。
如果每个人的判断都有一定准确性,并且他们的判断角度不完全相同,那么综合多个人的意见,往往比只听一个人的意见更加可靠。

因此,集成学习的核心并不是简单地“模型越多越好”,而是要同时关注两个方面:

  1. 单个基学习器要有一定准确性;
  2. 不同基学习器之间要有一定差异性。

如果所有模型都犯同样的错误,那么即使集成很多模型,也不能明显提升效果。


二、集成学习的核心思想

我认为集成学习可以从三个问题理解:

  1. 如何生成多个模型;
  2. 如何让多个模型之间产生差异;
  3. 如何把多个模型的结果合并起来。

其中,第二点非常关键。

如果所有基学习器使用完全相同的数据、相同的特征、相同的算法和相同的参数,那么它们的预测结果可能非常接近,这样集成的意义就不大。

因此,集成学习通常会通过以下方式制造差异:

  • 对样本进行随机采样;
  • 对特征进行随机选择;
  • 使用不同类型的模型;
  • 调整不同模型参数;
  • 让后一个模型关注前一个模型的错误;
  • 使用不同训练集划分方式。

集成学习的优势就在于,它能够通过多个模型之间的互补关系,提高整体模型的泛化能力。


三、弱学习器与强学习器

在集成学习中,经常会提到弱学习器和强学习器。

弱学习器是指性能略好于随机猜测的模型。
例如,在二分类问题中,随机猜测的准确率大约是 50%,如果一个模型的准确率略高于 50%,就可以看作一个弱学习器。

强学习器则是具有较好预测能力和泛化能力的模型。

集成学习的重要思想是:

多个弱学习器通过合理组合,可以形成一个强学习器。

这也是 Boosting 类算法的基础思想。

需要注意的是,弱学习器并不代表“模型很差”,而是指单个模型能力有限,但仍然能够提供有效信息。
在集成学习中,简单模型反而常常更适合作为基学习器,因为它们不容易单独过拟合。


四、集成学习的主要类型

根据基学习器之间的关系,集成学习大致可以分为以下几类:

  1. Bagging;
  2. Boosting;
  3. Stacking;
  4. Blending;
  5. Voting。

不同方法的核心区别在于模型之间是否独立、是否按顺序训练,以及最终结果如何融合。


五、Bagging:通过并行建模降低方差

Bagging 的全称是 Bootstrap Aggregating。

它的主要思想是:

从原始训练集中进行有放回抽样,构造多个不同的训练子集,然后分别训练多个基学习器,最后对结果进行投票或平均。

Bagging 中的多个基学习器通常可以并行训练,因为它们之间没有严格的先后依赖关系。

Bagging 的关键在于“随机抽样”。
由于每个模型看到的数据不完全相同,因此模型之间会存在差异。
多个模型组合后,可以降低单个模型带来的不稳定性。

Bagging 更擅长降低模型方差,因此适合处理容易过拟合的模型,例如决策树。


六、Bagging 的基本流程

Bagging 的基本流程可以概括为以下几步:

  1. 从原始训练集中进行有放回抽样;
  2. 得到多个不同的训练子集;
  3. 在每个训练子集上训练一个基学习器;
  4. 对分类任务使用投票法;
  5. 对回归任务使用平均法;
  6. 得到最终预测结果。

对于分类问题,常用多数投票:

模型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=1My^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 思想的典型代表。

它由多棵决策树组成,每棵树在训练时都会引入随机性。

随机森林的随机性主要来自两个方面:

  1. 样本随机;
  2. 特征随机。

样本随机是指每棵树使用有放回抽样得到的训练子集。
特征随机是指每次节点分裂时,不是从所有特征中选择最优特征,而是从随机抽取的一部分特征中选择最优特征。

这两个随机机制可以降低树与树之间的相关性,从而提升集成效果。


九、随机森林的优点

随机森林具有以下优点:

  1. 对非线性关系具有较强建模能力;
  2. 不容易过拟合;
  3. 可以处理较高维度的数据;
  4. 对异常值和噪声具有一定鲁棒性;
  5. 可以用于分类任务,也可以用于回归任务;
  6. 可以输出特征重要性;
  7. 对数据预处理要求相对较低。

随机森林在很多数据挖掘任务中都是一个非常实用的基准模型。

如果不知道一开始该选择什么模型,随机森林通常是一个不错的尝试对象。


十、随机森林的不足

虽然随机森林效果稳定,但也存在一些不足。

第一,模型解释性不如单棵决策树。
单棵决策树可以清楚展示判断路径,而随机森林包含大量树,整体结构更复杂。

第二,模型体积可能较大。
如果树的数量很多、树的深度较大,模型会占用较多内存。

第三,预测速度可能较慢。
因为预测时需要让多棵树分别输出结果,然后再进行汇总。

第四,对于特别稀疏的高维数据,随机森林不一定是最优选择。
例如文本分类中,线性模型或梯度提升模型有时更合适。


十一、随机森林代码示例

分类任务:

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 的基本流程可以概括为:

  1. 初始化每个训练样本的权重;
  2. 训练一个弱分类器;
  3. 计算该弱分类器的错误率;
  4. 根据错误率计算该分类器的权重;
  5. 提高被错误分类样本的权重;
  6. 降低被正确分类样本的权重;
  7. 重复训练多个弱分类器;
  8. 将所有弱分类器加权组合得到最终模型。

样本初始权重通常为:

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=1nwiI(Gm(xi)=yi)

其中,I(⋅)I(\cdot)I() 是指示函数,分类错误时取 1,分类正确时取 0。

分类器权重为:

αm=12ln⁡1−emem \alpha_m=\frac{1}{2}\ln \frac{1-e_m}{e_m} αm=21lnem1em

当错误率越低时,αm\alpha_mαm 越大,说明该分类器在最终模型中的作用越大。


十六、AdaBoost 的优点和不足

AdaBoost 的优点包括:

  1. 思想清晰,容易理解;
  2. 能够把多个弱分类器组合成强分类器;
  3. 对简单模型有较好的提升效果;
  4. 不容易出现特别复杂的参数设置。

但是,AdaBoost 也存在明显不足:

  1. 对异常值和噪声比较敏感;
  2. 如果错误样本本身是噪声,模型会反复关注这些噪声;
  3. 数据类别重叠严重时,效果可能下降;
  4. 对基学习器的选择比较依赖。

因此,在使用 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=1Mη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)=Fm1(x)+ηhm(x)

这里的学习率 η\etaη 用于控制每棵树对最终结果的影响。

学习率越小,模型学习越慢,但通常泛化能力更稳定;
学习率越大,模型学习越快,但可能更容易过拟合。


二十、GBDT 中残差的直观理解

在平方损失下,GBDT 可以理解为每一轮拟合残差。

例如,真实值为 100,当前模型预测为 70,那么残差为:

100 - 70 = 30

下一棵树就会尝试学习这个 30。

如果下一棵树预测残差为 25,那么新的预测结果就接近:

70 + 25 = 95

通过一轮一轮修正,模型预测值逐渐接近真实值。

这就是 GBDT 的直观思想。


二十一、GBDT 的优点和不足

GBDT 的优点包括:

  1. 能够处理复杂的非线性关系;
  2. 预测精度通常较高;
  3. 对特征缩放不敏感;
  4. 可以用于分类和回归任务;
  5. 能够捕捉特征之间的交互关系。

GBDT 的不足包括:

  1. 训练过程通常不能完全并行;
  2. 参数较多,需要调参;
  3. 对异常值和噪声仍需关注;
  4. 在高维稀疏数据上效率可能不如线性模型;
  5. 数据量极大时训练成本较高。

因此,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 的优势主要体现在:

  1. 引入正则化项;
  2. 支持列采样;
  3. 支持并行计算;
  4. 支持缺失值处理;
  5. 支持稀疏数据;
  6. 训练速度较快;
  7. 泛化能力较强。

可以理解为:

XGBoost 是在 GBDT 思想基础上,更重视效率、泛化和工程可用性的版本。


二十四、XGBoost 的目标函数理解

XGBoost 的目标函数通常由两部分组成:

  1. 损失函数;
  2. 正则化项。

可以表示为:

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=1nl(yi,y^i)+m=1MΩ(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 在大规模数据和高维特征场景下的训练效率。

它的特点可以概括为:

  1. 训练速度快;
  2. 内存占用低;
  3. 支持大规模数据;
  4. 支持类别特征;
  5. 支持并行学习;
  6. 在表格数据中表现优秀。

LightGBM 的提出主要是为了解决传统 GBDT 在大数据、高维数据中训练效率不足的问题。


二十八、LightGBM 的关键技术

LightGBM 中有几个重要技术:

  1. 直方图算法;
  2. GOSS;
  3. EFB;
  4. Leaf-wise 生长策略。

下面分别理解。


二十九、直方图算法

传统决策树在寻找最佳分裂点时,需要遍历大量连续特征取值。

LightGBM 使用直方图算法,将连续特征离散成若干个桶,也就是 bins。

这样做的好处是:

  1. 减少候选分裂点数量;
  2. 降低计算复杂度;
  3. 降低内存占用;
  4. 提高训练速度。

例如,原本年龄是连续值:

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_depthnum_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. 硬投票;
  2. 软投票。

硬投票只看最终分类结果。

模型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 的基本流程如下:

  1. 训练多个不同类型的基模型;
  2. 使用交叉验证生成基模型的预测结果;
  3. 将这些预测结果作为新特征;
  4. 训练一个元模型;
  5. 用元模型输出最终预测结果。

需要注意的是,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. 模型变复杂但效果没有提升

有时增加模型数量或使用更复杂算法,效果并不会明显提升。

原因可能是:

  1. 特征质量不高;
  2. 数据噪声较大;
  3. 训练集和测试集分布不一致;
  4. 模型已经达到当前数据的信息上限;
  5. 存在数据泄露或评估方式不合理。

因此,不能迷信复杂模型。


2. 训练集效果很好,测试集效果较差

这通常说明模型过拟合。

解决方法包括:

  1. 降低树深度;
  2. 增加正则化;
  3. 减小学习率;
  4. 使用样本采样;
  5. 使用特征采样;
  6. 增加训练数据;
  7. 清理异常值。

3. 模型训练速度太慢

可以考虑:

  1. 减少树的数量;
  2. 降低树深度;
  3. 使用 LightGBM;
  4. 减少特征数量;
  5. 使用采样;
  6. 使用并行计算。

4. 模型解释困难

集成学习模型通常比简单模型更难解释。

可以使用以下方式辅助理解:

  1. 查看特征重要性;
  2. 使用部分依赖图;
  3. 使用 SHAP 方法;
  4. 对关键样本进行局部解释;
  5. 与简单模型结果进行对比。

四十六、集成学习与特征工程的关系

集成学习模型很强,但并不代表可以忽视特征工程。

对于树模型来说,虽然它们能够自动捕捉部分非线性关系和特征交互,但特征质量仍然非常重要。

例如:

  1. 缺失值是否有实际含义;
  2. 类别变量是否合理编码;
  3. 时间变量是否提取出小时、星期、月份等信息;
  4. 异常值是否需要处理;
  5. 高基数类别变量是否需要特殊编码;
  6. 是否存在数据泄露特征。

好的特征可以让模型更容易学习到规律。

我的理解是:

集成学习决定模型如何学习,特征工程决定模型能学到什么。


四十七、集成学习中的评估方法

在使用集成学习时,合理的评估方法非常重要。

常见评估方式包括:

  1. 留出法;
  2. K 折交叉验证;
  3. 分层抽样;
  4. 时间序列切分;
  5. OOB 评估。

如果是分类任务,可以关注:

  • Accuracy;
  • Precision;
  • Recall;
  • F1-score;
  • AUC。

如果是回归任务,可以关注:

  • MAE;
  • MSE;
  • RMSE;
  • R²。

需要注意的是,不同任务的评价指标不同,不能只看准确率。

例如,在欺诈检测、疾病预测等类别不平衡问题中,准确率可能具有误导性。
此时,Recall、F1-score 或 AUC 可能更重要。


四十八、集成学习实践流程

我认为,一个完整的集成学习建模流程可以包括以下步骤:

  1. 明确任务类型,是分类还是回归;
  2. 进行数据清洗和缺失值处理;
  3. 进行特征工程;
  4. 划分训练集、验证集和测试集;
  5. 先建立简单基准模型;
  6. 尝试随机森林、GBDT 等集成模型;
  7. 通过交叉验证评估模型;
  8. 调整关键参数;
  9. 分析特征重要性;
  10. 检查是否过拟合;
  11. 在测试集上进行最终评估;
  12. 保存模型并记录实验结果。

这个流程可以避免直接上复杂模型而不知道问题出在哪里。


四十九、不同算法的适用场景

算法 适用场景 注意事项
随机森林 稳定基准模型、非线性数据 模型较大,解释性一般
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)
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐