本文主要包括adaboost和提升树,后期会扩展到XGboost和LightGBM。
boosting通过改变样本训练权重,学习多个弱分类器,最后进行线性组合,提高分类性能。
两个着重点:如何改变数据的样本权重或概率分布 如何将弱分类器整合成强分类器
Adaboost(Adaptiveboost)
adaboost通过提高错误分类样本权重,使的下一轮错误数据由于上一轮调高权重,而受到弱分类的关注。同时,使用加权多数表决的方式,组成一个强分类器。
算法流程:
- 初始化样本数据权重,假设样本权重均匀分布,得到初始权重分布D1
- 使用初始权重的训练数据集学习,得到基本分类器G1
- 计算G1在权重分布D1上的误差率
- 依据公式计算G1的权重
- 在D1基础上,依据误分率更改样本的权重分布,错误分类数据的权重提升,得到权重分布D2
- 迭代m轮,构建线性组合的强分类器Gm
adaboost的训练误差分析
这说明,可以在每一轮选取适当的Gm使得Zm最小,从而使训练误差下降最快,对二分类问题,有如下结果:
adaBoost的另外一个解释:
模型:加法模型
策略:最小化指数函数
算法:前向分步
公式的推导:
1、证明使用指数函数作为损失函数的合理性
2、计算弱分类器的权重
3、更新权重分布
adaboost python实现:
from numpy import *
def loaddata():
datMat=matrix([
[1.0,2.1],
[2,1.1],
[1.3,1.],
[1.,1.],
[2.,1.]
])
classLabels=[1.0,1.0,-1.0,-1.0,1.0]
return datMat,classLabels
##一个简单树的决策函数
def stumpClassify(dataMatrix,dimen,threshVal,threshInsq):
"""
:param dataMatrix:数据
:param dimen: 特征
:param threshVal: 阈值
:param threshInsq: 大于还是小于
:return:
"""
retArray= ones((shape(dataMatrix)[0],1))
if threshInsq=='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={}
bestClassEnt=mat(zeros((m,1)))
minError=inf
for i in range(n):
##寻找特征的分割点
rangeMin=dataMatrix[:,i].min()
rangeMax=dataMatrix[:,i].max()
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)
threshVal=(rangeMin+float(j)*stepSize)
errArr=mat(ones((m,1)))
#计算错误的权重
errArr[predictedVals==labelMat]=0
weightedError=D.T*errArr
if weightedError<minError:
minError=weightedError
bestClassEnt=predictedVals.copy()
bestStump['dim']=i
bestStump['thresh']=threshVal
bestStump['ineq']=inequal
return bestStump,minError,bestClassEnt
def adaBoostTrainDS(dataArr,classLabels,numIt=40):
"""
:param dataArr: 数据
:param classLabels: 样本类别
:param numIt: 迭代次数
:return:
"""
weakClassArr=[]
m=shape(dataArr)[0]
##初始的权重分布
D=mat(ones((m,1))/m)
aggClassEst=mat(zeros((m,1)))
##迭代numlt次
for i in range(numIt):
bestStump,error,classEst=buildStump(dataArr,classLabels,D)
##第一个alpha的值
alpha=float(0.5*log((1.0-error)/max(error,1e-16)))
bestStump['alpha']=alpha
weakClassArr.append(bestStump)
print("classEst",classEst.T)
expon=multiply(-1*alpha*mat(classLabels).T,classEst)
#更新权重
D=multiply(D,exp(expon))
D=D/D.sum()
aggClassEst+=alpha*classEst
aggErrors=multiply(sign(aggClassEst)!=mat(classLabels).T,ones((m,1)))
errorRate=aggErrors.sum()/m
print('total error:',errorRate)
if errorRate==0.0:
break
return weakClassArr
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'])
##利用前面训练好的adaboost模型进行预测
aggClassEst+=classifierArr[i]['alpha']*classEst
print(aggClassEst)
return sign(aggClassEst)
if __name__ == '__main__':
datMat,classLabels=loaddata()
classifierArray=adaBoostTrainDS(datMat,classLabels,30)
print("[0,0]:\n", adaClassify([0, 0], classifierArray))
print("\n\n[[5,5],[0,0]]:\n", adaClassify([[5, 5], [0, 0]], classifierArray))
提升树算法
提升树算法采用的是前向分步算法通过经验风险极小化确定下一颗决策树的参数
针对不同问题提升树学习算法,主要区别在于使用损失函数的不同,包括回归问题使用均方误差,分类问题的指数损失函数,以及一般决策问题的一般损失函数。
梯度提升树与adaboost的关系
梯度提升树分为分类树,回归树;adaboost将基本弱分类器限制为二类分类树就是提升树