学习目标
掌握集成学习的基本原理以及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)} e−f(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)} e−f(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)=−1∣x)+ e − H ( x ) ∗ P ( f ( x ) = 1 ∣ x ) e^{-H(x)}*P(f(x)=1|x) e−H(x)∗P(f(x)=1∣x)=0
e − H ( x ) ∗ P ( f ( x ) = 1 ∣ x ) e^{-H(x)}*P(f(x)=1|x) e−H(x)∗P(f(x)=1∣x)= e H ( x ) e^{H(x)} eH(x)* P ( f ( x ) = − 1 ∣ x ) P(f(x)=-1|x) P(f(x)=−1∣x)
取对数:
− H ( x ) + l n P ( f ( x ) = 1 ∣ x ) -H(x)+lnP(f(x)=1|x) −H(x)+lnP(f(x)=1∣x)= H ( x ) + l n P ( f ( x ) = − 1 ∣ x ) H(x)+lnP(f(x)=-1|x) H(x)+lnP(f(x)=−1∣x)
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)=21∗lnP(f(x)=−1∣x)P(f(x)=1∣x)
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(21∗lnP(f(x)=−1∣x)P(f(x)=1∣x))
可以看出:
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)=1∣x)>P(f(x)=−1∣x)时
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)=1∣x)<P(f(x)=−1∣x)时
当损失函数最小时:
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)=y∣x))
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) ∑x∈Daihi(x)
设 L ( H ∣ D ) L(H|D) L(H∣D)为在D分布下的损失函数,则:
L ( H ∣ D ) L(H|D) L(H∣D)= e − f ( x ) ∗ H ( x ) e^{-f(x)*H(x)} e−f(x)∗H(x)= e − f ( x ) ∗ a i ∗ h i ( x ) e^{-f(x)*a_i*h_i(x)} e−f(x)∗ai∗hi(x)
∂ L ( H ∣ D ) ∂ a \frac{\partial L(H|D)}{\partial a} ∂a∂L(H∣D)= e − f ( x ) ∗ a i ∗ h i ( x ) e^{-f(x)*a_i*h_i(x)} e−f(x)∗ai∗hi(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)] ∑−e−ai[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} −e−ai k 1 k_1 k1+ e a i k 2 e^{a_i}k_2 eaik2
当仅当 − e − a i -e^{-a_i} −e−ai 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} −e−ai ( 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} e−ai ( 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(Ht−1+ht∣D)= 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(e−f(x)∗(Ht−1(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(e−f(x)∗Ht−1(x)∗e−f(x)∗ht(x))
根据指数函数的泰勒展开式可以得到:
e − f ( x ) ∗ h t ( x ) e^{-f(x)*h_t(x)} e−f(x)∗ht(x)= 1 − f ( x ) ∗ h t ( x ) 1-f(x)*h_t(x) 1−f(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(e−f(x)∗Ht−1(x)∗(1−f(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(e−f(x)∗Ht−1(x)+1−f(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(e−f(x)∗Ht−1(x)∗(1−f(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(e−f(x)∗Ht−1(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(e−f(x)∗Ht−1(x)∗(f(x)∗ht(x))/Ex d[e−f(x)∗Ht−1(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[e−f(x)∗Ht−1(x)]e−f(x)∗Ht−1(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[e−f(x)∗Ht−1(x)]e−f(x)∗Ht−1(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[e−f(x)∗Ht(x)]e−f(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[e−f(x)∗Ht(x)]e−f(x)∗(Ht−1(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[e−f(x)∗Ht(x)]e−f(x)∗(Ht−1(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[e−f(x)∗Ht(x)]Dt(x)∗Ex d[e−f(x)∗Ht−1(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))