1.adaBoost元算法简介
在之前我们LZ介绍了不同的分类器,如果我们根据实际的要求对这些分类器进行组合,这种组合的结果则被称为集成算法(ensemble method)或者元算法(meta-method)。
我们这次使用的算法就是adaBoost,先给小伙伴一个直观的印象,该算法的优点是:泛化错误率低,易编码,可以应用在大部分分类器上,无参数调整。缺点是对离群点敏感,适用的数据类型:数值型和标称型数据。
自举汇聚法(bootstrap aggregating),也称为bagging方法,是在从原始数据集选择S次后得到S个新数据集的一种技术。bagging中的数据集相当于是有放回取样,比如要得到一个大小为n的新数据集,该数据集中的每个样本都是在原始数据集中随机抽样(有放回),也就是说原始数据集中的样本有部分可能就不会出现在新的数据集中,而有些样本可能会出现不止一次。
在S个数据集建立好之后,就会应用某种算法产生S个分类器,然后对每个分类器附上对应权重,加权求和后获得最后的结果。
bagging算法有很多种:例如随机森林等就自行研究
boosting是一种与bagging很类似的技术,这两种技术使用的分类器的类型都是一致的,前者是通过不同的分类器串行训练得到的,每个分类器都根据已训练出的分类器的性能来进行训练。boosting是通过集中关注被已有分类器错分的哪些数据来获得新的分类器。由于boosting分类结果是基于所有分类器的加权求和结果的,因此和bagging不太一样,bagging中的分类器的权重是相等的。boosting中的分类器权重并不相等,每个权重代表的是其对应分类器在上一轮迭代中的成功度。
adaBoost是adaptive boosting(自适应boosting)的缩写,而其想法就是如果我们能够建立一些弱分类器,这些分类器的性能比随机猜测要略好,但也不会好很多,那么如果我们把多个弱分类器构建成一个强分类器,那么结果会怎么样呢?
AdaBoost的运行过程如下:训练数据中的每个样本,并赋予其一个权重,这些权重构成了向量D。一开始这些权重都初始化相等值。首先在训练数据上训练出一个弱分类器并计算该分类器的错误率,然后在统一数据上再次训练弱分类器。在分类器的第二次训练当中,将会重新调整每个样本的权重,其中每一次分对的样本的权重将会降低,而第一次分错的样本的权重就会提高。为了从所有弱分类器中得到最终的分类结果,Adaboost为每个分类器都分配了一个权重值alpha,这些alpha值是基于每个弱分类器的错误率进行计算的。其中,错误率ϵ\epsilonϵ的定义为:
ϵ=未正确分类的样本数目所有样本数目\epsilon=\frac{未正确分类的样本数目}{所有样本数目}ϵ=所有样本数目未正确分类的样本数目
而α\alphaα的计算公式如下:
α=12In(1−ϵϵ)\alpha = \frac{1}{2}In(\frac{1-\epsilon}{\epsilon})α=21In(ϵ1−ϵ)
计算出α\alphaα值后,可以对权重向量D进行更新,以使得那些正确的分类的样本的权重降低而错分样本的权重升高。D的计算方法如下.
如果某个样本被正确分类,那么样本的权重更新为:
Dit+1=Dite−αSum(D)D^{t+1}_i = \frac{D^{t}_{i}e^{-\alpha}}{Sum(D)}Dit+1=Sum(D)Dite−α
如果某个样本被错分,那么样本的权重更新为:
Dit+1=DiteαSum(D)D^{t+1}_i = \frac{D^{t}_{i}e^{\alpha}}{Sum(D)}Dit+1=Sum(D)Diteα
在计算出D之后,AdaBoost又开始进入下一轮迭代。AdaBoost算法会不断地重复训练和调整权重的过程,直到训练错误率为0或者弱分类器的数目达到用户的指定值为止。
2.adaBoost的代码实现
#coding:utf-8#导入numpy依赖库fromnumpyimport*#创建简单数据集,后面会用到比较复杂的数据集defloadSimpData():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]returndatMat,classLabels#读取数据集的函数defloadDataSet(fileName):#general function to parse tab -delimited floatsnumFeat=len(open(fileName).readline().split('\t'))#get number of fieldsdataMat=[];labelMat=[]fr=open(fileName)forlineinfr.readlines():lineArr=[]curLine=line.strip().split('\t')foriinrange(numFeat-1):lineArr.append(float(curLine[i]))dataMat.append(lineArr)labelMat.append(float(curLine[-1]))returndataMat,labelMat#单层决策树生成函数#单层决策树仅基于单个特征来做决策defstumpClassify(dataMatrix,dimen,threshVal,threshIneq):#just classify the dataretArray=ones((shape(dataMatrix)[0],1))ifthreshIneq=='lt':retArray[dataMatrix[:,dimen]<=threshVal]=-1.0else:retArray[dataMatrix[:,dimen]>threshVal]=-1.0returnretArray#遍历stumpClassify()函数所有的可能输入值,并找到数据集上最佳的单层决策树defbuildStump(dataArr,classLabels,D):dataMatrix=mat(dataArr);labelMat=mat(classLabels).T m,n=shape(dataMatrix)numSteps=10.0;bestStump={};bestClasEst=mat(zeros((m,1)))minError=inf#init error sum, to +infinityforiinrange(n):#loop over all dimensionsrangeMin=dataMatrix[:,i].min();rangeMax=dataMatrix[:,i].max();stepSize=(rangeMax-rangeMin)/numStepsforjinrange(-1,int(numSteps)+1):#loop over all range in current dimensionforinequalin['lt','gt']:#go over less than and greater thanthreshVal=(rangeMin+float(j)*stepSize)predictedVals=stumpClassify(dataMatrix,i,threshVal,inequal)#call stump classify with i, j, lessThanerrArr=mat(ones((m,1)))errArr[predictedVals==labelMat]=0weightedError=D.T*errArr#calc total error multiplied by D#print "split: dim %d, thresh %.2f, thresh ineqal: %s, the weighted error is %.3f" % (i, threshVal, inequal, weightedError)ifweightedError<minError:minError=weightedError bestClasEst=predictedVals.copy()bestStump['dim']=i bestStump['thresh']=threshVal bestStump['ineq']=inequalreturnbestStump,minError,bestClasEst#基于单层决策树的AdaBoost训练过程,指定迭代次数numIt,DS代表的就是单层决策树defadaBoostTrainDS(dataArr,classLabels,numIt=40):weakClassArr=[]m=shape(dataArr)[0]D=mat(ones((m,1))/m)#init D to all equalaggClassEst=mat(zeros((m,1)))foriinrange(numIt):bestStump,error,classEst=buildStump(dataArr,classLabels,D)#build Stump#print "D:",D.Talpha=float(0.5*log((1.0-error)/max(error,1e-16)))#calc alpha, throw in max(error,eps) to account for error=0bestStump['alpha']=alpha weakClassArr.append(bestStump)#store Stump Params in Array#print "classEst: ",classEst.Texpon=multiply(-1*alpha*mat(classLabels).T,classEst)#exponent for D calc, getting messyD=multiply(D,exp(expon))#Calc New D for next iterationD=D/D.sum()#calc training error of all classifiers, if this is 0 quit for loop early (use break)aggClassEst+=alpha*classEst#print "aggClassEst: ",aggClassEst.TaggErrors=multiply(sign(aggClassEst)!=mat(classLabels).T,ones((m,1)))errorRate=aggErrors.sum()/mprint"total error: ",errorRateiferrorRate==0.0:breakreturnweakClassArr,aggClassEst#AdaBoost分类函数defadaClassify(datToClass,classifierArr):dataMatrix=mat(datToClass)#do stuff similar to last aggClassEst in adaBoostTrainDSm=shape(dataMatrix)[0]aggClassEst=mat(zeros((m,1)))foriinrange(len(classifierArr)):classEst=stumpClassify(dataMatrix,classifierArr[i]['dim'],\ classifierArr[i]['thresh'],\ classifierArr[i]['ineq'])#call stump classifyaggClassEst+=classifierArr[i]['alpha']*classEstprintaggClassEstreturnsign(aggClassEst)#画出ROC函数defplotROC(predStrengths,classLabels):importmatplotlib.pyplotasplt cur=(1.0,1.0)#cursorySum=0.0#variable to calculate AUCnumPosClas=sum(array(classLabels)==1.0)yStep=1/float(numPosClas);xStep=1/float(len(classLabels)-numPosClas)sortedIndicies=predStrengths.argsort()#get sorted index, it's reversefig=plt.figure()fig.clf()ax=plt.subplot(111)#loop through all the values, drawing a line segment at each pointforindexinsortedIndicies.tolist()[0]:ifclassLabels[index]==1.0:delX=0;delY=yStep;else:delX=xStep;delY=0;ySum+=cur[1]#draw line from cur to (cur[0]-delX,cur[1]-delY)ax.plot([cur[0],cur[0]-delX],[cur[1],cur[1]-delY],c='b')cur=(cur[0]-delX,cur[1]-delY)ax.plot([0,1],[0,1],'b--')plt.xlabel('False positive rate');plt.ylabel('True positive rate')plt.title('ROC curve for AdaBoost horse colic detection system')ax.axis([0,1,0,1])plt.show()print"the Area Under the Curve is: ",ySum*xStep好久没更新这个系列了,前阵子也是各种杂事,现在收心,好好学习啦O(∩_∩)O