集成学习有两大类:bagging和boosting。随机森林是bagging的一个例子,而Adaboost是boosting的典型算法。
bagging算法是由多个学习器组成的,但是学习器之间是 并 行 \color{#FF0000}{并行} 并行的,意思就是学习器之间互补干扰,各自训练各自的,各自测试各自的数据,然后通过整合每个学习器返回的数据最终得到结果。
整合的方式有很多种:
boosting也是有多个学习器组成,但是学习器之间是有 串 联 \color{#FF0000}{串联} 串联的。
举个例子,从一批数据中抽样70%,第一个学习器训练这70%,训练完之后测试这批数据,标记出错的样本,第二个学习器再重点训练这些第一个学习器出错的样本,训练完之后测试这批数据,再标记出错的样本,第三个学习器再重点训练第一个学习器和第二个学习器都出错的样本。最后利用集成学习整合这些数据,第一个学习器和第二个学习器输出一致时那就输出他们的结果,不一致时就输出第三个学习器的结果。这样误差率就大大下降了。
那么就刚刚的例子中,我们能够看到算法实现的时候需要 标 记 样 本 \color{#FF0000}{标记样本} 标记样本,并且最后需要 整 合 \color{#FF0000}{整合} 整合每个学习器的输出。
那接下来我们来看一下Adaboost是如何标记样本和整合输出的吧。
Adaboost具体实现如下图:
其中, ϵ t \epsilon_t ϵt是第 t t t个学习器的误差率, α t \alpha_t αt是第 t t t个学习器的更新权重系数 ( 整 合 输 出 ) \color{#FF0000}{(整合输出)} (整合输出), D t ( i ) D_t(i) Dt(i)是第 t t t个学习器对第 i i i个样本的权重 ( 标 记 样 本 ) \color{#FF0000}{(标记样本)} (标记样本)。
Adaboost算法有很好地数学特性,就是说它的误差率的收敛,更新权重的系数都是可以通过数学推导出来的,那我们就来看一下是如何推导出来的吧,在推导之前先明确一下几个定义:
误差率当然越小越好,但是这个误差率和什么有关呢,我们不知道啊,但是仔细想想boost的原理,这个误差率会不会和 学 习 器 输 出 结 果 的 整 合 方 式 \color{#FF0000}{学习器输出结果的整合方式} 学习器输出结果的整合方式与 选 取 的 训 练 的 样 本 \color{#FF0000}{选取的训练的样本} 选取的训练的样本有关呢?在Adaboost中难道和参数 α t \alpha_t αt和 D t ( i ) D_t(i) Dt(i)有关?算了,想那么多干嘛,先看看误差率长什么样吧!
误 差 率 ϵ = H ( x i ) 不 等 于 y i 的 个 数 样 本 总 个 数 m = 1 m ∑ i = 1 m [ ​ [ H ( x i ) ̸ = y i ] ​ ] \begin{aligned} 误差率\epsilon&=\frac{H(x_i)不等于y_i的个数}{样本总个数m}\\ &=\frac{1}{m}\sum_{i=1}^m[\![H(x_i) \not= y_i]\!] \end{aligned} 误差率ϵ=样本总个数mH(xi)不等于yi的个数=m1i=1∑m[[H(xi)̸=yi]]
其中, a a a成立, [ ​ [ a ] ​ ] = 1 [\![a]\!]=1 [[a]]=1, a a a不成立, [ ​ [ a ] ​ ] = 0 [\![a]\!]=0 [[a]]=0。
这个误差率表达式好像不怎么好处理,能不能转化一下。
我们看一下下面的式子
[ ​ [ H ( x i ) ̸ = y i ] ​ ] = 1 ⇒ y i f ( x i ) < 0 ⇒ e − y i f ( x i ) > 1 [ ​ [ H ( x i ) ̸ = y i ] ​ ] = 0 ⇒ y i f ( x i ) > 0 ⇒ e − y i f ( x i ) > 0 [\![H(x_i) \not= y_i]\!]=1\Rightarrow y_if(x_i)<0\Rightarrow e^{-y_if(x_i)}>1\\ [\![H(x_i) \not= y_i]\!]=0\Rightarrow y_if(x_i)>0\Rightarrow e^{-y_if(x_i)}>0 [[H(xi)̸=yi]]=1⇒yif(xi)<0⇒e−yif(xi)>1[[H(xi)̸=yi]]=0⇒yif(xi)>0⇒e−yif(xi)>0
好像有点意思,那我们整理一下不就可以得到: [ ​ [ H ( x i ) ̸ = y i ] ​ ] ≤ e − y i f ( x i ) [\![H(x_i) \not= y_i]\!]\leq e^{-y_if(x_i)} [[H(xi)̸=yi]]≤e−yif(xi)。那么 ϵ ≤ 1 m ∑ i = 1 m e − y i f ( x i ) \epsilon\leq \frac{1}{m}\sum_{i=1}^m e^{-y_if(x_i)} ϵ≤m1∑i=1me−yif(xi),虽然误差率整理的好像有点样子了,但是接下来也不知道怎么处理,我们暂时放一下。刚刚猜测误差率和 D t ( i ) D_t(i) Dt(i)有关来着,我们先看看 D t ( i ) D_t(i) Dt(i)的表达吧!
D t D_t Dt是样本的权重,我们一开始初始化 D t ( i ) D_t(i) Dt(i)为 1 m \frac{1}{m} m1,接下来通过不同学习器的学习训练,每个样本的权重都会变化,具体怎么变化呢?
综上,样本的权重为 D t ( i ) e − y i f ( x i ) D_t(i)e^{-y_if(x_i)} Dt(i)e−yif(xi),但是考虑每个样本的权重和应该为1,需要将权重标准化,最终权重: D t + 1 ( i ) = D t ( i ) e − y i α t h t ( x i ) Z t D_{t+1}(i)=D_t(i)\frac{e^{-y_i\alpha_th_t(x_i)}}{Z_t} Dt+1(i)=Dt(i)Zte−yiαtht(xi),其中, Z t = ∑ i D t ( i ) e − y i α t h t ( x i ) Z_t=\sum_i D_t(i)e^{-y_i\alpha_th_t(x_i)} Zt=∑iDt(i)e−yiαtht(xi)。
最后求解,
D T + 1 ( i ) = D 1 ( i ) ∏ t = 1 T e − y i α t h t ( x i ) Z t = 1 m e − y i f ( x i ) ∏ t = 1 T Z t \begin{aligned} D_{T+1}(i)&=D_1(i)\prod_{t=1}^T\frac{e^{-y_i\alpha_th_t(x_i)}}{Z_t}\\ &=\frac{1}{m}\frac{e^{-y_if(x_i)}}{\prod_{t=1}^TZ_t} \end{aligned} DT+1(i)=D1(i)t=1∏TZte−yiαtht(xi)=m1∏t=1TZte−yif(xi)
不知不觉出现了 e − y i f ( x i ) e^{-y_if(x_i)} e−yif(xi),且 e − y i f ( x i ) = m D T + 1 ( i ) ∏ t = 1 T Z t e^{-y_if(x_i)}=mD_{T+1}(i)\prod_{t=1}^TZ_t e−yif(xi)=mDT+1(i)∏t=1TZt,那么代入上面误差率的公式中,
ϵ ≤ ∑ i = 1 m D T + 1 ( i ) ∏ t = 1 T Z t = ∏ t = 1 T Z t \begin{aligned} \epsilon&\leq\sum_{i=1}^mD_{T+1}(i)\prod_{t=1}^TZ_t\\ &=\prod_{t=1}^TZ_t \end{aligned} ϵ≤i=1∑mDT+1(i)t=1∏TZt=t=1∏TZt
误差率出现了上界,仔细观察这个上界,里面的 Z t Z_t Zt好像和参数 D t ( i ) , α t D_t(i),\alpha_t Dt(i),αt有关耶,是不是和我们一开始的猜想一样。我们的目标是最小化误差率,可最小化 ∏ \prod ∏有点困难,我们退而求其次,即求解 min Z t \min Z_t minZt。
那么我们先处理一下 Z t Z_t Zt,观察 y i h t ( i ) y_ih_t(i) yiht(i)这项的值不是1就是-1,那么就好办了。
Z t = ∑ i D t ( i ) e − y i α t h t ( x i ) = ∑ y i ≠ h t ( x i ) D t ( i ) e α t + ∑ y i = h t ( x i ) D t ( i ) e − α t = e α t ϵ t + e − α t ( 1 − ϵ t ) \begin{aligned} Z_t&=\sum_i D_t(i)e^{-y_i\alpha_th_t(x_i)}\\ &=\sum_{y_i\neq h_t(x_i)}D_t(i)e^{\alpha_t}+\sum_{y_i=h_t(x_i)}D_t(i)e^{-\alpha_t}\\ &=e^{\alpha_t}\epsilon_t+e^{-\alpha_t}\left(1-\epsilon_t\right) \end{aligned} Zt=i∑Dt(i)e−yiαtht(xi)=yi̸=ht(xi)∑Dt(i)eαt+yi=ht(xi)∑Dt(i)e−αt=eαtϵt+e−αt(1−ϵt)
那么 Z t Z_t Zt对 α t \alpha_t αt求导,领导数等于0,得 α t = 1 2 ln 1 − ϵ t ϵ t \alpha_t=\frac{1}{2}\ln\frac{1-\epsilon_t}{\epsilon_t} αt=21lnϵt1−ϵt。
我们这边看一下,权重更新之后对当前学习器的误差率有什么影响,那我们就要计算 ϵ t ∗ = ∑ h t ( x i ) ≠ y i D t + 1 ( i ) \epsilon_t^*=\sum_{h_t(x_i)\neq y_i}D_{t+1}(i) ϵt∗=∑ht(xi)̸=yiDt+1(i),
ϵ t ∗ = ∑ h t ( x i ) ≠ y i D t + 1 ( i ) = ∑ h t ( x i ) ≠ y i D t ( i ) e − y i α t h t ( x i ) Z t = ∑ h t ( x i ) ≠ y i D t ( i ) e α t ∑ h t ( x i ) ≠ y i D t ( i ) e α t + ∑ h t ( x i ) = y i D t ( i ) e − α t = ϵ t e α t ϵ t e α t + ( 1 − ϵ t ) e − α t , α t = 1 2 ln 1 − ϵ t ϵ t = 0.5 \begin{aligned} \epsilon_t^*&=\sum_{h_t(x_i)\neq y_i}D_{t+1}(i)\\ &=\frac{\sum_{h_t(x_i)\neq y_i}D_t(i)e^{-y_i\alpha_th_t(x_i)}}{Z_t}\\ &=\frac{\sum_{h_t(x_i)\neq y_i}D_t(i)e^{\alpha_t}}{\sum_{h_t(x_i)\neq y_i}D_t(i)e^{\alpha_t}+\sum_{h_t(x_i)=y_i}D_t(i)e^{-\alpha_t}}\\ &=\frac{\epsilon_te^{\alpha_t}}{\epsilon_te^{\alpha_t}+(1-\epsilon_t)e^{-\alpha_t}},\alpha_t=\frac{1}{2}\ln\frac{1-\epsilon_t}{\epsilon_t}\\ &=0.5 \end{aligned} ϵt∗=ht(xi)̸=yi∑Dt+1(i)=Zt∑ht(xi)̸=yiDt(i)e−yiαtht(xi)=∑ht(xi)̸=yiDt(i)eαt+∑ht(xi)=yiDt(i)e−αt∑ht(xi)̸=yiDt(i)eαt=ϵteαt+(1−ϵt)e−αtϵteαt,αt=21lnϵt1−ϵt=0.5
结果是0.5,对于误差率来说应该是最坏的结果了(大于0.5的只要输出翻转一下就小于0.5了),那意思就是当前学习器训练完, 权 重 会 调 整 到 使 当 前 学 习 器 效 果 最 差 的 状 态 \color{#FF0000}{权重会调整到使当前学习器效果最差的状态} 权重会调整到使当前学习器效果最差的状态,然后再给下一个学习器训练,这是Adaboost一个重要的思想!
到这里,Adaboost算法里面公式的推导结束了,那接下来我们使用刚刚推导的结果看一下最终的误差率吧。
将 α t = 1 2 ln 1 − ϵ t ϵ t \alpha_t=\frac{1}{2}\ln\frac{1-\epsilon_t}{\epsilon_t} αt=21lnϵt1−ϵt代入 Z t Z_t Zt得
Z t = ∑ i D t ( i ) e − 1 2 y i h t ( x i ) ln 1 − ϵ t ϵ t = ∑ i D t ( i ) [ 1 − ϵ t ϵ t Pr ( y i ≠ h t ( i ) ) + ϵ t 1 − ϵ t Pr ( y i = h t ( i ) ) ] = 2 ∑ i D t ( i ) ϵ t ( 1 − ϵ t ) = 2 ϵ t ( 1 − ϵ t ) \begin{aligned} Z_t&=\sum_iD_t(i)e^{-\frac{1}{2}y_ih_t(x_i)\ln\frac{1-\epsilon_t}{\epsilon_t}}\\ &=\sum_iD_t(i)\left[\sqrt{\frac{1-\epsilon_t}{\epsilon_t}}\Pr(y_i\neq h_t(i))+\sqrt{\frac{\epsilon_t}{1-\epsilon_t}}\Pr(y_i= h_t(i))\right]\\ &=2\sum_iD_t(i)\sqrt{\epsilon_t(1-\epsilon_t)}\\ &=2\sqrt{\epsilon_t(1-\epsilon_t)} \end{aligned} Zt=i∑Dt(i)e−21yiht(xi)lnϵt1−ϵt=i∑Dt(i)[ϵt1−ϵtPr(yi̸=ht(i))+1−ϵtϵtPr(yi=ht(i))]=2i∑Dt(i)ϵt(1−ϵt)=2ϵt(1−ϵt)
令 ϵ t = 1 − r t 2 \epsilon_t=\frac{1-r_t}{2} ϵt=21−rt,在上面的算法中,我们可以看到 ϵ t > 0.5 \epsilon_t>0.5 ϵt>0.5,所以这边的 r t ∈ ( 0 , 1 ) r_t\in(0,1) rt∈(0,1)。
上式 2 ϵ t ( 1 − ϵ t ) = 1 − r t 2 , r t ∈ ( 0 , 1 ) 2\sqrt{\epsilon_t(1-\epsilon_t)}=\sqrt{1-r_t^2},r_t\in(0,1) 2ϵt(1−ϵt)=1−rt2,rt∈(0,1)
所以最终的误差率 ϵ ≤ ∏ t Z t = ∏ t 1 − r t 2 , r t ∈ ( 0 , 1 ) \epsilon\leq\prod_tZ_t=\prod_t\sqrt{1-r_t^2},r_t\in(0,1) ϵ≤∏tZt=∏t1−rt2,rt∈(0,1),可以看出误差率上界是 T T T个小于1的数相乘,明显是趋于0的。
from sklearn.datasets import make_gaussian_quantiles
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier
import numpy as np
import matplotlib.pyplot as plt
X1, y1 = make_gaussian_quantiles(cov=2., n_samples=200, n_features=2, n_classes=2, random_state=1)
X2, y2 = make_gaussian_quantiles((3, 3), cov=1.5, n_samples=300, n_features=2, n_classes=2, random_state=1)
X = np.concatenate((X1, X2))
y = np.concatenate((y1, -y2+1))
plt.scatter(X[:,0], X[:,1], marker='o', c=y)
bdt = AdaBoostClassifier(DecisionTreeClassifier(
max_depth=2
, min_samples_split=20
, min_samples_leaf=5
)
, algorithm='SAMME'
, n_estimators=200
, learning_rate=1
)
bdt.fit(X, y)
bdt.score(X, y)
初音程序结果参考
初音图片下载地址miku.zip
import pandas as pd
import numpy as np
from PIL import Image
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier
miku = pd.read_csv(r'miku.csv')
miku = np.array(miku.values)
# print(miku.shape)
# miku_grayscale = miku[:, 2]
# miku_grayscale = miku_grayscale.reshape((500, 500))
# miku_grayscale = miku_grayscale.transpose()
# image = Image.fromarray(miku_grayscale*255)
# image.show()
miku_data = miku[:, 0:2]
miku_target = miku[:, 2]
# n_estimators参数为上文讲到的T,修改参数看效果。
clf = AdaBoostClassifier(DecisionTreeClassifier(max_depth=5), n_estimators=50)
clf.fit(miku_data, miku_target)
predict = clf.predict(miku_data)
predict = predict.reshape((500, 500))
predict = predict.transpose()
image = Image.fromarray(predict*255)
image.show()
https://blog.csdn.net/zhisuihen6347/article/details/100582880