集成学习 Adaboost (Adaptive boosting) 学习笔记

学习目标

掌握集成学习的基本原理以及adaboost的推导过程、实现方法

1.集成学习原理

1.1 基本原理

集成学习,就是将多个学习器集成在一起,共同完成某个学习任务,通过"集成"的方式获得一个更好的学习结果
集成学习首先通过训练”个体学习器"(又称之为"基学习器"或"弱学习器"),个体学习器一般是指比较成熟的分类器(如决策树、BP神经网络等),在个体学习器训练结束后,根据某种策略将其结合起来,组成集成学习器(又称之为"强学习器")

1.2 分类器的要求

根据经验,将好坏都有的物品混合在一起,最终的结果肯定是要比最坏的好一些,那如何能够得到更好的集成分类器呢?

在这里插入图片描述
从图(a)中可以看出, 单个分类器的准确率为66.7%,但是集成在一起(按照投票的方式),准确率达到了100%
从图(b)中可以看出, 单个分类器的准确率仍未66.7%,但集成后的准确率依然还是66.7%,并没有提升
从图©中可以看出, 每个集成分类器的准确率为33.3%,但似乎集成在一起后,准确率却降低到0%

这说明:想要集成的结果 比 单个分类器 的学习效果好 , 单个分类器之间要保证 "好而不同"1

但是从现实出发,如果各个分类器想要足够好,就必须牺牲一定的差异性;同样,想要做到不同,也需要牺牲一定的准确度

因此如何进行折中,选取好的个体分类器,是集成学习的核心

1.3 集成策略

个体学习器进行集成的方式大概分成两类:
1.个体学习器之间存在着强依赖关系,即个体学习器必须按照串行的序列顺序进行集成
2.个体学习器之间存在弱依赖关系,个体学习器可以按照并行的方式同时进行生成
第一种集成方式的代表为Boosting,第二种集成方式的代表为bagging和随机森林

2.Boosting 之 Adaboost

1.3 中提到Boosting 是一种串行化个体学习器的集成学习方法,它的具体做法是:
根据当前分类器的分类情况重新分布样本(更新样本权重),使得学习错误的样本的权重升高,学习正确的样本权重降低。下一个学习器继续在新的样本分布上进行学习(新的分类器将会更加关注被分错样本),循环往复,一直到分类器的错误率下降到一定值 或者 分类器的数目达到定值 为止
同时,对于学习情况不同的分类器也会分配权值,分类准确度高的分类器自然权值更高,分类不准确的权值自然低
总结而言,boosting 在集成过程中干了三件事:

1.训练个体分类器
2.计算样本权值(重新分布样本)
3.计算分类器权值

2.1损失函数

Adaboost 使用的损失函数为指数函数2

f ( x ) f(x) f(x)为实际标签, H ( x ) H(x) H(x)为分类器预测标签

其损失函数可以表示为:

L o s s Loss Loss= e − f ( x ) ∗ H ( x ) e^{-f(x)*H(x)} ef(x)H(x)

为什么可以使用指数函数作为损失函数呢?

∂ L o s s ∂ H ( x ) \frac{\partial Loss}{\partial H(x)} H(x)Loss= e − f ( x ) ∗ H ( x ) e^{-f(x)*H(x)} ef(x)H(x)* − f ( x ) -f(x) f(x)

f ( x ) f(x) f(x)=1时: ∂ L o s s ∂ H ( x ) \frac{\partial Loss}{\partial H(x)} H(x)Loss= e H ( x ) e^{H(x)} eH(x)* − 1 -1 1

f ( x ) f(x) f(x)=-1时: ∂ L o s s ∂ H ( x ) \frac{\partial Loss}{\partial H(x)} H(x)Loss= e H ( x ) e^{H(x)} eH(x)* 1 1 1

当损失函数最小时, − e H ( x ) -e^{H(x)} eH(x)* P ( f ( x ) = − 1 ∣ x ) P(f(x)=-1|x) P(f(x)=1x)+ e − H ( x ) ∗ P ( f ( x ) = 1 ∣ x ) e^{-H(x)}*P(f(x)=1|x) eH(x)P(f(x)=1x)=0

e − H ( x ) ∗ P ( f ( x ) = 1 ∣ x ) e^{-H(x)}*P(f(x)=1|x) eH(x)P(f(x)=1x)= e H ( x ) e^{H(x)} eH(x)* P ( f ( x ) = − 1 ∣ x ) P(f(x)=-1|x) P(f(x)=1x)

取对数:

− H ( x ) + l n P ( f ( x ) = 1 ∣ x ) -H(x)+lnP(f(x)=1|x) H(x)+lnP(f(x)=1x)= H ( x ) + l n P ( f ( x ) = − 1 ∣ x ) H(x)+lnP(f(x)=-1|x) H(x)+lnP(f(x)=1x)

H ( x ) = 1 2 ∗ l n P ( f ( x ) = 1 ∣ x ) P ( f ( x ) = − 1 ∣ x ) H(x)=\frac{1}{2}*ln\frac{P(f(x)=1|x)}{P(f(x)=-1|x)} H(x)=21lnP(f(x)=1x)P(f(x)=1x)

s i g n H ( x ) signH(x) signH(x)= s i g n ( 1 2 ∗ l n P ( f ( x ) = 1 ∣ x ) P ( f ( x ) = − 1 ∣ x ) ) sign(\frac{1}{2}*ln\frac{P(f(x)=1|x)}{P(f(x)=-1|x)}) sign(21lnP(f(x)=1x)P(f(x)=1x))

可以看出:

s i g n ( H ( x ) ) = 1 sign(H(x))=1 sign(H(x))=1 当且仅当 P ( f ( x ) = 1 ∣ x ) > P ( f ( x ) = − 1 ∣ x ) {P(f(x)=1|x)}>{P(f(x)=-1|x)} P(f(x)=1x)>P(f(x)=1x)

s i g n ( H ( x ) ) = − 1 sign(H(x))=-1 sign(H(x))=1 当且仅当 P ( f ( x ) = 1 ∣ x ) < P ( f ( x ) = − 1 ∣ x ) {P(f(x)=1|x)}<{P(f(x)=-1|x)} P(f(x)=1x)<P(f(x)=1x)

当损失函数最小时:
s i g n ( H ( x ) ) sign(H(x)) sign(H(x))= a r g m a x y ( P ( f ( x ) = y ∣ x ) ) argmax_y(P(f(x)=y|x)) argmaxy(P(f(x)=yx)) y ∈ ( − 1 , 1 ) y\in({-1,1}) y(1,1)

说明其达到了贝叶斯最优错误率,可以替代0-1损失函数求解损失,并且指数函数连续可微,是一个更优的选择

2.2 分类器权值的计算

H ( x ) H(x) H(x)为我们最终的分类结果, h ( x ) h(x) h(x)为单个分类器的分类结果, a a a为每个分类器的权值,则集成学习最终的结果为:

H ( x ) H(x) H(x)= ∑ x ∈ D a i h i ( x ) \sum_{x \in D} a_i h_i(x) xDaihi(x)

L ( H ∣ D ) L(H|D) L(HD)为在D分布下的损失函数,则:

L ( H ∣ D ) L(H|D) L(HD)= e − f ( x ) ∗ H ( x ) e^{-f(x)*H(x)} ef(x)H(x)= e − f ( x ) ∗ a i ∗ h i ( x ) e^{-f(x)*a_i*h_i(x)} ef(x)aihi(x)

∂ L ( H ∣ D ) ∂ a \frac{\partial L(H|D)}{\partial a} aL(HD)= e − f ( x ) ∗ a i ∗ h i ( x ) e^{-f(x)*a_i*h_i(x)} ef(x)aihi(x)* − f ( x ) ∗ h i ( x ) -f(x)*h_i(x) f(x)hi(x)

= ∑ − e − a i [ f ( x ) = h i ( x ) ] \sum -e^{-a_i}[f(x)=h_i(x)] eai[f(x)=hi(x)]+ ∑ e a i [ f ( x ) ≠ h i ( x ) ] \sum e^{a_i}[f(x)\not=h_i(x)] eai[f(x)=hi(x)]

设分类正确的个数为 k 1 k_1 k1,分类错误的个数为 k 2 k_2 k2,则:

= − e − a i -e^{-a_i} eai k 1 k_1 k1+ e a i k 2 e^{a_i}k_2 eaik2

当仅当 − e − a i -e^{-a_i} eai k 1 k_1 k1+ e a i k 2 e^{a_i}k_2 eaik2=0 时,损失函数达到最小

设错误率为 ϵ \epsilon ϵ,正确率为 1 − ϵ 1-\epsilon 1ϵ,则

− e − a i -e^{-a_i} eai ( 1 − ϵ ) (1-\epsilon) (1ϵ)+ e a i ϵ e^{a_i}\epsilon eaiϵ=0

e a i ϵ e^{a_i}\epsilon eaiϵ= e − a i e^{-a_i} eai ( 1 − ϵ ) (1-\epsilon) (1ϵ)

取对数

a i a_i ai+ l n ϵ ln\epsilon lnϵ= − a i -a_i ai+ l n ( 1 − ϵ ) ln(1-\epsilon) ln(1ϵ)
2 a i 2a_i 2ai= l n ( 1 − ϵ ) ϵ ln\frac{(1-\epsilon)}{\epsilon} lnϵ(1ϵ)
a i a_i ai= 1 2 l n ( 1 − ϵ ) ϵ \frac{1}{2}ln\frac{(1-\epsilon)}{\epsilon} 21lnϵ(1ϵ)

这样就得到了分类器权重的更新公式。

也就是说,我们可以根据每次分类器分类的错误率来计算该分类器的权重。错误率越高,权重越低
(注意需要就错误率进行判断,在错误率>0.5时,就退出集成学习器的训练过程,因为这时权重为负,再进行计算无意义)

2.4 样本权值的计算

在每次个体分类器分类过后,需要根据分类的情况更新样本的权值3

L ( H t − 1 + h t ∣ D ) L(H_{t-1}+h_t|D) L(Ht1+htD)= E x   D ( e − f ( x ) ∗ ( H t − 1 ( x ) + h t ( x ) ) ) E_{x~D}(e^{-f(x)*(H_t-1(x)+h_t (x))}) Ex D(ef(x)(Ht1(x)+ht(x)))

= E x   D ( e − f ( x ) ∗ H t − 1 ( x ) ∗ e − f ( x ) ∗ h t ( x ) ) E_{x~D}(e^{-f(x)*H_{t-1}(x)}*e^{-f(x)*h_t(x)}) Ex D(ef(x)Ht1(x)ef(x)ht(x))

根据指数函数的泰勒展开式可以得到:

e − f ( x ) ∗ h t ( x ) e^{-f(x)*h_t(x)} ef(x)ht(x)= 1 − f ( x ) ∗ h t ( x ) 1-f(x)*h_t(x) 1f(x)ht(x)+ f 2 ( x ) ∗ h t 2 ( x ) f^2(x)*h_t^2(x) f2(x)ht2(x)

= E x   D ( e − f ( x ) ∗ H t − 1 ( x ) ∗ ( 1 − f ( x ) ∗ h t ( x ) E_{x~D}(e^{-f(x)*H_{t-1}(x)}*(1-f(x)*h_t(x) Ex D(ef(x)Ht1(x)(1f(x)ht(x)+ ( f 2 ( x ) ∗ h t 2 ( x ) ) / 2 ) ) (f^2(x)*h_t^2(x))/2)) (f2(x)ht2(x))/2))

因为 f 2 ( x ) ∗ h t 2 ( x ) f^2(x)*h_t^2(x) f2(x)ht2(x)=1,所以原式可以写成:

= E x   D ( e − f ( x ) ∗ H t − 1 ( x ) + 1 − f ( x ) ∗ h t ( x ) + 1 / 2 ) E_{x~D}(e^{-f(x)*H_{t-1}(x)}+1-f(x)*h_t(x)+1/2) Ex D(ef(x)Ht1(x)+1f(x)ht(x)+1/2)

h t ( x ) = a r g m i n h h_t(x)=argmin_h ht(x)=argminh E x   D ( e − f ( x ) ∗ H t − 1 ( x ) ∗ ( 1 − f ( x ) ∗ h t ( x ) + 1 / 2 ) ) E_{x~D}(e^{-f(x)*H_{t-1}(x)}*(1-f(x)*h_t(x)+1/2)) Ex D(ef(x)Ht1(x)(1f(x)ht(x)+1/2))

= a r g m a x h argmax_h argmaxh E x   D ( e − f ( x ) ∗ H t − 1 ( x ) ∗ ( f ( x ) ∗ h t ( x ) ) ) E_{x~D}(e^{-f(x)*H_{t-1}(x)}*(f(x)*h_t(x))) Ex D(ef(x)Ht1(x)(f(x)ht(x)))

= a r g m a x h argmax_h argmaxh E x   D ( e − f ( x ) ∗ H t − 1 ( x ) ∗ ( f ( x ) ∗ h t ( x ) ) / E x   d [ e − f ( x ) ∗ H t − 1 ( x ) ] ) E_{x~D}(e^{-f(x)*H_{t-1}(x)}*(f(x)*h_t(x))/E_{x~d}[e^{-f(x)*H_{t-1}(x)}]) Ex D(ef(x)Ht1(x)(f(x)ht(x))/Ex d[ef(x)Ht1(x)])

= a r g m a x h argmax_h argmaxh E x   D ( e − f ( x ) ∗ H t − 1 ( x ) ∗ D ( x ) E x   d [ e − f ( x ) ∗ H t − 1 ( x ) ] ) E_{x~D}(\frac {e^{-f(x)*H_{t-1}(x)}*D(x)}{E_{x~d}[e^{-f(x)*H_{t-1}(x)}]}) Ex D(Ex d[ef(x)Ht1(x)]ef(x)Ht1(x)D(x))

D ( x ) = f ( x ) ∗ h t ( x ) D(x)=f(x)*h_t(x) D(x)=f(x)ht(x),则

D t ( x ) = e − f ( x ) ∗ H t − 1 ( x ) ∗ D ( x ) E x   d [ e − f ( x ) ∗ H t − 1 ( x ) ] D_t(x)=\frac {e^{-f(x)*H_{t-1}(x)}*D(x)}{E_{x~d}[e^{-f(x)*H_{t-1}(x)}]} Dt(x)=Ex d[ef(x)Ht1(x)]ef(x)Ht1(x)D(x)

D t + 1 ( x ) = e − f ( x ) ∗ H t ( x ) ∗ D ( x ) E x   d [ e − f ( x ) ∗ H t ( x ) ] D_{t+1}(x)=\frac {e^{-f(x)*H_{t}(x)}*D(x)}{E_{x~d}[e^{-f(x)*H_{t}(x)}]} Dt+1(x)=Ex d[ef(x)Ht(x)]ef(x)Ht(x)D(x)

= e − f ( x ) ∗ ( H t − 1 ( x ) + a t ( x ) ∗ h t ( x ) ) ∗ D ( x ) E x   d [ e − f ( x ) ∗ H t ( x ) ] \frac {e^{-f(x)*(H_{t-1}(x)+a_t(x)*h_t(x))}*D(x)}{E_{x~d}[e^{-f(x)*H_{t}(x)}]} Ex d[ef(x)Ht(x)]ef(x)(Ht1(x)+at(x)ht(x))D(x)

= e − f ( x ) ∗ ( H t − 1 ( x ) ) ∗ e f ( x ) ∗ − a t ( x ) ∗ h t ( x ) ∗ D ( x ) E x   d [ e − f ( x ) ∗ H t ( x ) ] \frac {e^{-f(x)*(H_{t-1}(x))}*e^{f(x)*-a_t(x)*h_t(x)}*D(x)}{E_{x~d}[e^{-f(x)*H_{t}(x)}]} Ex d[ef(x)Ht(x)]ef(x)(Ht1(x))ef(x)at(x)ht(x)D(x)

= D t ( x ) ∗ E x   d [ e − f ( x ) ∗ H t − 1 ( x ) ] ∗ e f ( x ) ∗ − a t ( x ) ∗ h t ( x ) E x   d [ e − f ( x ) ∗ H t ( x ) ] \frac {D_t(x)*E_{x~d}[e^{-f(x)*H_{t-1}(x)}]*e^{f(x)*-a_t(x)*h_t(x)}}{E_{x~d}[e^{-f(x)*H_{t}(x)}]} Ex d[ef(x)Ht(x)]Dt(x)Ex d[ef(x)Ht1(x)]ef(x)at(x)ht(x)

= D t ( x ) ∗ e f ( x ) ∗ − a t ( x ) ∗ h t ( x ) / Z t D_t(x)*e^{f(x)*-a_t(x)*h_t(x)}/{Z_t} Dt(x)ef(x)at(x)ht(x)/Zt

由此可以实现样本权值的更新,可以看出, f ( x ) = g ( x ) f(x)=g (x) f(x)=g(x)时,样本的权重减小,反之,样本的权重增大

3.实战

1.设置弱分类器,这里设置的是单层的决策树

#单个弱分类器,设置弱分类器的分类规则
def weakclassifier(data,dimension,flag,thresh):#使用阈值分类的方法,根据某个特征进行分类
    label=np.ones((data.shape[0],1))
    if flag=='less':#小于阈值的是第负类
        label[data[:,dimension]<=thresh]=-1
    if flag=='great':#大于阈值的是负类
        label[data[:,dimension]>=thresh]=-1
    return label

2.训练弱分类器

#训练弱分类器
#根据权值向量,寻找最佳的阈值分类器
def buildStump(data,labels,D):
    m,n=data.shape
    numstep=10  #确定步长
    best_state={}
    best_predict_labels=np.ones((m,1))
    min_error=np.inf
    data=np.mat(data)
    labels=np.mat(labels)
   
    for i in range(0,n):#遍历所有的特征
        max_num=max(data[:,i])
        min_num=min(data[:,i])
        stepsize=(max_num-min_num)/numstep  #求解当前列所需要走过的步数
        for j in range(-1,int(numstep+1)):
            thresh=(min_num+j*stepsize)#获得阈值
            for flag in ['less','great']:#设置阈值的求解方向
                predict_labels=weakclassifier(data,i,flag,thresh)#训练弱分类器,找到最好的分类方法
                error=np.mat(np.ones((m,1)))#定义误差矩阵
                error[labels==predict_labels]=0#如果预测对了就是0
                weighted_error=(D.T*error)  #按照公式,求解加权后的错误率
                if weighted_error<min_error :#如果说当前的错误率是最小的话,更新best_state,记录阈值、特征以及阈值的方向
                    min_error=weighted_error
                    best_state['dim']=i
                    best_state['thresh']=thresh
                    best_state['flag']=flag
                    best_predict_labels=predict_labels.copy()
    return min_error,best_predict_labels,best_state

3.集成分类器训练个体分类器,计算分类器的权值以及更新样本分布

#根据想要设置的弱分类器个数,生成和训练弱分类器
#计算样本的分布和分类器的权值
def strongClassifier(T,data,label):
    error_rate=1.0
    i=0
    weakClass=[]
    m,n=data.shape
    D=np.ones((m,1))*1/m
    range_label=np.zeros((m,1))
    while i<T and error_rate>1e-6:
        min_error,best_predict_labels,best_state=buildStump(data,label,D)#获得错误率
        if min_error>0.5:
            print('min_error>0.5,minerror=',min_error)
            break
        a=float(0.5*np.log((1-min_error)/min_error))#获得该分类器的权重
        best_state['alphi']=a  #记录该弱分类器的权重
        weakClass.append(best_state)
        D=np.multiply(D,np.exp(np.multiply(-a*(best_predict_labels.T),label)))
        D=D/D.sum()  #更新样本的分布
        range_label+=a*best_predict_labels
        error=np.ones((m,1))
        error[(np.sign(range_label)==label)]=0  #
        error_rate=np.sum(error)/m
        i=i+1
    return weakClass

4.循环每一个弱分类器,对测试集进行分类

#根据弱分类器的结果进行预测
def predict(test_data,weakClass):
    test_data=np.mat(test_data)
  
    predict_label=np.zeros((test_data.shape[0],1))
    for i in range(0,len(weakClass)):
        predict_label+=weakClass[i]['alphi']*weakclassifier(test_data,weakClass[i]['dim'],weakClass[i]['flag'],weakClass[i]['thresh'])#将T个弱分类器的分类结果加权求和
  return np.sign(predict_label)
T=10  #设定10个弱分类器
train_data,test_data,train_label,test_label=train_test_split(character,label,test_size=0.3,random_state=0)
weakClass=strongclassifier(T,train_data,train_label)
pre_label=predict(test_data,weakClass)
result=np.ones((pre_label.shape[0],1))
result[pre==np.mat(test_label).T]=0 #如果预测错误就将其值改为1
print('total',np.sum(result))
print("error rate",np.sum(result)/test_data.shape[0])

上述是针对二分类的计算方法,如果学习的任务是多酚类问题,可以采用one vs other的方法,每次将一类作为正样本,其余类作为负样本,将最终各类的预测结果融合即可

for item in set(label): #一类标签一类标签的去计算,鸢尾花数据集共计有3类标签
    train_label1=[-1 if i!=item else 1 for i in train_label]
    test_label1=[-1 if i!=item else 1 for i in test_label]
    weakClass=strongClassifier(T,train_data,train_label1)
    pre_label=predict(test_data,weakClass)
    result=np.ones((pre_label.shape[0],1))
    result[pre_label==np.mat(test_label1).T]=0 #如果预测错误就将其值改为1
    error_rate=np.sum(result)/test_data.shape[0]
    print("第%d类"%item,"的错误率为:",error_rate)
    mul_label=np.multiply(pre_label,1-error_rate)
    all_predict.append(mul_label)#所有的预测标签
    
#计算错误率 
final_predict=np.ones((45,1))*-1
for i in range(0,len(final_predict)):
    final_predict[i]=([all_predict[0][i],all_predict[1][i],all_predict[2][i]].index(max(all_predict[0][i],all_predict[1][i],all_predict[2][i])))+1


error=np.ones((len(test_label),1))
error[final_predict==(np.mat(test_label)).T]=0
print('最终错误率为',np.sum(error)/len(test_label))

使用的是鸢尾花的数据集,最终结果为:在这里插入图片描述
调用sklearn的包,结果为:

from sklearn.ensemble import AdaBoostClassifier
from sklearn.metrics import accuracy_score
model=AdaBoostClassifier(n_estimators=10)
train_data,test_data,train_label,test_label=train_test_split(character,label,test_size=0.3,random_state=0)
model.fit(train_data,train_label)
predict_label=model.predict(test_data)
print("准确率为:",accuracy_score(predict_label,test_label))

在这里插入图片描述

参考文献:


  1. 《机器学习》 周志华 ↩︎

  2. AdaBoost算法的原理与实现 ↩︎

  3. 《统计学习方法》 李航 ↩︎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值