集成学习Day9 Boosting (1)
1. Boosting
(1)强可学习与弱可学习
Valiant和Kearns提出了“强可学习”与“弱可学习”概念。在概率近似正确PAC框架下,
- 强可学习:识别准确率很高并且能在多项式时间内完成的学习算法;
- 弱可学习:识别错误率小于1/2(即准确率仅比随机猜测高的学习算法)。
并且强可学习与弱可学习是等价的(一个概念是强可学习的充要条件是这个概念是弱可学习的)。那么,在学习中,如果已经发现了弱可学习算法,那么能否将它提升到强可学习算法?
(2)Boosting原理
获得弱可学习算法比强可学习算法要容易的多。提升方法就是从弱学习算法出发,反复学习得到一系列弱分类器(基本分类器)然后通过一定形式去组合这些弱分类器构成一个强分类器。大多数Boosting方法都是通过改变训练数据集的概率分布(训练数据不同样本的权值),针对不同概率分布的数据调用弱分类算法学习一系统的弱分类器。上一节提到的Bagging方法通过Bootstrap的方式对全样本数据集进行抽样得到抽样子集,对不同子集使用同一模型进行拟合,然后投票得出最终预测结果。不同于Bagging,Boosting方法使用同一组数据集进行反复学习得到一系列简单模型,然后组合这些模型构成一个具有更强预测能力的机器学习模型。
对于Boosting方法来说,需要明确两个问题:第一个,每一轮学习应该如何改变数据的概率分布?第二个,如何组合各个弱分类器?常用的Boosting方法有Adaptive Boosting 和 Gradient Boosting,下面将介绍Adaboost算法。
2 Adaboost
(1)Adaboost原理
Adaboost提高那些被前一轮分类器错误分类的样本的权重,而降低那些被正确分类的样本的权重,这样一来,那些在上一轮分类器中没有得到正确分类的样本,由于其权重的增大而在后一轮的训练中“备受关注”,从而解决改变数据概率分布的问题;Adaboost组合各个弱分类器是通过采取加权多数表决的方式,具体来说,加大分类错误率低的弱分类器的权重,因为这些分类器能更好地完成分类任务,而减小分类错误率较大的弱分类器的权重,使其在表决中起较小的作用。
假设给定一个二分类的训练数据集:
T
=
{
(
x
1
,
y
1
)
,
(
x
2
,
y
2
)
,
⋯
,
(
x
N
,
y
N
)
}
T=\left\{\left(x_{1}, y_{1}\right),\left(x_{2}, y_{2}\right), \cdots,\left(x_{N}, y_{N}\right)\right\}
T={(x1,y1),(x2,y2),⋯,(xN,yN)},特征
x
i
∈
X
⊆
R
n
x_{i} \in \mathcal{X} \subseteq \mathbf{R}^{n}
xi∈X⊆Rn,类别
y
i
∈
Y
=
{
−
1
,
+
1
}
y_{i} \in \mathcal{Y}=\{-1,+1\}
yi∈Y={−1,+1},
X
\mathcal{X}
X是特征空间,
Y
\mathcal{Y}
Y是类别集合,输出最终分类器
G
(
x
)
G(x)
G(x)。Adaboost算法如下:
(1) 初始化训练数据的分布:
D
1
=
(
w
11
,
⋯
,
w
1
i
,
⋯
,
w
1
N
)
,
w
1
i
=
1
N
,
i
=
1
,
2
,
⋯
,
N
D_{1}=\left(w_{11}, \cdots, w_{1 i}, \cdots, w_{1 N}\right), \quad w_{1 i}=\frac{1}{N}, \quad i=1,2, \cdots, N
D1=(w11,⋯,w1i,⋯,w1N),w1i=N1,i=1,2,⋯,N
(2) 对于m=1,2,…,M :
a. 使用具有权值分布
D
m
D_m
Dm的训练数据集进行学习,得到基本分类器:
G
m
(
x
)
:
X
→
{
−
1
,
+
1
}
G_{m}(x): \mathcal{X} \rightarrow\{-1,+1\}
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}^{N} P\left(G_{m}\left(x_{i}\right) \neq y_{i}\right)=\sum_{i=1}^{N} w_{m i} I\left(G_{m}\left(x_{i}\right) \neq y_{i}\right)
em=∑i=1NP(Gm(xi)=yi)=∑i=1NwmiI(Gm(xi)=yi)
c. 计算
G
m
(
x
)
G_m(x)
Gm(x)的系数
α
m
=
1
2
log
1
−
e
m
e
m
\alpha_{m}=\frac{1}{2} \log \frac{1-e_{m}}{e_{m}}
αm=21logem1−em,这里的log是自然对数ln
d. 更新训练数据集的权重分布,这里的
Z
m
Z_m
Zm是规范化因子,使得
D
m
+
1
D_{m+1}
Dm+1称为概率分布,
Z
m
=
∑
i
=
1
N
w
m
i
exp
(
−
α
m
y
i
G
m
(
x
i
)
)
Z_{m}=\sum_{i=1}^{N} w_{m i} \exp \left(-\alpha_{m} y_{i} G_{m}\left(x_{i}\right)\right)
Zm=∑i=1Nwmiexp(−αmyiGm(xi))。
D
m
+
1
=
(
w
m
+
1
,
1
,
⋯
,
w
m
+
1
,
i
,
⋯
,
w
m
+
1
,
N
)
w
m
+
1
,
i
=
w
m
i
Z
m
exp
(
−
α
m
y
i
G
m
(
x
i
)
)
,
i
=
1
,
2
,
⋯
,
N
\begin{array}{c} D_{m+1}=\left(w_{m+1,1}, \cdots, w_{m+1, i}, \cdots, w_{m+1, N}\right) \\ w_{m+1, i}=\frac{w_{m i}}{Z_{m}} \exp \left(-\alpha_{m} y_{i} G_{m}\left(x_{i}\right)\right), \quad i=1,2, \cdots, N \end{array}
Dm+1=(wm+1,1,⋯,wm+1,i,⋯,wm+1,N)wm+1,i=Zmwmiexp(−αmyiGm(xi)),i=1,2,⋯,N
(3) 构建基本分类器的线性组合
f
(
x
)
=
∑
m
=
1
M
α
m
G
m
(
x
)
f(x)=\sum_{m=1}^{M} \alpha_{m} G_{m}(x)
f(x)=∑m=1MαmGm(x),得到最终的分类器
G
(
x
)
=
sign
(
f
(
x
)
)
=
sign
(
∑
m
=
1
M
α
m
G
m
(
x
)
)
\begin{aligned} G(x) &=\operatorname{sign}(f(x)) \\ &=\operatorname{sign}\left(\sum_{m=1}^{M} \alpha_{m} G_{m}(x)\right) \end{aligned}
G(x)=sign(f(x))=sign(m=1∑MαmGm(x))
对于步骤(1),假设训练数据的权值分布是均匀分布,是为了使得第一次没有先验信息的条件下每个样本在基本分类器的学习中作用一样。
对于步骤(2),每一次迭代产生的基本分类器
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
\begin{aligned}e_{m} &=\sum_{i=1}^{N} P\left(G_{m}\left(x_{i}\right) \neq y_{i}\right) =\sum_{G_{m}\left(x_{i}\right) \neq y_{i}} w_{m i}\end{aligned}
em=i=1∑NP(Gm(xi)=yi)=Gm(xi)=yi∑wmi代表了在
G
m
(
x
)
G_m(x)
Gm(x)中分类错误的样本权重和,这点直接说明了权重分布
D
m
D_m
Dm与
G
m
(
x
)
G_m(x)
Gm(x)的分类错误率
e
m
e_m
em有直接关系。同时,在步骤(2)中,计算基本分类器
G
m
(
x
)
G_m(x)
Gm(x)的系数
α
m
\alpha_m
αm,
α
m
=
1
2
log
1
−
e
m
e
m
\alpha_{m}=\frac{1}{2} \log \frac{1-e_{m}}{e_{m}}
αm=21logem1−em,它表示了
G
m
(
x
)
G_m(x)
Gm(x)在最终分类器的重要性程度,
α
m
\alpha_m
αm的取值由基本分类器
G
m
(
x
)
G_m(x)
Gm(x)的分类错误率有直接关系,当
e
m
⩽
1
2
e_{m} \leqslant \frac{1}{2}
em⩽21时,
α
m
⩾
0
\alpha_{m} \geqslant 0
αm⩾0,并且
α
m
\alpha_m
αm随着
e
m
e_m
em的减少而增大,因此分类错误率越小的基本分类器在最终分类器的作用越大。最重要的,对于步骤(2)中的样本权重的更新:
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}=\left\{\begin{array}{ll} \frac{w_{m i}}{Z_{m}} \mathrm{e}^{-\alpha_{m}}, & G_{m}\left(x_{i}\right)=y_{i} \\ \frac{w_{m i}}{Z_{m}} \mathrm{e}^{\alpha_{m}}, & G_{m}\left(x_{i}\right) \neq y_{i} \end{array}\right.
wm+1,i={Zmwmie−αm,Zmwmieαm,Gm(xi)=yiGm(xi)=yi
因此,从上式可以看到:被基本分类器
G
m
(
x
)
G_m(x)
Gm(x)错误分类的样本的权重扩大,被正确分类的样本权重减少,二者相比相差
e
2
α
m
=
1
−
e
m
e
m
\mathrm{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)的重要性,值得注意的是:所有的
α
m
\alpha_m
αm之和不为1。
f
(
x
)
f(x)
f(x)的符号决定了样本x属于哪一类。
(2)sklearn代码
本次案例我们使用一份UCI的机器学习库里的开源数据集:葡萄酒数据集,该数据集可以在 ( https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data )上获得。该数据集包含了178个样本和13个特征,从不同的角度对不同的化学特性进行描述,任务是根据这些数据预测红酒属于哪一个类别。
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
from sklearn.ensemble import AdaBoostClassifier
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
plt.style.use("ggplot")
import seaborn as sns
# load the dataset
wine = pd.read_csv("https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data",header=None)
wine.columns = ['Class label', 'Alcohol', 'Malic acid', 'Ash', 'Alcalinity of ash','Magnesium', 'Total phenols','Flavanoids', 'Nonflavanoid phenols',
'Proanthocyanins','Color intensity', 'Hue','OD280/OD315 of diluted wines','Proline']
# print the category of the datasets
print("Class labels", np.unique(wine["Class label"]))
print(wine.head())
# delete the labeled 1 data
wine = wine[wine['Class label'] != 1]
y = wine['Class label'].values
X = wine[['Alcohol','OD280/OD315 of diluted wines']].values
# change labels into the binary coding
le = LabelEncoder()
y = le.fit_transform(y)
# split dataset according to 8(training):2(testing)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1, stratify=y) # the parameter stratify represents equal sampling according to the category of y
# single DecisionTree Model
tree = DecisionTreeClassifier(criterion='entropy', random_state=1, max_depth=1)
tree = tree.fit(X_train, y_train)
y_train_pred = tree.predict(X_train)
y_test_pred = tree.predict(X_test)
tree_train = accuracy_score(y_train, y_train_pred)
tree_test = accuracy_score(y_test, y_test_pred)
print('Decision tree train/test accuracies %.3f/%.3f' % (tree_train,tree_test))
# AdaBoost
ada = AdaBoostClassifier(base_estimator=tree, n_estimators=500, learning_rate=0.1, random_state=1)
ada = ada.fit(X_train, y_train)
y_train_pred = ada.predict(X_train)
y_test_pred = ada.predict(X_test)
ada_train = accuracy_score(y_train, y_train_pred)
ada_test = accuracy_score(y_test, y_test_pred)
print('Adaboost train/test accuracies %.3f/%.3f' % (ada_train,ada_test))
# Draw the decision boundary
x_min = X_train[:, 0].min() - 1
x_max = X_train[:, 0].max() + 1
y_min = X_train[:, 1].min() - 1
y_max = X_train[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),np.arange(y_min, y_max, 0.1))
f, axarr = plt.subplots(nrows=1, ncols=2,sharex='col',sharey='row',figsize=(12, 6))
for idx, clf, tt in zip([0, 1],[tree, ada],['Decision tree', 'Adaboost']):
clf.fit(X_train, y_train)
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
axarr[idx].contourf(xx, yy, Z, alpha=0.3)
axarr[idx].scatter(X_train[y_train==0, 0],X_train[y_train==0, 1],c='blue', marker='^')
axarr[idx].scatter(X_train[y_train==1, 0],X_train[y_train==1, 1],c='red', marker='o')
axarr[idx].set_title(tt)
axarr[0].set_ylabel('Alcohol', fontsize=12)
plt.tight_layout()
plt.text(0, -0.2,s='OD280/OD315 of diluted wines',ha='center',va='center',fontsize=12,transform=axarr[1].transAxes)
plt.show()
结果:
绘制决策树的决策边界: