BLOG

个人博客,记录学习与生活

集成学习

Published Nov. 25, 2020, 2:46 p.m. by kkk

1. 集成学习介绍

The wisdom of the crowd

简而言之就是集各家所长,融合多个模型为一个,组合之后的效果超过每个单一模型。

一个例子:如果有一种分类器,预测对的概率为51%,根据大数定律,对同一样本进行无数次预测后(假设不同次数的预测结果完全独立),正样本预测比例占51%,那么对于这无数次的结果,如果取出现次数多的作为最终结果,那就是100%的正确率。借助这个思路,如果有1000个相互完全独立的51%概率的分类器,对于一样本预测任务,所有结果中最多的作为最终预测,可能达到近75%的概率。

集成学习依赖的关键:各分模型间尽量独立

常见的集成学习模型比如随机森林、GBDT、XGBoost等。

2. 集成学习流派

概括起来可以分为以下四类:

  • Voting
  • Bagging (Pasting)
  • Boosting
  • Stacking

3. Voting

最直接的思路,为了让各模型间尽量独立,可以采用完全不同的算法进行计算,然后采用多个模型投票的方式,有两种方式:Hard、Soft,直接翻译起来就是硬投票和软投票

两者区别:模型通常是既能输出预测概率,也能输出预测结果,预测结果是对概念进行了一个argmax,Hard Voting就是直接针对各个模型的输出结果,平均化选择最好的作为最终结果,而Soft Voting只是将预测结果换成了预测概率

from sklearn.ensemble import VotingClassifier
clf1, clf2, clf3, ... clfn
voting_clf = VotingClassifier(
    estimators=[('name_clf1', clf1), ('name_clf2', clf2), ...], 
    voting=<'hard', 'soft'>)
voting_clf.fit(X, y)

3.1 使用建议

用于算法差异较大(多个基准算法模型),但正确率接近的情况。当几个算法正确率相差好几个点时,集成模型可能比最好的单个模型效果还要差。

4. Bagging

全称:Bootstrap Aggregating,即通过Bootstrap的采样方法(训练实例可被统一模型多次采用),非Bootstrap为Pasting。即通过在训练集中循环采样得到子样本进行单一模型的训练,Bagging和Pasting的差别在于,在Bagging中,同一样本可被同一模型采样多次,按统计学数据就是有放回

为了使各模型准确率接近,采用的是同一算法进行不同数据拟合。

注:通常如果使用Bagging进行抽样,且所有模型抽样的总和是总训练样本数量,根据统计学可能有63%的样本会被抽到,其他的37%的样本都不会被抽到($1-\frac{1}{e}\approx 63.212 \% $)

同时,也可以对样本特征进行采样,对于高维数据的处理比较有效。

随机块方法:同时对样本和特征进行bootstrap采样

随机子空间方法:不进行bootstrap采样(保持所有的训练样本),只对特征进行采样

4.1对于训练的多个模型,如何聚合所有的结果?

通常,对于分类任务,就是通过Hard Voting或Soft Voting方式,对于回归任务则是平均化所有模型输出。通常采样后的模型具有相对与直接在原数据上训练具有更大的偏差,但是通过聚合多个模型之后,最终的集成模型与原数据集上直接训练的有类似的偏差,但方差更小。

4.2 编程接口

'''
首先需要传入基本模型,
n_estimators: 模型个数
max_samples: 每个模型最多采样的样本个数
bootstrap: 是否可重复采样,True为Bagging方式,False为Pasting方式
oob_score: 是否使用没采样到的样本进行分数评估,接近测试集的分数,训练后通过oob_score_属性可查看

bootstrap_features: 是否对特征进行采样
max_features: 最大采样样本数


随机子空间方法设置:
bootstrap=False
max_samples=1.0
bootstrap_features=True
max_features<=1.0(可选)
'''
bag_clf = BaggingClassifier(
    DecisionTreeClassifier(),
    n_estimators=500, 
    max_samples=100, 
    bootstrap=True, 
    oob_score=True,
    n_jogs=-1
)
bag_clf.fit(X, y)

4.3 Bagging的应用——随机森林

以决策树算法作基模型进行Bagging有更加专门的算法模型——随机森林,对于决策树进行了特别的优化处理,Sciki-learn中有专门的API:RandomForestClassifier(分类)、RandomForestRegressor(回归)

from sklearn.ensemble import RandomForestClassifier

rnd_clf = RandomForestClassifier(
    n_estimators=200, 
    max_leaf_nodes=16, 
    n_jobs=-1)
rnd_clf.fit(X_train, y_train)

y_pred = rnd_clf.predict(X_test)

随机森林有一个作用:描述特征间的相对重要性高低,对于节点的分裂,是通过部分特征,指标是基尼系数或熵,通过衡量特征参与节点分类的次数可以表示其重要性。

不同特征的相对重要性高低通过参数feature_importances_可以进行展示。

4.4 使用建议

采用同样的基准算法(通常准确率较为接近),但想提高模型收益的情况,通过Bagging产生不同的数据样本,以产生相对独立的单个模型。

5. Boosting

Boosting是另外一种思路,前面两个集成学习是并行的,而Boosting是一种循序渐进的思路,通过后面的模型不断优化前面模型的缺陷。

Boosting中最常用的是:AdaBoost, Gradient Boosting

5.1 AdaBoost

AdaBoost全称是Adaptive Boosting,思想是通过叠加模型不断对前面模型表现不好的样本点进行着重训练(改变样本权重、也为不同次迭代的模型设定不同的权重)。

与前面模型的差别:

  1. 模型间存在递进式关系
  2. 模型和样本(训练时)都具有权重,另外还有学习率

流程:

  1. 计算当前模型错误率,根据错误率设置当前模型权重(需要再乘上一个学习率)
  2. 根据样本预测对错计算、调正样本权重
  3. 重复上述步骤,直到满足设定条件
  4. 模型权重进行归一化,按归一化权重组合所有模型

在Adaboost中也可使用决策树,但通常只需要使用深度为1的决策树,因为后续模型起到的作用相当于子树的作用了。

from sklearn.ensemble import AdaBoostClassifier

rnd_clf = AdaBoostClassifier(
    n_estimators=200, 
    max_leaf_nodes=16, 
    n_jobs=-1)
rnd_clf.fit(X_train, y_train)

y_pred = rnd_clf.predict(X_test)

5.2 Gradient Boosting

Gradient Boosting与AdaBoosting思路不同,后面模型的训练,不是通过更改预测出错样本的权重来改善训练,而是不同针对前面模型的残差进行着重训练,通常还是通过决策树进行计算,也称GBDT

因为是对残差训练,而且需要利用到梯度,所以需要输出连续值,采用的时决策回归树,最后通过数值所处的值区间确定最终的结果。

fromsklearn.ensembleimport GradientBoostingRegressor
gbdt = GradientBoostingRegressor(
    max_depth=2, 
    n_estimators=100, 
    learning_rate=1.0)
gbrt.fit(X_train, y_train)
y_pred = gbrt.predict(X_test)

Early Stopping

为了确定最佳的树数目(寻找最佳参数),需要知道为多少树时误差最小(准确率最高),只有一个个试,但是再Scikit-learn中有两种方式:

  1. 通过方法staged_predict(),在数据下测试,保存不同树数量下模型的对数据的测试结果(以迭代器形式存储,无法向量化操作),然后计算误差后选择最佳误差对应的树数量重新训练一个模型
  2. 通过设置参数warm_start=True,使模型能在之前模型下继续训练,保存此前模型参数,然后人为更改n_estimators的值(要按照树数量从低到高更改),然后循环训练找最佳误差的树数量(最佳参数)

第一种方式:

gbdt = GradientBoostingRegressor(max_depth=2, n_estimators=200)
gbdt.fit(X_train, y_train)

y_preds = gbdt.staged_predict(X_test)
from sklearn.metrics import mean_squared_error

errors = [mean_squared_error(y_pred, y_test) for y_pred in y_preds]
best_n = np.argmin(errors) + 1

gbdt_best = GradientBoostingRegressor(max_depth=2, n_estimators=best_n)
gbdt_best.fit(X_train, y_train)

第二种方式:

bdt = GradientBoostingRegressor(max_depth=2, warm_start=True)

min_test_error = float('inf')
error_going_up_times = 0
for n in range(1, 200):
    gbdt.n_estimators = n
    gbdt.fit(X_train, y_train)
    y_pred = gbdt.predict(X_test)
    test_error = mean_squared_error(y_pred, y_test)
    if test_error < min_test_error:
        min_test_error = test_error
        error_going_up_times = 0
    else:
        error_going_up_times += 1
        if error_going_up_times == 5:
            break
best_n = gbdt.n_estimators
gbdt_best = gbdt

Stochastic Gradient Boosting

GradientBoostingRegressor也支持采样的方式,指定后,比如0.3,那么每棵树训练时都是从数据中随机采样30%的数据量进行训练。用bias换variance,此时称为Stochastic Gradient Boosting

5.3 XGBoost

类似GBDT的思想进行设计,论文暂时未看,意味着Extreme Gradient Boosting,目标是非常快、具有可拓展性和便携性。安装如下

pip install xgboost

==待继续补充==

import xgboost
xgb_clf = xgboost.XGBClassifier(max_depth=2, n_estimators=200)
xgb_clf.fit(X_train, y_train)
y_pred = xgb_clf.predict(X_test)
accuracy_score(y_pred, y_test)

5.4 LightGBM

==待补充==

5.5 CatBoost

==待补充==

6. Stacking(Blending)

另外一种集成方法思路,全称是stacked generalization,相同思路不同的处理成为Blending(见下面内容),基于的思想:此前集成学习算法都集中在采样、模型训练,对于模型的集成,通常较为简单直接,Stacking通过专门再训练一个函数来处理模型间的集成(聚合)。将各模型的输入作为参数,函数处理后输出,有点类似激活函数。

最终要训练成的模型结构就很类似于神经网络的结构,一层层的,最终一层是一个模型,产生直接输出,训练方法有留出法Hold-out和K折K_Flod

6.1 hold-out式训练(Blending)

如果要训练L层Stacking模型,最后一层只有一个模型,记作$M^L$,假设其它层每层具有N个模型(因为同一层模型在同一个样本数据下训练,所有每个模型采用的算法要不同),第$i$层模型为$M_1^i, M_2^i, M_3^i...M_N^i$。训练方式如下:

  1. 先将训练数据分成$L$堆(通常等比例划分),为$D_1,D_2,...D_L$
  2. 在$D_1$上,训练出第一层的$N$个模型(都在所有的$D_1$样本下训练)
  3. 在$D_2$上,通过模型$M_1^1, M_2^1, ...M_N^1$进行预测产生$N$组输出,将$N$组输出当成一个整体,训练第二层$N$个模型(第二层的模型利用第一层的模型输出作为输入,以此形成堆叠结构)
  4. 重复上述操作,直至最后一层
  5. 在第$L$层,将$D_L$输入到堆叠好的$L-1$层模型中,产生的输出作为输入,训练一个模型$M^L$
  6. 堆叠所有$L$层的模型,形成最终的集成模型$M$

预测任务就是将测试集中的样本,输入到集成模型$M$中,对比输出和实际输出,进行效果评估。

6.2 K_Flod式训练(Stacking)

同样训练上述目标,

  1. 将模型分成K堆(同样等比例划分),为$D_1,D_2,...D_K$
  2. 训练第一层的N个模型,N个模型都是先在除了$D_1$外的所有数据下训练,并预测$D_1$产生预测值$D_1^1$
  3. 然后在除了$D_2$外的所有数据下训练相同的$N$个模型,并预测$D_2$产生预测值$D_2^1$
  4. 重复操作,直至产生预测值数据$D_1^1,D_2^1,...D_K^1$
  5. 然后在整个训练集上训练这$N$个模型,作为第一层,并且用该模型对所有验证集进行预测,产生预测值$D^1_t$
  6. 以$D_1^1,D_2^1,...D_K^1$为训练集,$D^1_t$为测试集,训练第二层模型
  7. 直至训练完$L-1$层模型后,按相同步骤训练最后一层,只不过将模型数目从$N$变为1,最后一层模型不用对前一层产生的预测集进行预测
  8. 堆叠所有$L$层的模型,形成最终的集成模型$M$

预测任务就是将测试集中的样本,输入到集成模型$M$中,对比输出和实际输出,进行效果评估。

6.3 Blending和Stacking

从上述步骤可以看出Blending和Stacking训练步骤存在差异,作以下总结

Blending

  • 训练更为简单
  • 泛化能力更强,不同层模型使用到了不同的数据
  • 训练更加安全(相比于Stacking)

Stacking

  • 训练更加复杂
  • 使用到了更多的数据
  • 可能对数据过拟合
  • 存在数据泄露的风险(训练途中用到了测试集)

Share this post
< Pre: GBDT+LR Pos: 天池推荐系统之新闻推荐 >
1 comment
Similar posts
Add a new comment