Adaboost

来源:互联网 发布:淘宝卖弓犯法吗 编辑:程序博客网 时间:2024/06/07 13:19

原文
上述文章讲了AdaBoost(adaptive boosting自适应提升算法)的理论基础和一个小例子。
bagging(bootstrap aggregating,自举汇聚法)是从原始数据集选择S次后得到S个新数据集的一种技术。
boosting是一种与bagging很类似的技术。boosting和bagging所使用的分类器的类型都是一致的。但是boosting的分类器是通过串行训练而或得,每个新分类器都根据已训练出来的分类器的性能来进行训练,boosting是通过集中关注被已有分类器错分的那些数据来获得新的分类器。
bagging中的分类器权重是相等的,而boosting中的分类器权重并不相等,

每个权重代表的是对应分类器在上一轮迭代中的成功度。

基于单层决策树构建弱分类器

单层决策树(decision stump,也称决策树桩)是一种简单的决策树。
我们将构建一个单层决策树,仅基于单个特征来做决策。由于这棵树只有一次分裂过程,因此它实际上就是一个树桩。
首先通过一个简单数据集确保算法在实现上一切就绪。
新建adaboost.py

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

如果想要试着从某个坐标轴上选择一个值(即选择一条与坐标轴平行的直线)来将+1和-1分开,显然是不可能的,这就是单层决策树难以处理的一个著名问题。通过使用多棵决策树,可以构建出一个能够对该数据集完全正确分类的分类器。
导入数据集和类标签:

import adaboostdatMat,classLabels=adaboost.loadSimpData()

接下来通过构建多个函数来构建单层决策树
第一个函数用来测试是否有某个值小于或者大于我们正在测试的阈值。
第二个函数则会在一个加权数据集中循环,并找到具有最低错误率的单层决策树。
伪代码如下:

将最小错误概率minError设为+无穷对数据集中的每一个特征(第一层循环):    对每个步长(第二层循环):        对每个不等号(第三层循环):            建立一棵单层决策树并利用加权数据集对它进行测试            如果错误率低于minError,则将当前单层决策树设为最佳单层决策树返回最爱单层决策树
//单层决策树生成函数def stumpClassify(dataMatrix,dimen,threshVal,threshIneq):    retArray=ones((shape(dataMatrix)[0],1))    if threshIneq=='lt':        retArray[dataMatrix[:,dimen]<=threshVal]=-1.0    else:        retArray[dataMatrix[:,dimen]>threshVal]=-1.0    return retArraydef buildStump(dataArr,classLabels,D):    dataMatrix=mat(dataArr);labelMat=mat(classLabels).T    m,n=shape(dataMatrix)    numSteps=10.0;bestStump={};bestClassEst=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)                errArr=mat(ones((m,1)))                errArr[predictedVals==labelMat]=0                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

第一个函数stumpClassify()通过阈值比较对数据进行分类,所有在阈值一边的数据分类到类别 -1,另一边的分类到+1。该函数通过函数过滤来实现,首先将返回数组的全部元素设置为1,然后将所有不满足不等式要求的元素设置为-1,可以基于数据集中的任一元素进行比较,同时也可以将不等号在大于,小于之间切换。
第二个函数buildStump()将会遍历stumpClassify()函数所有的可能输入值,并找到数据集上最佳的单层决策树。这里的最佳是基于数据的权重向量D来定义的。在确保输入数据符合矩阵格式之后,整个函数就开始执行了。
然后,函数将构建一个称为bestStump的空字典,这个字典用于存储给定权重向量D时所得到的最佳单层决策树的相关信息。
变量numSteps用于在特征的所有可能值上进行遍历。
minError则一开始就初始化成正无穷大,之后用于寻找可能的最小错误率。
三层嵌套的for循环是最主要的部分,第一层for循环在数据集的所有特征上遍历。考虑到数值型的特征,我们可以通过计算最大值和最小值来了解应该需要多大的步长
第二层for循环在这些值上遍历,甚至将阈值设置在这些值之外也是可以的,因此,在取值范围之外还应该有2个额外的步骤。最后一个for循环则是在大于小于之间切换不等式。
在嵌套的三层for循环之内,我们在数据集及3个循环变量上调用stumpClassify()函数。基于这些循环变量,该函数将会返回分类预测结果。接下来构建一个列向量errArr,如果predictedVals中的值不等于labelMat中的真正类别标签值,那么errArr的相应位置为1.
将错误向量errArr和权重向量D的相应元素相乘并求和,得到数值weightedError。这就是Adaboost和分类器交互的地方。这里是基于权重向量D而不是其他错误计算指标来评价分类器的,如果需要其他分类器的话,就需要考虑D上最佳分类器所定义的计算过程。

完整的Adaboost算法实现

//整个实现的伪代码如下:对每次迭代:    利用buildStump()函数找到最佳的单层决策树    将最佳单层决策树加到单层决策树数组    计算alpha    计算新的权重向量D    更新累计类别估计值    如果错误率等于0.0,则退出循环。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 = 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        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    print weakClassArr    return weakClassArrdatMat,classLabels = loadSimpleData()adaBoostTrainDS(datMat,classLabels,9)
0 0
原创粉丝点击