sklearn集成学习ensemble模块学习
一、前言
集成学习由数个基础学习器构成, 在表现上通常优于单个学习器。根据基础学习器的组合方式又分为bagging、boosting、stacking三大类,第一类经典模型为随机森林,第二类代表为梯度boosting,该类目前最受欢迎的有LGBM,GBDT,XGBoost。
1.算法原理
1.1 GBDT
GBDT的Boosting方法与众不同,它是一个由多棵CART决策回归树构成的加法模型。我们可以简单理解成最后整个模型的预测结果是所有回归树预测结果的和.其预测公式可以写为
y
∗
=
∑
i
m
f
(
x
,
θ
i
)
y^*=\sum_{i}^{m} f(x,\theta_i)
y∗=i∑mf(x,θi)
其中m为m个基模型,
θ
i
\theta_i
θi为第i个基模型对应的参数.
如何训练每一个基模型,这里涉及到了梯度与残差的概念,在线性回归当中我们使用梯度下降法是为了寻找最佳的参数,使得损失函数最小。实际上目前绝大多数的模型都是这么做的,计算梯度的目的是为了调整参数。但是GBDT不同,计算梯度是为了下一轮的迭代.
我们来举个例子,假设我们用线性回归拟合一个值,这里的目标y是20。我们当前的得到的是10,那么我们应该计算梯度来调整参数,明显应该将它调大一些从而降低偏差。
但是GBDT不是这么干的,同样假设我们第一棵回归树得到的结果也是10,和真实结果相差了10,我们一样来计算梯度。在回归问题当中,我们通常使用均方差MSE作为损失函数,那么我们可以来算一下这个函数的梯度。我们先写出损失函数的公式:
L
o
s
s
=
1
2
n
∑
i
n
(
y
i
−
f
(
x
i
)
)
2
Loss=\frac{1}{2n}\sum_{i}^{n} \left ( y_i-f(x_i) \right )^2
Loss=2n1i∑n(yi−f(xi))2
其中i是第i个样本,一共为n个样本.对损失函数f(x)进行求导取负即得到f(x)负梯度
1
n
∑
i
n
(
y
i
−
f
(
x
i
)
)
\frac{1}{n} \sum_{i}^{n} (yi-f(x_i))
n1i∑n(yi−f(xi))
可以看到这个个负梯度看起来刚好是我们要预测的目标值减去之前模型预测的结果。因此值得注意的是我们尝试GBDT是去拟合残差,本质是由损失函数计算负梯度得到的。
回归任务训练过程:
- 构建第一颗树,其标签是y,训练集为(x,y),损失函数为前面提到的均方误差,得到第一颗树的预测值 f 1 ( x i ) f_1(x_i) f1(xi),这样强学习强 F ( x ) = f 1 ( x ) F(x)=f_1(x) F(x)=f1(x);
- 训练第2颗树,计算当前强学习器下的残差,其公式如下,残差即为第2颗树的训练标签,训练集为(x_i,
r
2
i
r_{2i}
r2i),损失函数仍使用均方差,得到第二颗树的预测值
f
2
(
x
i
)
f_2(x_i)
f2(xi),这样强学习强
F
(
x
)
=
f
1
(
x
)
+
f
2
(
x
)
F(x)=f_1(x)+f_2(x)
F(x)=f1(x)+f2(x);
r 2 i = − ∂ L ( y i , F ( x i ) ) ∂ F ( x i ) r_{2i}=-\frac{\partial L(y_{i},F(x_i))}{\partial F(x_i)} r2i=−∂F(xi)∂L(yi,F(xi)),其中i表示第i个样本, F ( x i ) = f 1 ( x i ) F(x_i)=f_1(x_i) F(xi)=f1(xi).该式子也是负梯度计算. - 训练第m颗树,计算当前强学习器下的残差,其公式如下,残差即为第m颗树的训练标签,训练集为(x_i,
r
m
i
r_{mi}
rmi),损失函数仍使用均方差,得到第m颗树的预测值
f
m
(
x
i
)
f_m(x_i)
fm(xi),这样强学习强
F
(
x
)
=
f
1
(
x
)
+
f
2
(
x
)
+
…
+
f
m
(
x
i
)
F(x)=f_1(x)+f_2(x)+…+f_m(x_i)
F(x)=f1(x)+f2(x)+…+fm(xi);
r m i = − ∂ L ( y i , F ( x i ) ) ∂ F ( x i ) r_{mi}=-\frac{\partial L(y_{i},F(x_i))}{\partial F(x_i)} rmi=−∂F(xi)∂L(yi,F(xi)),其中i表示第i个样本, F ( x i ) = f 1 ( x i ) + f 2 ( x ) + … + f m − 1 ( x i ) F(x_i)=f_1(x_i)+f_2(x)+…+f_{m-1}(x_i) F(xi)=f1(xi)+f2(x)+…+fm−1(xi).该式子也是负梯度计算. - 记第j个样本在第m个弱学习器的输出为
c
m
j
c_{mj}
cmj,则强学习器输出可以表示为:
F ( x ) = ∑ m M ∑ j J ( c m j I ( x ∈ R m j ) ) F(x)= \sum_{m}^{M} \sum_{j}^{J}(c_{mj}I(x\in R_{mj})) F(x)=m∑Mj∑J(cmjI(x∈Rmj)),其中 R m j R_{mj} Rmj表示为第m个弱学习器所有叶结点的预测样本集合,若样本在该集合中,则 I I I为1,否则为0.
分类任务:
回归问题中,构建新数据集用的是负梯度值,就是用真实值减去预测值,但是在分类问题中,真实值和预测值都是类别,类别之间的相减是没有意义的。一种解决方案是,采用逻辑回归算法中的对数损失函数,用结果的预测概率值和真实概率值的差值作为残差。
这样残差可求得:
−
∂
L
(
y
i
,
F
(
x
i
)
)
∂
F
(
x
i
)
=
y
i
−
1
1
+
e
−
F
(
x
i
)
-\frac{\partial L(y_{i},F(x_i))}{\partial F(x_i)}=y_i-\frac{1}{1+e^{-F(x_i)}}
−∂F(xi)∂L(yi,F(xi))=yi−1+e−F(xi)1,其中
F
0
(
x
i
)
=
log
p
(
y
=
1
)
1
−
p
(
y
=
1
)
F_0(x_i)=\log{\frac{p(y=1)}{1-p(y=1)} }
F0(xi)=log1−p(y=1)p(y=1)为样本集的先验类别概率分布,以此作为初始预测值,然后按照残差公式进行残差计算(即将类别型标签转换为概率值标签).
通过上方求取每一次的残差进行下一个弱学习器拟合,得到强学习器
F
(
x
)
=
F
0
(
x
)
+
∑
m
M
∑
j
J
(
c
m
j
I
(
x
∈
R
m
j
)
)
F(x)=F_0(x)+ \sum_{m}^{M} \sum_{j}^{J}(c_{mj}I(x\in R_{mj}))
F(x)=F0(x)+∑mM∑jJ(cmjI(x∈Rmj)),通过sigmoid 函数转为类别概率输出,即:
y
i
=
1
1
+
e
−
F
(
x
i
)
y_i=\frac{1}{1+e^{-F(x_i)}}
yi=1+e−F(xi)1
Shrinkage–缩放:
Shinkage是一种优化避免GBDT陷入过拟合的方法,这个方法的本质是减小每一次迭代对于残差的收敛程度,认为每一次逼近少一些多次收敛的效果好于一次逼近很多,逼近次数较少的结果。具体的表现措施就是给我们的每一棵回归树的结果乘上一个类似于学习率的参数,通过增大回归树的个数来弥补。
Shrinkage的机制并没有一个明确的证明或者是感性的认识,它的效果更多是基于经验的。
我们写一下加上Shrinkage之后的方程来做个对比:
F
(
x
)
=
f
m
−
1
(
x
)
+
γ
∑
j
J
c
m
j
I
(
x
∈
R
m
j
)
F(x)=f_{m-1}(x)+\gamma \sum_{j}^{J} c_{mj}I(x\in R_{mj})
F(x)=fm−1(x)+γj∑JcmjI(x∈Rmj)
这里的就是我们的Shrinkage的参数,
γ
\gamma
γ一般取值在0.001到0.01之间。
优缺点
优点:
1、适用各类损失函数
2、适用回归与分类任务
1.2 Adaboost
AdaBoost的核心思路是通过使用Boosting的方法,通过一些弱分类器构建出强分类器来。我们的目的是通过设计样本和模型的权重,使得可以做出最佳决策,将这些弱分类器的结果综合出强分类器的效果来。
首先我们会给训练样本赋予一个权重,一开始的时候,每一条样本的权重均相等。根据训练样本训练出一个弱分类器并计算这个分类器的错误率。然后在同一个数据集上再次训练弱分类器,在第二次的训练当中,我们将会调整每个样本的权重。其中正确的样本权重会降低,错误的样本权重会升高。
具体流程如下:
1.初始化样本权重:
初始权重:
D
i
1
=
1
/
N
D_{i}^{1} = 1/N
Di1=1/N,其中N为训练样本集的大小,i为样本索引,1为第1次迭代。
2.训练弱分类器:
使用当前样本权重训练一个弱分类器
f
t
(
x
)
f^{t}(x)
ft(x),t表示第t次迭代。
3.计算分类错误率:
计算当前弱分类器的错误率:
ε
t
=
∑
(
D
(
i
)
t
∗
I
(
y
i
!
=
f
t
(
x
i
)
)
)
ε_t = \sum(D_{(i)}^{t} * I(y_i != f^t(x_i)))
εt=∑(D(i)t∗I(yi!=ft(xi))),其中
D
(
i
)
t
D_{(i)}^{t}
D(i)t为第t次迭代后样本i的权重,
y
i
y_i
yi为样本i的真实标签,
f
t
(
x
i
)
f^t(x_i)
ft(xi)为第t次迭代后弱分类器对样本i的预测值,I是一个指示函数,当条件成立时值为1,否则为0。
4.计算当前弱分类器的权重:
α
t
=
1
/
2
∗
l
n
(
(
1
−
ε
t
)
/
ε
t
)
α_t = 1/2 * ln((1 - ε_t) / ε_t)
αt=1/2∗ln((1−εt)/εt)
5.更新样本权重:
对于每个样本i,根据预测准确性来更新权重:
{
错误样本权重
:
D
i
t
+
1
=
D
i
t
∗
e
α
正确样本权重
:
D
i
t
+
1
=
D
i
t
∗
e
−
α
\begin{cases} 错误样本权重:D_{i}^{t+1}={D_{i}^{t}*{e^{\alpha}} } \\正确样本权重:D_{i}^{t+1}={D_{i}^{t}*{e^{-\alpha}} } \end{cases}
{错误样本权重:Dit+1=Dit∗eα正确样本权重:Dit+1=Dit∗e−α
,其中
D
t
+
1
(
i
)
D^{t+1}(i)
Dt+1(i)为第t+1次迭代后样本i的权重,
D
t
(
i
)
D^{t}(i)
Dt(i)为第t次迭代后样本i的权重,。
归一化样本权重:
规范化样本权重,使得它们之和等于1:
D
t
+
1
(
i
)
=
D
t
+
1
(
i
)
/
∑
(
D
t
+
1
(
i
)
)
D^{t+1}(i) = D^{t+1}(i) /\sum(D^{t+1}(i))
Dt+1(i)=Dt+1(i)/∑(Dt+1(i))
6.继续迭代
重复步骤2-6,直到达到预定的迭代次数或者错误率已经足够小。
通过上述公式,可以动态更新样本权重,使得每个迭代中的弱分类器更关注于上一轮被错误分类的样本,最终得到一个强分类器。则最后输出由多个弱学习及其权重加和得到,分类中再加一个符号函数
F
(
x
)
=
S
i
g
n
(
∑
i
m
α
i
f
i
(
x
)
)
F(x)=Sign(\sum_{i}^{m} \alpha_if_i(x))
F(x)=Sign(i∑mαifi(x))
回归任务
当用于回归任务时,错误率的计算变为
E
i
=
∣
y
i
−
y
^
i
∣
E_i = |y_i - \hat{y}_i|
Ei=∣yi−y^i∣,其模型权重计算方式不变,其样本权重计算方式如下,因为回归无正确与错误之分,因此在权重更新中更关注错误率高的样本,加大改样本的权重.再进行权重的归一化.
w
i
=
w
i
⋅
exp
(
−
α
t
⋅
sign
(
E
i
)
)
w_i = w_i \cdot \exp \left( -\alpha_t \cdot \text{sign}(E_i) \right)
wi=wi⋅exp(−αt⋅sign(Ei))
其中sign 函数是一个数学函数,它用于返回一个数的符号。它的定义如下:
如果输入的数是正数,则返回 1。
如果输入的数是负数,则返回 -1。
如果输入的数是零,则返回 0。
优缺点
缺点:异常值敏感,无法并行
优点:适用多类任务,较少基学习器即可达到不错的效果
1.3 Random forests
随机森林是bagging的集成学习方法,可以并行生成多个决策树模型,在做分类时遵循少数服从多数原则,做回归采用各决策树的均值作为输出.
其具体训练过程如下:
1、训练子集获取
采用有放回的抽样方法从样本集中抽取得到训练子集,(该方法约36%的样本未被抽取到)
2、决策树搭建
在搭建过程中,划分点的候选特征集可以增加随机性(如随机抽取总候选集的logm个数特征作为当前划分的候选特征集)
3、预测测试集
每一个测试样本输入所有决策树,而后按照多数投票法或者均值得到测试样本的最终输出.
二、GBDT
本库中实现了两种GBDT,一种是经典的实现(如前面的原理),另一种是基于直方图的实现(由light GBDT得到灵感).当样本上万时,后者要比前者快几个数量级.后者天然支持类别型特征与缺失值,无需额外的处理过程.当小样本时可能更适合使用前者,由于后者的分箱后的划分点可能会很相似.
应用
1、缺失值支持
在基于直方图的实现中,
- 特征划分时缺失:计算划分到左子树与右子树的增益,选择增益最大的划入.
- 样本划分缺失时:训练集中有缺失,则按照训练集划分的结果进行划分;若训练集中无缺失,划入样本更多的那个子树
- 类别型特征缺失:划分时选择增益最大的类别划入.样本预测时,逻辑不变.
2、样本权重支持
通过下面代码设置样本权重,在计算分箱梯度与hessians时会将样本权重考虑进去,不过在建立分箱时不会考虑样本权重.
X = [[1, 0],
[1, 0],
[1, 0],
[0, 1]]
y = [0, 0, 1, 0]
# ignore the first 2 training samples by setting their weight to 0
sample_weight = [0, 0, 1, 1]
gb = HistGradientBoostingClassifier(min_samples_leaf=1)
gb.fit(X, y, sample_weight=sample_weight)
gb.predict([[1, 0]])
gb.predict_proba([[1, 0]])[0, 1]
3、类别型数据支持
类别型数据分箱的几种方式:
- 无排序合并直接按类别,将样本分箱:优点是包含了所有类别的信息,缺点是在类别较多的情况下,分箱过细,计算量加大,其树变深,可能会出现过拟合的问题。
- onehot转化分箱:将类别数据通过onehot进行转化后,每一维为一个分箱;缺点是以每个类别作为一个分箱,导致分箱数量过多,消耗过多的计算资源,并且可能会出现过拟合的问题。
- 排序合并分箱:按类别划分样本,计算各类别下的样本均值,样本数等统计类信息用于衡量类别间的差异,差异小的进行合并,合并后按新类别将样本分箱.优点是合并一些相似的类别,提升计算效率,缺点是被合并的类别信息会丢失.
使用类别型分箱可以通过下面代码进行设置
#传递所有列是否为类别型bool值数组
gbdt = HistGradientBoostingClassifier(categorical_features=[True, False])
#传递类别所在列的下标
gbdt = HistGradientBoostingClassifier(categorical_features=[0])
#DataFrame传递类别的列名
gbdt = HistGradientBoostingClassifier(categorical_features=["site", "manufacturer"])
#从DataFrame训练集中的数据类型自动推断类别(category)
gbdt = HistGradientBoostingClassifier(categorical_features="from_dtype")
分箱后,是如何寻找类别型特征的划分点的呢?算法通过目标方差对分箱进行排序,这样就可以按照连续特征一样处理,若有k个分箱,则计算k个划分点的判定准则,由此得到最终划分点.因此该种策略的时间复杂度为排序时间复杂度加上划分点计算复杂度
O
(
k
log
k
+
k
)
O(k\log k+k)
O(klogk+k)
4、单调性限制支持与交互特征限制支持
- 单调性限制:当其它输入一致,某一个特征上涨其输出也应该上涨(或负向单调,上涨输出下降);如输出贷款概率,输入一致,信用分越高其获得贷款的概率应该越大.值得注意的是该限制是作用在输出上,且不适应多分类任务,在实际使用中可以通过下方代码进行设置
from sklearn.ensemble import HistGradientBoostingRegressor
# monotonic increase, monotonic decrease, and no constraint on the 3 features
gbdt = HistGradientBoostingRegressor(monotonic_cst=[1, -1, 0])
- 交互特征限制:在一些情况下,特征之间的交互作用对预测结果可能有重要影响。这意味着当选择一个特征进行分裂时,只能考虑与该特征具有交互作用的其他特征进行分裂,而不能考虑其他无关的特征。比如购买一台手机,考率品牌与功能,在对品牌特征进行划分后,下一次可划分的特征便只能在品牌与功能特征中选择划分点.在实际使用中可以通过下方代码进行设置
from sklearn.ensemble import HistGradientBoostingRegressor
# forbids all interactions on the 3 features
gbdt = HistGradientBoostingRegressor(interaction_cst=[{0}, {1}, {2}])
# Features 0 and 1 may interact with each other, as well as features 1 and 2. But note that features 0 and 2 are forbidden to interact.
gbdt = HistGradientBoostingRegressor(interaction_cst=[{0, 1}, {1, 2}])
5、低层级并行支持
可以并行计算的点如下
- 搭建个特征的分箱
- 将样本按阈值划分到各箱中
- 计算各特征划分点
- 将各样本进行子树划分
- 计算样本的梯度与hessian
- 样本预测
6、模型搭建(重点参数+属性)
参数列表
经典GBDT(GradientBoostingClassifier)参数列表如下,其中重要的参数有learnong_rate(缩放作用),n_estimators
序号 | 参数名 | 含义 | 应用 |
---|---|---|---|
1 | loss | 损失函数 | ’log_loss’对数熵用于分类,{‘squared_error’, ‘absolute_error’, ‘huber’, ‘quantile’}, default=’squared_error’用于回归 |
2 | learnong_rate | 学习率 | 起到缩放作用与n_estimators有相互作用,取值范围(0,1) |
3 | n_estimators | 基学习器个数 | 确定了基模型的规模,默认100 |
4 | subsample | 子样本占比 | 用于获取单个基学习器的训练集生成,默认为1不做采样,取值范围(0,1) |
5 | criterion | 评判准则 | {‘friedman_mse’, ‘squared_error’}用于评价树的划分质量 |
6 | init | 指定初始化模型的方式 | None:表示从头开始训练;estimator对象:使用给定的estimator对象作为初始化模型如已经训练好的其他回归或分类模型,其预测结果将被用作GBDT模型的初始预测值。 |
7 | n_iter_no_change | 提前停止迭代 | 若设置一个大于1的n,则在n个迭代中,验证集无提升则停止迭代 |
8 | validation_fraction | 验证集比例 | 从训练集中留出一部分做验证 |
9 | warm_start | 是否已训练 | 默认False,否则允许像已经拟合好的模型中添加更多的基模型 |
10 | 其它 | 一批树结构参数 | 用于预防过与欠拟合 |
基于直方图GBDT(GradientBoostingClassifier)参数列表如下 | |||
1 | max_bins | 最大分箱数 | |
2 | categorical_features | 类别型特征说明 | 见前文的用法 |
3 | monotonic_cst | 单调性说明 | 见前文的用法 |
4 | interaction_cst | 交互特征说明 | 见前文的用法 |
5 | early_stopping | 早期停止设置 | ‘auto’ or bool, default=’auto’,为自动时,样本超过1万,该设置可用 |
6 | scoring | 评分 | 与第5点配合使用,str or callable or None,为None时采用的是损失函数 |
7 | verbose | 冗余等级设置 | 不为零时在拟合过程中会输出一些信息 |
特征重要性
单颗树的特征重要性可以直接通过树的结构得到,而GBDT中是多颗树,在本库中通过计算各树在该特征上的非纯度下降值的均值,来得到各特征的重要性.该方法有两点潜在的缺陷,从而可能得到错误的结论.
- 对取值较多的特征有偏向
- 由训练集统计得到而不是对获得好预测的支撑数据集得到的
方法Permutation feature importance 则不会有该缺陷,其核心思想是对单个特征的取值进行随机打散,来观看模型效果下降程度.通过打破特征与目标之间的关系,从而得到模型对每个特征的依赖性.
三、随机森林与其它随机树集成学习
1.随机森林
有两个随机点(一单个决策树训练集为有放回随机抽样得到,二在划分时候选特征集是总特征候选集中随机抽取的子集),来降低决策树的复杂度,增加决策树之间的差异性;提升随机森林的在方差降低上的效果,降低过拟合风险(可能会损失些许偏差).
随机森林VS 基于直方图的GBDT
- 决策树生成差异:随机森林的依赖的树往往比较深(单颗树过拟合风险高),单颗树拟合所需计算量大;GBDT生成的树较浅,拟合快计算量较小(单颗树过拟合风险低).
- 顺序提升差异:GBDT是按顺序生成树,当前树由前面的树拟合的残差进行生成;因此较少颗树下就能得到较好的预测效果;相比之下随机森林需要训练更多的树才能达到同等预测效果.
- 高效分箱差异:GBDT基于直方图进行分箱与预计算,拟合计算量小;而随机森林没有分箱处理,每一次划分都需要计算所有候选集的特征与所有候选划分点,所需计算量大,计算资源所需更多.
2.极端随机森林
与随机森林的区别在于,在随机森林中寻找每个特征的最佳划分点对应的收益,然后对比各特征间的收益,取最佳收益的特征与作为划分的特征;而在极端随机森林中,随机寻找每个特征的划分点,计算对应的收益,然后对比各特征间的收益,取最佳收益的特征与作为划分的特征.该中方式可以进一步降低方差,然模型的偏差增加的风险进一步增加.
3.参数
- 随机森林中最重要的参数为n_estimators 与
max_features.前者是树的颗树,理论上越多越好,计算量越大.在实际应用中,在超过一个关键数后,模型效果提升便不显著了.后者是划分时的候选特征集的参数设置,通常在回归任务中使用全部候选特征较好(默认设置为1或None),在分类任务中使用全部候选特征的根号数特征(设置为"sqrt"). - 参数设置max_depth=None 配合 min_samples_split=2,通常能取得不错的效果(在没有其它树结构限制时)
- 随机森林中抽样参数bootstrap默认是True,而极端随机森林中默认是False;该参数为开启时,可以设置oob_score=True使用袋外数据对模型泛化性能评估
当然上述配置不一定是最优配置,建议使用交叉验证寻找最优参数.
序号 | 参数名 | 含义 | 应用 |
---|---|---|---|
1 | criterion | 评判准则 | {“gini”, “entropy”, “log_loss”}, default=”gini” |
2 | bootstrap | 有放回抽样设置 | 见上文 |
3 | n_estimators | 基学习器个数 | 确定了基模型的规模,默认100 |
4 | max_features | 候选特征集设置 | {“sqrt”, “log2”, None}, int or float, default=”sqrt” |
5 | n_jobs | 并行job数 | -1表示使用所有进程 |
6 | warm_start | 是否已训练 | 默认False,否则允许像已经拟合好的模型中添加更多的基模型 |
7 | monotonic_cst | 单调性说明 | 见前文的用法 |
8 | verbose | 冗余等级设置 | 不为零时在拟合过程中会输出一些信息 |
9 | oob_score | 袋外样本评估 | 见上文 |
10 | 其它 | 一批树结构参数 | 用于预防过与欠拟合 |
4.特征重要性
在本库中采用树在该特征上的非纯度下降值以及该特征所影响的样本比例两者联合得到特征重要性评分,最后取各树均值得到该特征最终的重要性评分.
5.RandomTreesEmbedding随机森林嵌入
无监督学习,通过数据点最终所在的叶子的索引对数据进行编码,最终编码规模为n_estimators * 2 ** max_depth.该变换实现了一个隐式的无参的密度估计.
四、其它基学习器下的bagging 集成学习
关键设置在于训练基模型的训练集生成,以及候选特征集的生成.参数max_samples 与 max_features决定训练集占总样本比例,以及特征集占总特征集的比例,参数bootstrap and bootstrap_features决定了数据集生成的方式,为true 时为有放回的抽样,此时可以联合oob_score=True使用;为False则为随机抽样.
下面代码片段展示了使用近邻算法作为基学习器的bagging集成学习
from sklearn.ensemble import BaggingClassifier
from sklearn.neighbors import KNeighborsClassifier
bagging = BaggingClassifier(KNeighborsClassifier(),
max_samples=0.5, max_features=0.5)
五、投票分类/回归任务
常见投票有两种策略,大多数胜出法与权重平均法,前者称为硬投票,后者为软投票.
1.硬投票分类
大多数胜出法,即选择基学习输出最多的那个类,若输出票数相同,则选择排序最前的那个类.具体操作例子如下代码所示:
from sklearn import datasets
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import VotingClassifier
iris = datasets.load_iris()
X, y = iris.data[:, 1:3], iris.target
clf1 = LogisticRegression(random_state=1)
clf2 = RandomForestClassifier(n_estimators=50, random_state=1)
clf3 = GaussianNB()
eclf = VotingClassifier(
estimators=[('lr', clf1), ('rf', clf2), ('gnb', clf3)],
voting='hard')
for clf, label in zip([clf1, clf2, clf3, eclf], ['Logistic Regression', 'Random Forest', 'naive Bayes', 'Ensemble']):
scores = cross_val_score(clf, X, y, scoring='accuracy', cv=5)
print("Accuracy: %0.2f (+/- %0.2f) [%s]" % (scores.mean(), scores.std(), label))
2.软投票分类
软投票是指基学习对每一个类的输出乘以该学习器的权重,然后求均值,取最大值所对应的类为最终结果,当各学习器权重一致时则为简单的平均法,该方法要求基学习要能输出概率值.其具体计算例子如下(3个基学习器权重为[w1=1,w2=1,w3=1]):
其具体代码例子如下:
from sklearn import datasets
from sklearn.tree import DecisionTreeClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
from itertools import product
from sklearn.ensemble import VotingClassifier
# Loading some example data
iris = datasets.load_iris()
X = iris.data[:, [0, 2]]
y = iris.target
# Training classifiers
clf1 = DecisionTreeClassifier(max_depth=4)
clf2 = KNeighborsClassifier(n_neighbors=7)
clf3 = SVC(kernel='rbf', probability=True)
eclf = VotingClassifier(estimators=[('dt', clf1), ('knn', clf2), ('svc', clf3)],
voting='soft', weights=[2, 1, 2])
clf1 = clf1.fit(X, y)
clf2 = clf2.fit(X, y)
clf3 = clf3.fit(X, y)
eclf = eclf.fit(X, y)
3.投票回归任务
回归里,没有大多数胜出概念,因此只有软投票方法.其使用方法与分类任务类似,调用方法为from sklearn.ensemble import VotingRegressor,其基学习器对应为回归类算法.
六、堆叠泛化(Stacked generalization)
其含义是并行训练多个基学习器,其输出作为最终基学习器(元学习器)的输入,输出标签不变;拟合好的最终基学习器的输出即为最终预测.其具体流程如下:
- 基学习器拟合:对数据集划分为训练集,测试与验证集,使用训练集训练多个基学习器;
- 元学习器拟合:获取基学习在验证集上的预测输出,联合原始的特征(基学习器训练时输入的特征),得到元学习器的输入meta_features_val;以及验证集的标签y_val;构成元学习器的训练集,训练元学习器.
meta_features_val = [X_val, dt_pred, svm_pred, knn_pred] - 预测:预测时先输入基学习器得到基学习器预测,然后整合得到元学习器的输入如下式子,由此得到元学习器的输出即最终预测.
meta_features_test = [X_test, dt_pred_test, svm_pred_test, knn_pred_test]
在本库中,其相关方法与使用参考如下代码例子:
# 选择基学习器
from sklearn.linear_model import RidgeCV, LassoCV
from sklearn.neighbors import KNeighborsRegressor
estimators = [('ridge', RidgeCV()),
('lasso', LassoCV(random_state=42)),
('knr', KNeighborsRegressor(n_neighbors=20,
metric='euclidean'))]
# 选择元学习器 并堆叠起来
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.ensemble import StackingRegressor
final_estimator = GradientBoostingRegressor(
n_estimators=25, subsample=0.5, min_samples_leaf=25, max_features=1,
random_state=42)
reg = StackingRegressor(
estimators=estimators,
final_estimator=final_estimator)
# 训练
from sklearn.datasets import load_diabetes
X, y = load_diabetes(return_X_y=True)
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y,
random_state=42)
reg.fit(X_train, y_train)
# 预测
y_pred = reg.predict(X_test)
from sklearn.metrics import r2_score
print('R2 score: {:.2f}'.format(r2_score(y_test, y_pred)))
还可以进行多层叠加学习,然该种方法虽然有较好的表现,但计算量消耗太大.
七、Adaboost
原理前言中已介绍不再赘述,主要介绍本库中的使用方式与相关参数.
其关键参数n_estimators,要控制单个基学习器的复杂度可以通过参数max_depth或者min_samples_split.
本库中默认基学习器是一层的决策树(decision stumps),以方法AdaBoostClassifier为例,其参数见下表
序号 | 参数名 | 含义 | 应用 |
---|---|---|---|
1 | estimator | 基学习器 | 可以在基学习器中设置其参数,如深度,类权重等 |
2 | n_estimators | 基学习器个数 | 确定了基模型的规模,默认50 |
3 | learning_rate | 基学习器权重 | float, default=1.0,更大的值会提升每一个基学习器的权重 |
4 | algorithm | 算法选择 | default=”SAMME” |
5 | random_state | 随机状态 | 作用在每一个基学习器随机种子设置上 |
其具体使用代码如下: |
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_iris
from sklearn.ensemble import AdaBoostClassifier
X, y = load_iris(return_X_y=True)
clf = AdaBoostClassifier(n_estimators=100, algorithm="SAMME",)
scores = cross_val_score(clf, X, y, cv=5)
scores.mean()