adaboost python实现小样例

时间:2022-09-09 00:29:05

元算法是对其他算法进行组合的一种方式。
单层决策树实际上是一个单节点的决策树。
adaboost
优点:泛化错误率低,易编码,可以应用在大部分分类器上,无参数调整
缺点:对离群点敏感
适用数据类型:数值型和标称型数据
bagging:基于数据随机重抽样的分类器构建方法
自举汇聚法,也称为bagging方法,是在从原始数据集选择S次后得到的S个新数据集的一种技术。
新数据集和原数据集的大小相等。每个数据集都是通过在原始数据集中随机选择一个样本来进行替换得到的。
这里的替换就意味着可以多次选择同一个样本。这一性质允许新数据集中可以有重复的值,而原始数据集的
某些值在新集合中则不再出现。
在S个数据集建好之后,将某个学习算法分别作用于每个数据集就得到了s个分类器。当我们要对新数据进行
分类时,就可以应用这s个分类器进行分类。与此同时,选择分类器投票结果中最多的类别作为最后的分类结果。
boosting是一种与bagging很类似的技术。不论是在boosting还是bagging当中,所使用的多个分类器的类型都是
一致的。但是在前者当中,不同的分类器是通过串行训练而获得的,每个新分类器都根据已训练出的分类器的性
能进行训练。boosting是通过集中关注被已有分类器错分的那些数据来获得新的分类器
由于boosting分类器的结果是基于所有分类器的加权求和结果的,因此boosting与bagging不太一样,bagging中的
分类器权重是相等的,而boosting中的分类器权重并不相等,每个权重代表的是其对应分类器在上一轮迭代中的成功度。
Adaboost的一般流程
(1)收集数据:可以适用任意方法
(2)准备数据:依赖于所使用的弱分类器类型,本章使用的是单层决策树,这种分类器可以处理任何数据类型。
当然也可以使用任意分类器作为弱分类器,第2章到第6章中的任一分类器都可以充当弱分类器。作为弱分类器,简单分类器的效果更好。
(3)分析数据:可以使用任意方法
(4)训练算法:AdaBoost的大部分时间都用在训练上,分类器将多次在同一数据集上训练弱分类器
(5)测试算法:计算分类的错误率
(6)使用算法:同SVM一样,AdaBoost预测两个类别中的一个。如果想把它应用到多个类别的场合,
那么就要像多类SVM中的做法一样对AdaBoost进行修改
弱分类器就是说在二分类下错误率会高于50%,而'强'分类器的错误率会低很多。
AdaBoost是adaptive boosting(自适应 boosting)的缩写,其运行过程如下:训练数据中的每个样本,并赋予其一个权重,
这些权重构成了向量D。一开始,这些权重都初始化称相等值。首先在训练数据上训练出一个弱分类器并计算该分类器的错
误率,然后在同一个数据集上再次训练弱分类器。在分类器的第二次训练当中,将会重新调整每个样本的权重,其中第一次
分对的样本的权重将会降低,而第一次分许哦的样本权重将会提高。为了从所有弱分类器中得到最终的分类结果,AdaBoost为
每一个分类器都分配了一个权重alpha,这些alpha值是基于每个弱分类器的错误率进行计算的。

  1 rom numpy import *
  2 
  3 def loadSimpData():
  4     datMat = matrix([[ 1. ,  2.1],
  5         [ 2. ,  1.1],
  6         [ 1.3,  1. ],
  7         [ 1. ,  1. ],
  8         [ 2. ,  1. ]])
  9     classLabels = [1.0, 1.0, -1.0, -1.0, 1.0]
 10     return datMat,classLabels
 11 
 12 '''
 13 接下来构造单层决策树。第一个函数将用于测试是否有某个值小于或大于我们正在测试的阈值。
 14 第二个函数则更加复杂一些,它会在一个加权数据集中循环,并找到具有最低错误率的单层决策树。
 15 这个程序的伪代码看起来大致如下:
 16 将最小错误率minError设为+∞
 17 对数据集中的每一个特征(第一层循环):
 18     对每个步长(第二层循环):
 19         对每个不等号(第三层循环):
 20             建立一颗单层决策树并利用加权数据集对它进行测试
 21             如果错误率低于minError,则将当前单层决策树设为最佳单层决策树
 22 返回最佳单层决策树
 23 '''
 24 
 25 
 26 def stumpClassify(dataMatrix, dimen, threshVal, threshIneq):  # just classify the data
 27     retArray = ones((shape(dataMatrix)[0], 1))
 28     if threshIneq == 'lt':
 29         retArray[dataMatrix[:, dimen] <= threshVal] = -1.0
 30     else:
 31         retArray[dataMatrix[:, dimen] > threshVal] = -1.0
 32     return retArray
 33 
 34 
 35 def buildStump(dataArr, classLabels, D):
 36     dataMatrix = mat(dataArr);
 37     labelMat = mat(classLabels).T
 38     m, n = shape(dataMatrix)
 39     numSteps = 10.0;
 40     bestStump = {};
 41     bestClasEst = mat(zeros((m, 1)))
 42     minError = inf  # init error sum, to +infinity
 43     for i in range(n):  # loop over all dimensions
 44         rangeMin = dataMatrix[:, i].min();
 45         rangeMax = dataMatrix[:, i].max();
 46         stepSize = (rangeMax - rangeMin) / numSteps
 47         for j in range(-1, int(numSteps) + 1):  # loop over all range in current dimension
 48             for inequal in ['lt', 'gt']:  # go over less than and greater than
 49                 threshVal = (rangeMin + float(j) * stepSize)
 50                 predictedVals = stumpClassify(dataMatrix, i, threshVal,
 51                                               inequal)  # call stump classify with i, j, lessThan
 52                 errArr = mat(ones((m, 1)))
 53                 errArr[predictedVals == labelMat] = 0
 54                 weightedError = D.T * errArr  # calc total error multiplied by D
 55                 # print "split: dim %d, thresh %.2f, thresh ineqal: %s, the weighted error is %.3f" % (i, threshVal, inequal, weightedError)
 56                 if weightedError < minError:
 57                     minError = weightedError
 58                     bestClasEst = predictedVals.copy()
 59                     bestStump['dim'] = i
 60                     bestStump['thresh'] = threshVal
 61                     bestStump['ineq'] = inequal
 62     return bestStump, minError, bestClasEst
 63 
 64 '''
 65 完整AdaBoost算法的实现
 66 整个实现的伪代码如下:
 67 对每次迭代:
 68     利用buildStump()函数找到最佳的单层决策树
 69     将最佳单层决策树加入到单层决策树数组
 70     计算alpha
 71     计算新的权重向量D
 72     更新累计类别的估计值
 73     如果错误率等于0.0,则退出循环
 74     
 75 '''
 76 def adaBoostTrainDS(dataArr,classLabels,numIt=40):
 77     weakClassArr = []
 78     m = shape(dataArr)[0]
 79     D = mat(ones((m,1))/m)   #init D to all equal
 80     aggClassEst = mat(zeros((m,1)))
 81     for i in range(numIt):
 82         bestStump,error,classEst = buildStump(dataArr,classLabels,D)#build Stump
 83         #print "D:",D.T
 84         alpha = float(0.5*log((1.0-error)/max(error,1e-16)))#calc alpha, throw in max(error,eps) to account for error=0
 85         bestStump['alpha'] = alpha
 86         weakClassArr.append(bestStump)                  #store Stump Params in Array
 87         #print "classEst: ",classEst.T
 88         expon = multiply(-1*alpha*mat(classLabels).T,classEst) #exponent for D calc, getting messy
 89         D = multiply(D,exp(expon))                              #Calc New D for next iteration
 90         D = D/D.sum()
 91         #calc training error of all classifiers, if this is 0 quit for loop early (use break)
 92         aggClassEst += alpha*classEst
 93         #print "aggClassEst: ",aggClassEst.T
 94         aggErrors = multiply(sign(aggClassEst) != mat(classLabels).T,ones((m,1)))
 95         errorRate = aggErrors.sum()/m
 96         print("total error: ",errorRate)
 97         if errorRate == 0.0: break
 98     return weakClassArr,aggClassEst
 99 
100 def adaClassify(datToClass,classifierArr):
101     dataMatrix = mat(datToClass)#do stuff similar to last aggClassEst in adaBoostTrainDS
102     m = shape(dataMatrix)[0]
103     aggClassEst = mat(zeros((m,1)))
104     for i in range(len(classifierArr)):
105         classEst = stumpClassify(dataMatrix,classifierArr[i]['dim'],classifierArr[i]['thresh'],classifierArr[i]['ineq'])#call stump classify
106         aggClassEst += classifierArr[i]['alpha']*classEst
107         print(aggClassEst)
108     return sign(aggClassEst)
109 
110 
111 dataMat,classLabels=loadSimpData()
112 D=mat(ones((5,1))/5)
113 A,B,C=buildStump(dataMat,classLabels,D)
114 classifierArr=adaBoostTrainDS(dataMat,classLabels,30)
115 print(classifierArr)
116 adaClassify([0,0],classifierArr)

小结:集成方法通过组合多个分类器的分类结果,获得了比简单的单分类器更好的分类结果。有一些利用不同分类器的继承方法,但是本章只介绍了那些利用同一类分类器的集成方法。

多个分类器组合可能会进一步凸显单分类器的不足,比如过拟合问题。如果分类器之间差别显著,那么多个分类器组合就可能会缓解这一问题。分类器之间的差别可以是算法本身或者是应用于算法上的数据的不同

本章介绍的两种集成方法是bagging和boosting。在bagging中,是通过随机抽样的替换方式,得到了与原始数据集规模一样的数据集。而boosting在bagging的思路上更进了一步,他在数据集上顺序应用了多个不同的分类器。另一个成功的继承方法就是随机森林,但是由于随机森林不如adaboost流行,所以本书并没有对他进行介绍

本章介绍了boosting方法中最流行的一个称为AdaBoost的算法。AdaBoost以弱学习器作为基分类器,并且输入数据,使其通过权重向量进行加权。在第一次迭代当中,所有数据都等权重。但是在后续的迭代当中,前次迭代中分错的数据的权重会增大。这种针对错误的调节能力正是Adaboost的长处。

本章以单层决策树作为弱学习器构建了AdaBoost分类器。实际上,AdaBoost函数可以应用于任意分类器,只要该分类器能够处理加权数据即可,AdaBoost算法十分强大,它能够快速处理其他分类器很难处理的数据集。

非均衡分类问题是指在分类器训练时正例数目和反例数目不相等(相差很大)。该问题在错分正例和反例不同时也存在。

本章介绍了通过过抽样和欠抽样方法来调节数据集中的正例和反例数目。另外一种可能更好的非均衡问题的处理方法,就是在训练分类器时将错误的代价考虑在内