Adaboost
提升方法就是从弱学习器出发,反复学习,得到一系列弱分类器(基本分类器),然后组合这些弱分类器,构成一个强分类器。
基本思路
待解决问题
1、每一轮如何改变训练数据的权值或概率分布
2、如何将弱分类器组合成强分类器
解决方法
1、高低赋权:提高在前一轮分类中分类错误的样本的权值,降低分类正确的样本的权值(分类问题被一系列弱分类器“分而治之”)
2、加权多数表决:加大分类误差率小的弱分类器的权值,使其在表决中起较大的作用。(因为Adaboost最终目标就是要提高分类效率,分类误差率低作用就好,因此要提高其在整个系统中的权值)
*弱分类器采用串联的形式,后一轮的演变与前一轮的训练结果紧密相关。
Adaboost算法
以二分类训练数据集为例 ,每个样本由实例和标记组成,T={(x~i~, y~i~
)} x属于Rn,y属于{1, -1}
步骤
(2)(a)中I函数表示指数函数,当括号内为True时,输出为1否则输出为0,所以整个et可以理解为所有被分类器误分类的样本占所有样本的比例,即该分类器的出错率。值得强调的一点是,由于第一轮所有样本的权重相同,所以et就是出错率,但是随着新一轮的测试的进行,就要开始调节权重,即前文所提到的高低赋权,着重调高被误分类的样本的权值,调低被正确分类的样本的权值。
此外et=∑P(Ht(xi)≠yi)(被G误分类样本的权值之和)
(b)中的at表示各基本分类器在最终分类器的线性组合中的重要性,因为et是分类错误率,一旦分类错误率大于1/2,那么它对应基本分类器的分类性能就比较弱,分类效果还不如瞎猜的好,那么当错误率小于等于1/2的时候,at>0,而且log函数是一个随着et减小而增大的函数,那么它在最终分类器中的作用就比较强,即分类误差率越小的基本分类器在最终分类器中的作用越大。
©对新一轮权值的更新,误分类样本的权值得到扩大,正确分类的样本权值减小,因为分子位置 会随着正误分类指数的位置为正或负,若指数位置为正的时候相比于负对最终结果影响会大。
at之和并不为1.其中sign为符号函数,最终结果取决于所有分类器的分类结果,少数服从多数。
import pdb
import numpy as np
import operator
import math
def dataset():
data=[0,1,2,3,4,5,6,7,8,9]
labels=[1,1,1,-1,-1,-1,1,1,1,-1]
return data,labels
def mytree(data,label,D1): #生成最优决策树,D是权值
point=(np.array(data[:-1])+np.array(data[1:]))/2 #取data中相邻两者之间的平均值
#结果:array([0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5])一共有九个划分点
dic={}
sign={}
for i in point: #遍历分割点
predict1=np.array(data<i) #判断分割点左边为1 生成[true,false]
predict1=(predict1+0)+(predict1-1) #将true和false结果转换为[1,-1] predict=[0,1] 2*predict-1=[1,-1]
result1=sum(abs(predict1-label)/2*D1) #误差
predict2 = np.array(data > i) #判断右边为1
predict2 = (predict2 + 0) + (predict2 - 1)
result2 = sum(abs(predict2 - label) / 2 * D1) #误差em abs函数是取绝对值 当predict和label相同的时候被抵消,相异的时候变成原来的二倍
if result1<=result2: #保存符号和左右边哪个结果更好
dic[i]=result1
sign[i]='<'
else:
dic[i]=result2
sign[i]='>'
bestpoint = sorted(dic.items(),key=operator.itemgetter(1)) #对dic列表排序,以item中的第二个元素为索引键,即value
#返回一个可调用对象,用于从运算对象中获取元素,其实是采用运算对象的_getitem_()方法。如果指定了多个项目,返回一个元组形式。
return bestpoint[0],sign[bestpoint[0][0]] # bestpoint表示返回列表第一位元素,即错误率最低的元素,sign对象index是i,value是‘<’或者>
def Zm1(label,Gm,a,D1): #返回当前样本的权重 D1是一个1*10的矩阵
sum=0
for i in range(len(label)): #label长度为10
sum+=D1[i]*math.e**(-a*label[i]*Gm[i]) #sum就是归一化因子
newD1=[] #创建对象,用来存储新一轮各训练数据的权重
for i in range(len(label)):
w=D1[i]/sum*math.e**(-a*label[i]*Gm[i])
newD1.append(w)
return newD1
def adaboot1():
data,label=dataset() #获取数据集和标签文件
D1=[1/len(data)]*len(data) #求每一个样本的初始权重,0.1
bestpoint=[] #保存目前最佳的分割点
besta=[] #保存每一棵基决策树对应的权重
signall=[] #保存每一个最佳分割点对应的符号(大于或小于)
result=[] #保存每个基决策树对样本分类的结果
for i in range(20):
ht,sign=mytree(data,label,D1)#???当前最好的树 ,ht是每棵树最终选好的em
print(ht)
signall.append(sign) #保依次存记号
bestpoint.append(ht[0]) #保存当前最佳分割点 ht表示bestpoint列表中的两个内容。一个是划分点一个是错误率。
if sign==str('>'):
Gm= np.array(data > ht[0])
Gm = (Gm+0) + (Gm-1)
else:
Gm= np.array(data < ht[0])
Gm = (Gm+ 0) + (Gm- 1) #样本代入树中得到当前样本结果
a=0.5*(math.log((1-ht[1])/ht[1])) # 通过误差计算得到基决策树权值
besta.append(a) # 依次保存每棵基决策树对应的权重。
result.append(Gm) #依次保存每个基分类器
D1=Zm1(label,Gm,a,D1) #计算得到每个样本点的权值
sum1=[0]*len(data) # [0]此时是一个int类型,len(data)个int组成sub数组,list类型.
print(len(result),len(besta)) #sum变成list类型 ,输出形式:[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
for i in range(len(result)): #以下循环计算当前结果是否达到最优
sum1+=result[i]*besta[i]#result=w1f(x1)+w2f(x2)+..
print(sum1)
sum1 = np.array(sum1>=0)
sum1 = (sum1 + 0) + (sum1- 1)
if sum(sum1==label)==len(data): #如果结果相等,则输出以下语句 ,最终误分类点为零个,完成整个建模过程
print("一种生成{}棵基函数".format(len(result)))
for i in range(len(result)): #result长度为3,要循环3次
dic = {} #创建对象
print ("第{}棵决策树是".format(i+1)) #i+1精度加一
if signall[i]==str('>'): #如果最佳分割点对应的符号是‘>’
dic['num'+'>' + str(bestpoint[i])]=1
dic['num'+'<' + str(bestpoint[i])] = -1
if signall[i] == str('<'):
dic['num'+'<' + str(bestpoint[i])] = 1
dic['num'+'>' + str(bestpoint[i])] = -1
print(dic)
print ("权值是{}".format(besta[i]))
print()
break
adaboot1()在这里插入代码片
代码借鉴https://blog.csdn.net/qq_37960402/article/details/88539253