集成学习依据个体学习器之间是否存在依赖关系分为两类:一类是个体学习器之间存在强依赖关系,其代表算法是boosting算法;另一类是个体学习器之间不存在强依赖关系,代表算法是bagging算法。AdaBoost是最著名的算法之一,既可以做分类问题,也可以解决回归问题。
AdaBoost算法
Boosting的思想是对于一个复杂模型,每一个学习器是一个弱学习器,其学习能力有限,并不能很好的学习模型中的复杂特征,但是将每一个弱学习器学习的模型组合在一起形成一个强学习器,大大地提升了模型的学习能力,正所谓“三个臭皮匠顶个诸葛亮”。
假设给定一个二类分类的训练集
T
=
{
(
x
1
,
y
1
)
,
(
x
2
,
y
2
)
,
.
.
.
,
(
x
N
,
y
N
)
}
T=\left\{(x_1,y_1),(x_2,y_2),...,(x_N,y_N)\right\}
T={(x1,y1),(x2,y2),...,(xN,yN)}
x
i
x_i
xi是n维向量,有n个特征,
x
i
∈
X
⊆
R
n
x_i\in \mathcal X \subseteq R^n
xi∈X⊆Rn;
y
i
y_i
yi是类别标签,
y
i
∈
Y
=
{
−
1
,
+
1
}
y_i\in \mathcal {Y}=\left\{-1,+1\right\}
yi∈Y={−1,+1},
X
\mathcal X
X是实例空间,
Y
\mathcal Y
Y是标记集合。AdaBoost利用以下算法,从训练数据中学习一系列弱分类器(基分类器),并将这些弱分类器线性组合成一个强分类器。
在介绍AdaBoost算法之前,先思考以下这些问题:
- 每一个弱学习器是如何训练得到的
- 如何将这些弱学习器组合在一起合成一个强学习器
- 如何通过这些组合的强学习器预测最终的结果
算法
输入:训练数据集
T
=
{
(
x
1
,
y
1
)
,
(
x
2
,
y
2
)
,
.
.
.
,
(
x
N
,
y
N
)
}
T=\left\{(x_1,y_1),(x_2,y_2),...,(x_N,y_N)\right\}
T={(x1,y1),(x2,y2),...,(xN,yN)},其中
x
i
∈
X
⊆
R
n
x_i\in \mathcal X \subseteq R^n
xi∈X⊆Rn,
y
i
∈
Y
=
{
−
1
,
+
1
}
y_i\in \mathcal {Y}=\left\{-1,+1\right\}
yi∈Y={−1,+1};弱分类器;
输出:最终分类器
G
(
x
)
G(x)
G(x)
- 初始化训练数据的权值分布 D 1 = ( W 11 , W 12 , . . . , W 1 i , . . . , W 1 N ) , W 1 i = 1 N , i = 1 , 2 , 3 , . . . , N D_1=(W_{11},W_{12},...,W_{1i},...,W_{1N}), W_{1i}=\frac{1}{N},i=1,2,3,...,N D1=(W11,W12,...,W1i,...,W1N),W1i=N1,i=1,2,3,...,N
- 对于
m
=
1
,
2
,
.
.
.
,
M
m=1,2,...,M
m=1,2,...,M,训练每一个弱分类器
G
m
(
x
)
G_m(x)
Gm(x)
(a) 使用具有权值分布 D m D_m Dm的训练数据集学习,得到基分类器 G m ( x ) : X → { − 1 , + 1 } G_m(x):\mathcal X\rightarrow\left\{-1,+1\right\} Gm(x):X→{−1,+1}
(b) 计算 G m ( x ) G_m(x) Gm(x)在训练数据集上的分类误差率 e m = ∑ i = 1 N P ( G m ( x i ) = ̸ y i ) = ∑ i = 1 N W m i I ( G m ( x i ) = ̸ y i ) e_m=\sum_{i=1}^NP(G_m(x_i) =\not y_i)=\sum_{i=1}^NW_{mi}I(G_m(x_i) =\not y_i) em=i=1∑NP(Gm(xi)≠yi)=i=1∑NWmiI(Gm(xi)≠yi)
(c) 计算 G m ( x ) G_m(x) Gm(x)的系数,其表示该弱分类器的重要性 α m = 1 2 l o g 1 − e m e m \alpha_m=\frac{1}{2}log\frac{1-e_m}{e_m} αm=21logem1−em
(d) 更新训练数据集的下一轮的权值分布 D m + 1 = ( W m + 1 , 1 , W m + 2 , 2 , . . . , W m + 1 , i , . . . , W m + 1 , N ) D_{m+1}=(W_{m+1,1},W_{m+2,2},...,W_{m+1,i},...,W_{m+1,N}) Dm+1=(Wm+1,1,Wm+2,2,...,Wm+1,i,...,Wm+1,N) W m + 1 , i = W m i Z m e x p ( − α m y i G m ( x i ) ) W_{m+1,i}=\frac{W_{mi}}{Z_m}exp(-\alpha_my_iG_m(x_i)) Wm+1,i=ZmWmiexp(−αmyiGm(xi)) Z m Z_m Zm是规划化因子,归一化处理。 Z m = ∑ i = 1 N W m i e x p ( − α m y i G m ( x i ) ) Z_m=\sum_{i=1}^NW_{mi}exp(-\alpha_my_iG_m(x_i)) Zm=i=1∑NWmiexp(−αmyiGm(xi))它使得 D m + 1 D_{m+1} Dm+1成为一个概率分布。 - 构建基分类器的线性组合 f ( x ) = ∑ m = 1 M α m G m ( x ) f(x)=\sum_{m=1}^M\alpha_mG_m(x) f(x)=m=1∑MαmGm(x)得到最终的分类器 G ( x ) = s i g n ( f ( x ) ) = s i g n ( ∑ m = 1 M α m G m ( x ) ) G(x)=sign(f(x))=sign(\sum_{m=1}^M\alpha_mG_m(x)) G(x)=sign(f(x))=sign(m=1∑MαmGm(x))
AdaBoost算法的解释说明
步骤1:假设训练数据集具有均匀的权值分布,即每个训练样本在基分类器的学习作用相同,数据集样本的权重初始化,这一假设保证能够在原始数据上学习基分类器
G
1
(
x
)
G_1(x)
G1(x)。
步骤2:AdaBoost迭代学习基分类器,在每一轮
m
=
1
,
2
,
.
.
.
,
M
m=1,2,...,M
m=1,2,...,M按顺序执行以下操作:
(a) 使用当前分布
D
m
D_m
Dm加权的训练数据集,学习基分类器
G
m
(
x
)
G_m(x)
Gm(x)。
(b) 计算基分类器
G
m
(
x
)
G_m(x)
Gm(x)在加权训练数据集上的分类错误率:
e
m
=
∑
i
=
1
N
P
(
G
m
(
x
i
)
=
̸
y
i
)
=
∑
G
m
(
x
i
)
=
̸
y
i
W
m
i
e_m=\sum_{i=1}^NP(G_m(x_i)=\not y_i)=\sum_{G_m(x_i)=\not y_i}W_{mi}
em=i=1∑NP(Gm(xi)≠yi)=Gm(xi)≠yi∑Wmi
W
m
i
W_{mi}
Wmi表示第m轮中第i个实例的权值,
∑
i
=
1
N
W
m
i
=
1
\sum_{i=1}^NW_{mi}=1
∑i=1NWmi=1,表明
G
m
(
x
)
G_m(x)
Gm(x)在加权的训练数据集上的分类误差率是被
G
m
(
x
)
G_m(x)
Gm(x)误分类样本的权值之和。
(c) 计算基分类器
G
m
(
x
)
G_m(x)
Gm(x)的系数
α
m
\alpha_m
αm,
α
m
\alpha_m
αm表示
G
m
(
x
)
G_m(x)
Gm(x)在最终分类器中的重要性。当
e
m
≤
1
2
e_m\leq \frac{1}{2}
em≤21时,
α
m
≥
0
\alpha_m\ge 0
αm≥0,并且
α
m
\alpha_m
αm随着
e
m
e_m
em的减少而增大,所以分类误差率越小的基分类器在最终分类器中的作用越大。
(d) 更新训练数据的权值分布为下一轮做准备
W
m
+
1
,
i
=
{
W
m
i
Z
m
e
−
α
m
,
G
m
(
x
i
)
=
y
i
W
m
i
Z
m
e
α
m
,
G
m
(
x
i
)
=
̸
y
i
W_{m+1,i} = \begin{cases} \frac{W_{mi}}{Z_m}e^{-\alpha_m}, G_m(x_i)=y_i \\ \frac{W_{mi}}{Z_m}e^{\alpha_m},G_m(x_i)=\not y_i \end{cases}
Wm+1,i={ZmWmie−αm,Gm(xi)=yiZmWmieαm,Gm(xi)≠yi
由此可知,被基分类器
G
m
(
x
)
G_m(x)
Gm(x)误分类样本的权值在扩大,而被正确分类样本的权值在缩小。相比较,误分类样本的权值被放大
e
2
α
m
=
1
−
e
m
e
m
e^{2\alpha_m}=\frac{1-e_m}{e_m}
e2αm=em1−em倍。正确分类的样本在下一轮的训练过程中的权重较小,而误分类样本在下一轮的学习权重较大。对于全体训练数据集,在每一轮训练之前更新对应的权重分布,使得训练数据在基分类器的学习中起着不同的作用。
步骤3:线性组合
f
(
x
)
f(x)
f(x)实现M个基分类器的加权表决。系数
α
m
\alpha_m
αm表示基分类器
G
m
(
x
)
G_m(x)
Gm(x)的重要程度。
f
(
x
)
f(x)
f(x)的符号决定了实例x的类别。
AdaBoost算法实例




AdaBoost的核心思想在于样本权重的更新和弱分类器权值的生成,样本权重的更新保证了前面的弱分类器重点处理普遍情况,后续的分类器重点处理疑难杂症。最终,弱分类器加权组合保证了前面的弱分类器会有更大的权重,这其实有先抓总体,再抓特例的分而治之思想。
AdaBoost算法的另一种解释
AdaBoost算法的目标是学习每一个弱学习器 G m ( x ) G_m(x) Gm(x)和对应的权重系数 α m \alpha_m αm,然后将这些弱学习器线性组合成一个强学习器。因此,AdaBoost模型是加法模型,学习算法为前向分步算法。其中前向分步算法事实上是通过每一轮的弱学习器学习,利用前N轮的弱学习器的结果来更新后一个弱学习器的训练模型。
例如,前k-1轮的强学习器为:
f
k
−
1
(
x
)
=
∑
i
=
1
k
−
1
α
i
G
i
(
x
)
f_{k-1}(x)=\sum_{i=1}^{k-1}\alpha_iG_i(x)
fk−1(x)=i=1∑k−1αiGi(x)
目标是使前向分步算法得到的
α
k
,
G
k
(
x
)
\alpha_k,G_k(x)
αk,Gk(x)使
f
k
(
x
)
f_{k}(x)
fk(x)在训练数据集上的损失最小,即
(
α
k
,
G
k
(
x
)
)
=
a
r
g
min
α
,
G
∑
i
=
1
N
L
(
y
i
,
f
k
−
1
(
x
)
+
α
G
(
x
)
)
(\alpha_k,G_k(x))=arg\min_{\alpha,G}\sum_{i=1}^NL(y_i,f_{k-1}(x)+\alpha G(x))
(αk,Gk(x))=argα,Gmini=1∑NL(yi,fk−1(x)+αG(x))
则第k轮的强学习器为:
f
k
(
x
)
=
f
k
−
1
(
x
)
+
α
k
G
k
(
x
)
f_k(x)=f_{k-1}(x)+\alpha_kG_k(x)
fk(x)=fk−1(x)+αkGk(x)
可见强学习器是通过前向分步学习算法一步步叠加得到的。
AdaBoost实践
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
print('Loading data...')
# load data
iris = load_iris()
data = iris.data
target = iris.target
print('Plotting scatter...')
# plot
def plot(data,target):
x0,y0 = [],[]
x1,y1 = [],[]
x2,y2 = [],[]
for i in range(len(data)):
if target[i] == 0:
x0.append(data[i][0])
y0.append(data[i][1])
elif target[i] == 1:
x1.append(data[i][0])
y1.append(data[i][1])
else:
x2.append(data[i][0])
y2.append(data[i][1])
plt.scatter(x0,y0,c='b',marker='o',label='0')
plt.scatter(x1,y1,c='r',marker='o',label='1')
plt.scatter(x2,y2,c='g',marker='o',label='2')
plt.legend()
plt.show()
plot(data,target)
iris数据集分布如下图

from sklearn.ensemble import AdaBoostClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
from sklearn.datasets import load_iris
print('Loading data...')
# load data
iris = load_iris()
data = iris.data
target = iris.target
X_train,X_test,y_train,y_test = train_test_split(data,target,test_size=0.8,random_state=2019)
print('Starting training...')
# train
clf = AdaBoostClassifier(n_estimators=20,
learning_rate=0.05,
algorithm='SAMME.R',
random_state=20)
clf.fit(X_train,y_train)
print('Predicting with the trained model...')
y_pred = clf.predict(X_test)
print('Evaluating model...')
print("the precise of the model's prediction is:",precision_score(y_test,y_pred,average='macro'))
print("the recall of the model is :",recall_score(y_test,y_pred,average='macro'))
print('the f1_score of the model is :',f1_score(y_test,y_pred,average='macro'))
print('the feature importance of model is:',list(clf.feature_importances_))
运行结果如下
Loading data...
Starting training...
Predicting with the trained model...
Evaluating model...
the precise of the model's prediction is: 0.923060391145
the recall of the model is : 0.915363769022
the f1_score of the model is : 0.915824915825
the feature importance of model is: [0.10000000000000001, 0.0, 0.55000000000000004, 0.34999999999999998]
sklearn.ensemble.AdaBoostClassifier
- algorithm:这个参数只有AdaBoostClassifier有。主要原因是scikit-learn实现了两种Adaboost分类算法,SAMME和SAMME.R。两者的主要区别是弱学习器权重的度量,SAMME使用了和我们的原理篇里二元分类Adaboost算法的扩展,即用对样本集分类效果作为弱学习器权重,而SAMME.R使用了对样本集分类的预测概率大小来作为弱学习器权重。由于SAMME.R使用了概率度量的连续值,迭代一般比SAMME快,因此AdaBoostClassifier的默认算法algorithm的值也是SAMME.R。我们一般使用默认的SAMME.R就够了,但是要注意的是使用了SAMME.R, 则弱分类学习器参数base_estimator必须限制使用支持概率预测的分类器。SAMME算法则没有这个限制。
- n_estimators: AdaBoostClassifier和AdaBoostRegressor都有,就是我们的弱学习器的最大迭代次数,或者说最大的弱学习器的个数。一般来说n_estimators太小,容易欠拟合,n_estimators太大,又容易过拟合,一般选择一个适中的数值。默认是50。在实际调参的过程中,我们常常将n_estimators和下面介绍的参数learning_rate一起考虑。
- learning_rate: AdaBoostClassifier和AdaBoostRegressor都有,即每个弱学习器的权重缩减系数ν
- base_estimator:AdaBoostClassifier和AdaBoostRegressor都有,即我们的弱分类学习器或者弱回归学习器。理论上可以选择任何一个分类或者回归学习器,不过需要支持样本权重。我们常用的一般是CART决策树或者神经网络MLP。