boosting方法
转载声明
原文作者:Datawhale学习社区
原文链接:Datawhale学习社区
著作权归作者所有,任何形式的转载都请联系作者。
1、先行概念
- 弱学习:识别错误率小于1/2(即准确率仅比随机猜测略高的学习算法)
- 强学习:识别准确率很高并能在多项式时间内完成的学习算法
2、boosting原理
-
boosting就是一族可将弱学习器提升为强学习器的算法,其运行机制为:
- 从初始训练集训练出一个基学习器
- 根据上一轮预测结果调整训练集样本概率分布
- 基于调整后的训练集训练一个新的基学习器
- 重复进行,直到基学习器数量达到开始设置的值T
- 将T个基学习器结合起来
-
对于boosting族方法,有几个问题需要解决,不同的boosting有不同的解决方法:
- 如何计算学习误差率e?
- 如何得到弱学习器权重系数α?
- 如何更新样本权重D?
- 如何将各个基分类器组合起来?
3、Bagging,Boosting二者之间的区别
| bagging | boosting | |
|---|---|---|
| 样本选择 | 训练集是在原始集中有放回选取的,从原始集中选出的各轮训练集之间是独立的。 | 每一轮的训练集不变,只是训练集中每个样例在分类器中的权重发生变化。而权值是根据上一轮的分类结果进行调整。 |
| 样例权重 | 均匀取样,每个样例的权重相等 | 根据错误率不断调整样例的权值,错误率越大则权重越大。 |
| 预测函数 | 所有预测函数的权重相等。 | 每个弱分类器都有相应的权重,对于分类误差小的分类器会有更大的权重。 |
| 计算顺序 | 各个预测函数可以并行生成 | 各个预测函数只能顺序生成,因为后一个模型参数需要前一轮模型的结果。 |
- bagging是减少方差(variance),而boosting是减少偏差(bias)
-
当用bagging法时,每个样本集都有相似分布(方差、偏差相近)。对最终的训练结果,\(Var(\frac{\sum X_i}{n})=\frac{VarX_i}{n},bias=\frac{\sum[X_i-E(X_i)]}{n}=0\)
偏差没有变化,但是方差被压缩了 -
当用boosting方法时,样本集的概率分布随着前一轮的错误率调整(不断拟合残差),这个过程中,方差、偏差都在缩小
-
4、Adaboost算法的基本思路
假设给定一个二分类的训练数据集:$$T={(x_1,y_1),(x_2,y_2),\cdots,(x_N,y_N) }$$其中每个样本点由特征与类别组成。
Adaboost算法如下:
-
初始化训练数据的分布:$$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$$假设训练数据的权值分布是均匀分布,是为了使得第一次没有先验信息的条件下每个样本在基本分类器的学习中作用一样。
-
对于m=1,2,...,M
- 使用具有权值分布\(D_m\)的训练数据集进行学习,得到基本分类器:
\[G_{m}(x): \mathcal{X} \rightarrow\{-1,+1\} \]- 计算\(G_m(x)\)在训练集上的分类误差率
\[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) \]I为指示函数,括号里条件满足为1,不满足为0,错误率可分解为权重和I的乘积和
- 计算\(G_m(x)\)的权重系数:
\[\alpha_{m}=\frac{1}{2} \log \frac{1-e_{m}}{e_{m}} \]这里可以看出对应的分类错误率\(e_m\)越大,对应的弱分类器权重\(\alpha _m\)越小,即正确率越高的基学习器在最终学习器所占比重越高,当\(e_m>\frac12\)时,\(\alpha _m<0\),学习器已失去意义
- 更新训练数据集的权重分布
\[\begin{array}{l} 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\\\\ Z_{m}=\sum_{i=1}^{N} w_{m i}exp(-\alpha_{m} y_{i} G_{m}(x_{i}))\\\\ \hspace{0.6cm}=\sum_{i=1}^{N} w_{m i}e^{-\alpha_{m} y_{i} G_{m}(x_{i})} \end{array} \]这里的\(Z_m\)是规范化因子,使得\(D_{m+1}\)成为概率分布,因为是二元分布,y从\(w_{m+1}\)可以看出,当预测错误时,\(y_i*G_m(x)<0\),导致样本权重在第m+1个弱分类器中增大
\[w_{m+1, i}= \left\{\begin{array}{l} \frac{w_{m i}}{Z_{m}}e^{-\alpha_m}\hspace{2cm}G_m(x_i)= y_i\\\\ \frac{w_{m i}}{Z_{m}}e^{\alpha_m}\hspace{2.2cm}G_m(x_i)\neq y_i \end{array}\right. \]
从上式可以看到:被基本分类器\(Gm(x)\)错误分类的样本的权重扩大,被正确分类的样本权重减少,二者相比相差\(e^{2αm}=\frac{1−em}{em}\)倍。
3. 构建基本分类器的线性组合,得到最终的分类器
sign(x):符号函数,当x>0,sign(x)=1;当x=0,sign(x)=0;当x<0,sign(x)=-1;
5、例题训练
下面,我们使用一组简单的数据来手动计算Adaboost算法的过程:(例子来源:http://www.csie.edu.tw)
训练数据如下表,假设基本分类器的形式是一个分割\(x<v\)或\(x>v\)表示,阈值v由该基本分类器在训练数据集上分类错误率\(e_m\)最低确定。
解:
初始化样本权值分布
对m=1:
- 在权值分布\(D_1\)的训练数据集上,遍历每个结点并计算分类误差率\(e_m\),阈值取v=2.5时分类误差率最低,那么基本分类器为:
- \(G_1(x)\)在训练数据集上的误差率为\(e_{1}=P\left(G_{1}\left(x_{i}\right) \neq y_{i}\right)=0.3\)。
- 计算\(G_1(x)\)的系数:\(\alpha_{1}=\frac{1}{2} \log \frac{1-e_{1}}{e_{1}}=0.4236\)
- 更新训练数据的权值分布:
对于m=2:
- 在权值分布\(D_2\)的训练数据集上,遍历每个结点并计算分类误差率\(e_m\),阈值取v=8.5时分类误差率最低,那么基本分类器为:
- \(G_2(x)\)在训练数据集上的误差率为\(e_2 = 0.2143\)
- 计算\(G_2(x)\)的系数:\(\alpha_2 = 0.6496\)
- 更新训练数据的权值分布:
对m=3:
- 在权值分布\(D_3\)的训练数据集上,遍历每个结点并计算分类误差率\(e_m\),阈值取v=5.5时分类误差率最低,那么基本分类器为:
- \(G_3(x)\)在训练数据集上的误差率为\(e_3 = 0.1820\)
- 计算\(G_3(x)\)的系数:\(\alpha_3 = 0.7514\)
- 更新训练数据的权值分布:
于是得到:$$f_{3}(x)=0.4236 G_{1}(x)+0.6496 G_{2}(x)+0.7514 G_{3}(x)$$,分类器\(\operatorname{sign}[f_{3}(x)]\)在训练数据集上的误分类点的个数为0。
于是得到最终分类器为:$$G(x)=\operatorname{sign}\left[f_{3}(x)\right]=\operatorname{sign}\left[0.4236 G_{1}(x)+0.6496 G_{2}(x)+0.7514 G_{3}(x)\right]$$
5、sklearn模型
# 引入数据科学相关工具包:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
plt.style.use("ggplot")
%matplotlib inline
import seaborn as sns
# 加载训练数据:
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("Class labels",np.unique(wine["Class label"]))
wine.head()

Class label:分类标签
Alcohol:酒精
Malic acid:苹果酸
Ash:灰
Alcalinity of ash:灰的碱度
Magnesium:镁
Total phenols:总酚
Flavanoids:黄酮类化合物
Nonflavanoid phenols:非黄烷类酚类
Proanthocyanins:原花青素
Color intensity:色彩强度
Hue:色调
OD280/OD315 of diluted wines:稀释酒OD280 OD350
Proline:脯氨酸``
# 数据预处理
# 仅仅考虑2,3类葡萄酒,去除1类
wine = wine[wine['Class label'] != 1]
y = wine['Class label'].values
X = wine[['Alcohol','OD280/OD315 of diluted wines']].values
# 将分类标签变成二进制编码:
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
y = le.fit_transform(y)
# 按8:2分割训练集和测试集
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=1,stratify=y) # stratify参数代表了按照y的类别等比例抽样
# 使用单一决策树建模
from sklearn.tree import DecisionTreeClassifier
tree = DecisionTreeClassifier(criterion='entropy',random_state=1,max_depth=1)
from sklearn.metrics import accuracy_score
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))
Decision tree train/test accuracies 0.916/0.875
# 使用sklearn实现Adaboost(基分类器为决策树)
'''
AdaBoostClassifier相关参数:
base_estimator:基本分类器,默认为DecisionTreeClassifier(max_depth=1)
n_estimators:终止迭代的次数
learning_rate:学习率
algorithm:训练的相关算法,{'SAMME','SAMME.R'},默认='SAMME.R'
random_state:随机种子
'''
from sklearn.ensemble import AdaBoostClassifier
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))
Adaboost train/test accuracies 1.000/0.917
结果分析:单层决策树似乎对训练数据欠拟合,而Adaboost模型正确地预测了训练数据的所有分类标签,而且与单层决策树相比,Adaboost的测试性能也略有提高。然而,为什么模型在训练集和测试集的性能相差这么大呢?我们使用图像来简单说明下这个道理!
# 画出单层决策树与Adaboost的决策边界:
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()

从上面的决策边界图可以看到:Adaboost模型的决策边界比单层决策树的决策边界要复杂的多。也就是说,Adaboost试图用增加模型复杂度而降低偏差的方式去减少总误差,但是过程中引入了方差,可能出现国拟合,因此在训练集和测试集之间的性能存在较大的差距,这就简单地回答的刚刚问题。值的注意的是:与单个分类器相比,Adaboost等Boosting模型增加了计算的复杂度,在实践中需要仔细思考是否愿意为预测性能的相对改善而增加计算成本,而且Boosting方式无法做到现在流行的并行计算的方式进行训练,因为每一步迭代都要基于上一部的基本分类器。

浙公网安备 33010602011771号