1.算法思想:根据加权分类误差,增加错分样本的权值,降低正确分类样本的权值,串连地构建多个弱分类器,即上一个弱分类器改变的样本权值影响下一个弱分类器。根据弱分类器的分类误差,维护分类器的系数alpha。将各个弱分类器与系数乘积的和代入sign函数,最终得到分类结果。
2.算法实现逻辑
AdaBoost生成:这里介绍使用单层决策树(树桩)作为弱分类器,也可用CART树做弱分类器。
#对每次迭代:
#利用数据集与样本权值向量D,找出加权误差最小的单层决策树
#将该最佳单层决策树加入到单层决策树数组
#计算该最佳单层决策树的分类误差与分类器系数alpha
#计算新的权重向量D
#如果分类错误率为0.0,则退出循环
注:
ε为错误率
alpha=0.5ln(1/ε-1)
样本权重更新公式:
3.Python代码实现
1)加载数据集函数
def loadSimpData():
dataMat=matrix([[1.,2.1],
[2.,1.1],
[1.3,1.],
[1.,1.],
[2.,1.]])
classLabels=[1.0,1.0,-1.0,-1.0,1.0]
return dataMat,classLabels
2)生成单层决策树
def stumpClassify(dataMatrix,dimen,threshVal,threshIneq):
'''
进行树桩分类
:param dataMatrix:数据集
:param dimen: 特征维度序号
:param threshVal: 按照dimen列中值与threshVal对比进行分类
:param threshIneq: 符号>和<=
:return:
'''
retArray=ones((shape(dataMatrix)[0],1))#类别数组,初始化所有类别为正类
#如果dimen列对应值不满足不等式>threshVal或<=threshVal则为负类
if threshIneq=='lt':
retArray[dataMatrix[:,dimen]<=threshVal]=-1.0
else:
retArray[dataMatrix[:,dimen]>threshVal]=-1.0
return retArray
def buildStump(dataArr,classLabels,D):
'''
创建单层决策树
:param dataArr:训练数据集
:param classLabels: 类别标签数组
:param D: 关于每个训练数据的 权重向量
:return:
'''
#讲数据转化成矩阵形式
dataMatrix=mat(dataArr);labelMat=mat(classLabels).T
m,n=shape(dataMatrix)
#划分个数,最佳树桩信息,最佳树桩的分类结果
numSteps=10.0;bestStump={};bestClasEst=mat(zeros((m,1)))
minError=inf#最小权重误差
for i in range(n):
rangeMin=dataMatrix[:,i].min();rangeMax=dataMatrix[:,i].max()#i列中的最小和最大值
stepSize=(rangeMax-rangeMin)/numSteps#每步迈开多大
for j in range(-1,int(numSteps)+1):#对于所有步
for inequal in ['lt','gt']:#切换大于和小于符号
threshVal=(rangeMin+float(j)*stepSize)#阈值
predictedVals=stumpClassify(dataMatrix,i,threshVal,inequal)#预测结果数组
errArr=mat(ones((m,1)))#误差数组。初始化认为都错了
errArr[predictedVals==labelMat]=0#将预测值与真实值相等的错误值变成0,这样只有预测错误的样本为1
weightedError=D.T*errArr#乘以权重向量,得到权重误差
print "split:dim:%d,thresh%.2f,thresh ineqal:%s,the weighted error is %.3f"\
%(i,threshVal,inequal,weightedError)
if weightedError<minError:#更新最小权重误差
minError=weightedError
bestClasEst=predictedVals.copy()
bestStump['dim']=i
bestStump['thresh']=threshVal
bestStump['ineq']=inequal
return bestStump,minError,bestClasEst
3)adaboost生成
def adaBoostTrainDS(dataArr,classLabels,numIt=40):
weakClassArr=[]
m=shape(dataArr)[0]
D=mat(ones((m,1))/m)
aggClassEst=mat((zeros((m,1))))
for i in range(numIt):
bestStump,error,classEst=buildStump(dataArr,classLabels,D)
print "D:",D.T
#分类器权值alpha
alpha=float(0.5*log((1.0-error)/max(error,1e-16)))
bestStump['alpha']=alpha
weakClassArr.append(bestStump)
print "classEst:",classEst.T
#计算权重向量D
expon=multiply(-1*alpha*mat(classLabels).T,classEst)
D=multiply(D,exp(expon))
D=D/D.sum()
#错误率累加计算
aggClassEst+=alpha*classEst
print "aggClassEst:",aggClassEst.T
aggErrors=multiply(sign(aggClassEst)!=mat(classLabels).T,ones((m,1)))
errorRate=aggErrors.sum()/m
print "total error:",errorRate,"\n"
if errorRate==0.0:break
return weakClassArr,aggClassEst
4)adaboost分类
def adaClassify(datToClass,classifierArr):
dataMatrix=mat(datToClass)
m=shape(dataMatrix)[0]
aggClassEst=mat(zeros((m,1)))
for i in range(len(classifierArr)):
classEst=stumpClassify(dataMatrix,classifierArr[i]['dim'],classifierArr[i]['thresh'],classifierArr[i]['ineq'])
aggClassEst+=classifierArr[i]['alpha']*classEst
print aggClassEst
return sign(aggClassEst)
4.思考
1)当正负样本不均匀时,就会遇到非均衡分类问题。使用AdaBoost算法,给误分类样本增加权值,相当于增加误分类的样本数,降低正确分类样本的数量,能够有效解决非均衡分类问题。
2)最终的分类结果是根据各个弱分类器的分类结果乘分类器系数alpha累加得到的,类似于多数表决,表决时训练误差小的弱分类器比训练误差大的弱分类器作用大,这样能够有效解决单个分类器误差不可避免的问题,提高分类准确率。三个臭皮匠顶一个诸葛亮。
(对算法的认识不够深刻,写的不好,后面继续修正补充吧。。。)