您的位置:首页 > 编程语言 > Python开发

python机器学习实战:Adaboost

2017-10-15 19:27 387 查看
1.AdaBoost算法:

  什么叫AdaBoost算法呢,我们可以这样理解:当我们做重要的决定的时候,我们一个人的意见有可能是错误的,但时如果我们能够吸取多个人的意见再做决定,那我们犯错误的几率就会大大的下降,没错,AdaBoost就是就是这样的算法,当我们只采用一个分类器来分类的时候,我们犯错的几率可能会是30%,但是如果我们采用多个分类器来分类,那我们的错误几率就有可能降低到10%,甚至5%以内。这就是AdaBoost强大的能力。

2.AdaBoost算法的实现:

  首先我们将会建立一个单层的决策树分类器,它是一个单节点的决策树。AdaBoost将建立在这个单层分类器上。

AdaBoost的运行过程如下:训练数据中的每个样本,并赋予一个权重,这些权重构成向量D。一开始,这些权重都初始化为相等的值。首先在训练数据上训练出一个弱分类器,并计算该分类器的准确率,然后在同一数据集上再次训练弱分类器。在分类器的第二次训练当中,将会重新调整每个样本的权值,其中第一次分对的样本权值将会下降,第一次分错的样本的权值将会增加。为了从所有弱分类器中得到最终的分类结果,AdaBoost为每个分类器都分配了一个权值alpha,这些alpha是基于每个弱分类器的错误率进行计算的:

                                  error=未分对的样本数/所有样本数目

              alpha的计算公式如下:

                             alpha=1/2  *  ln(1-error/error)

   容易发现当错误率error越大时,该分类器对应得权值alpha就越小,error越小,该分类器对应得权值就越大。

AdaBoost的工作原理如图:



首先我们需要创建一个单层决策数分类器:from numpy import *
#单侧决策树分类器
def stumpClassify(dataMatrix,dimen,threshVal,threshIneq):
"""
次函数的功能就是:将dataMatrix的第dimen个维度的数据与threshVal进行比较,对dataMatrix进行分类,
将大于threshVal的分成一类,
将小于threshVal的 分成另外一类。
:param dataMatrix: 数据集
:param dimen: 分类依据的维度
:param threshVal: :分类依据的阈值
:param threshIneq: 分类的方法:it:将大于阈值的置为1,小于阈值的置为-1 ge:将小于阈值的置为1,大于阈值的置为-1
"""
retArray=ones((shape(dataMatrix)[0],1))#用来保存分类结果的矩阵

if threshIneq=='It':
retArray[dataMatrix[:,dimen]<=threshVal]=-1.0#如果维度dimen中数据小于threshVal,就将retArray的对应值置为-1
else:
retArray[dataMatrix[:,dimen]>threshVal]=-1.0
return retArray #返回的是标签的预测值

#选择最佳的单侧决策树分类器
def buildStump(dataArr,classLabels,D):
 dataMatrix=mat(dataArr) #数据集
labelMat=mat(classLabels).T #标签

m,n=shape(dataMatrix) #m为样本数据数量,n为样本数据维度。
numSteps=10.0 #阈值迭代的步数
bestStump={}#保存最
4000
佳分类器
bestClasEst=mat(zeros((m,1)))#储存数据的预测值
minError=inf

for i in range(n):#对数据集中的每一个特征循环
rangeMin=dataMatrix[:,i].min()#取得第i个维上的最小值
rangeMax=dataMatrix[:,i].max()#取得第i个维度上的最大值

stepSize=(rangeMax-rangeMin)/numSteps

for j in range(-1,int(numSteps)+1):#对每个步长循环
for inequal in ['It','gt']:
threshVal=(rangeMin+float(j)*stepSize) #分类的阈值
predictedVals=stumpClassify(dataMatrix,i,threshVal,inequal)#对第i个维度上的数据进行阈值分类。
errArr=mat(ones((m,1))) #错误矩阵
errArr[predictedVals==labelMat]=0#对于m个数据预测正确值0,错误置为1

weightedError=D.T*errArr#计算错误率

if weightedError<minError:
minError=weightedError
bestClasEst=predictedVals.copy()
bestStump['dim']=i
bestStump['thresh']=threshVal
bestStump['ineq']=inequal
return bestStump,minError,bestClasEst

上面有两个函数,这两个函数的功能就是构建一个最佳的决策树分类器。为下面的AdaBoost分类器打下基础。上面的算法耐心的一行一行看吧,想我当初也是这么过来的。
接下来我们来测试一下上面的两个函数:

创建数据集:

def loadSimpData():
datMat = 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 datMat, classLabels

这个函数返回5个数据集。

dataMat,classLabels=loadSimpData()
D=mat(ones((5,1))/5)
stump,error,clasest= buildStump(dataMat,classLabels,D)
print("最佳分类器stump:",stump)
print("错误率error:",error)
print("预测值clasest:",clasest)

运行的结果为:



可以发现我们训练出来的单层决策树分类器为stump,错误率为0.2,我们的真实值为[1.0, 1.0, -1.0, -1.0, 1.0],预测值的第一个数据错误。

下面我们将会才会AdaBoost来增强这个分类器:

每次迭代:

   利用 buildStump()函数找到最佳单层决策树。
   将最佳单层决策树加入到单层决策树数组。
   计算alpha
   计算新的权重向量D
   更新累计类别估计值
   如果错误率等于0.0 退出循环
其中权重的更新算法为:



 代码如下:

def adaBoostTrainDS(dataArr,classLabels,numIt=40):
weakClassArr=[]#保存基本分类器
m=shape(dataArr)[0]#m为数据的样本数
D=mat(ones((m,1))/m)#样本的权值矩阵
aggClassEst=mat(zeros((m,1)))

for i in range(numIt):#迭代numIt次
bestStump,error,classEst=buildStump(dataArr,classLabels,D)#找到最佳决策树
alpha=float(0.5*log((1.0-error)/max(error,1e-16)))#根据错误率求出alpha

bestStump['alpha']=alpha
weakClassArr.append(bestStump)#将最佳决策树加到决策树数组

#更新D的值(公式在上面)
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:print(D);break#如果错误率为0,跳出循环

return weakClassArr,aggClassEst #返回分类器列表和最终的预测值矩阵


这个函数的功能就是叠加多个单层分类器来实现决策。
验证代码为:

dataMat,classLabels=loadSimpData()
weakClassArr,aggClassEst=adaBoostTrainDS(dataMat,classLabels,9)
print("分类器列表:",weakClassArr)
print("预测值:",aggClassEst)

结果如下:
分类器列表: [{'dim': 0, 'thresh': 1.3, 'ineq': 'It', 'alpha': 0.6931471805599453}, {'dim': 1, 'thresh': 1.0, 'ineq': 'It', 'alpha': 0.9729550745276565}, {'dim': 0, 'thresh': 0.90000000000000002, 'ineq': 'It', 'alpha': 0.8958797346140273}]

预测值: [[ 1.]

 [ 1.]

 [-1.]

 [-1.]

 [ 1.]]

可以看到有三个分类器,最终的预测结果与实际值[1.0, 1.0, -1.0, -1.0, 1.0],与上面的单层决策树的结果相比,准确率提高了偶,是不是很有趣。

上面的预测结果是在训练集上的,接下来我们在测试集上进行验证。

def adaClassify(datToClass,classifierArr):
"""

:param datToClass: 测试数据集
:param classifierArr: 由adaBoostTrainDS返回的分类器
:return: 预测值
"""
dataMatrix=mat(datToClass)
m=shape(dataMatrix)[0]#m为测试集的大小
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#alpha*分类器

print (aggClassEst)
return sign(aggClassEst)

以上就是在测试集上的验证函数。
classifierArr,est=adaBoostTrainDS(dataMat,classLabels,30)
prediction=adaClassify([0,0],classifierArr)
print(prediction)

运行结果为:预测值: [[-1.]]

以上就实现了一个简单的AdaBoost分类器,哎呀,终于写完了,说实话,在下对机器学习的理解也还有限,如果有错误的地方还请大家指出。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: