AdaBoost分类器

来源:互联网 发布:如何提升淘宝店铺排名 编辑:程序博客网 时间:2024/06/06 19:15

本博客是基于《机器学习实战》中第七章的基础上加上个人理解所做的笔记,其中python程序的注释也是个人的理解,可能有不正确的地方,仅供参考。
环境:win7 64位 python3.5

0、概述

当做重要决定时,大家可能都会考虑吸取多个专家而不只是一个人的意见。机器学习处理问题时又何尝不是如此?这就是元算法(meta-algorithm ) 背后的思路。元算法是对其他算法进行组合的一种方式,即可以将不同的分类器组合起来,这种组合的结果也叫集成方法。其中AdaBoost被称为最流行的元算法。由于某些人认为AdaBoost是最好的监督学习的方法,所以该方法是机器学习工具箱中最强有力的工具之一。

1、bagging与boosting

bagging:自举汇聚(boostrap aggregating),也称为bagging方法,是在从原始数据集选择S次后得到S个新数据集的一种技术。新数据集和原数据集的大小相等。每一个数据集都是由有放回抽样取得的数据集。这样在S个数据集建好之后,将某个学习算法分别作用于每个数据集就得到了S个分类器。每一个分类器都有一个分类的结果,所以在S个分类器的结果中采取投票机制,即多数原则,来确定此次的分类结果。随机森林就是其中之一。

boosting: boosting是一种与bagging很类似的技术。不论是在boosting还是bagging当中,所使用的多个分类器的类型都是一致的。但是在boosting当中,不同的分类器是通过串行训练而获得的,每个新分类器都根据已训练出的分类器的性能来进行训练。boosting是通过集中关注被已有分类器错分的那些数据来获得新的分类器。

由于boosting分类的结果是基于所有分类器的加权求和结果的,因此boosting与bagging不太一样 。bagging中的分类器权重是相等的,而boosting中的分类器权重并不相等,每个权重代表的是其对应分类器在上一轮迭代中的成功度。
boosting方法拥有多个版本,AdaBoost是其最流行版本之一。

2、AdaBoost原理简述

弱分类器:比随机猜测要稍微好,但不会好太多。在二分类情况下,弱分类器的错误率高于50%。

AdaBoost是adaptive boosting(自适应boosting)的缩写,其运行过程如下:训练数据中的每个样本,并赋予其一个权重,这些权重构成了向量D。一开始,这些权重都初始化成相等值。首先在训练数据上训练出一个弱分类器并计算该分类器的错误率,然后在同一数据集上再次训练弱分类器。在分类器的第二次训练当中,将会重新调整每个样本的权重,其中第一次分对的样本的权重将会降低,而第一次分错的样本的权重将会提高。为了从所有弱分类器中得到最终的分类结果 ,AdaBoost为每个分类器都分配了一个权重值alpha,这些alpha值是基于每个弱分类器的错误率进行计算的。其中,错误率的定义为:
这里写图片描述
而alpha的计算公式如下:
这里写图片描述
现在分析alpha的公式,由于误差率delta是大于0.5小于1的数值,所以当delta增大时,alpha也是增大的,也就是说一个弱分类器的错误率越大,其获得的权重也是越大的,这就意味着在训练的时候,分类器会更加注重这些错误率比较大的弱分类器。
AdaBoost^% 的流程如图所示。
这里写图片描述
从图中可以看出,n个加了权重的弱分类器累加,便得到一个强分类器。
计算出alpha值之后,可以对权重向量D进行更新,以使得那些正确分类的样本的权重降低而错分样本的权重升高。D的计算方法如下。
如果某个样本被正确分类,那么该样本的权重更改为:
这里写图片描述
而如果某个样本被错分,那么该样本的权重更改为:
这里写图片描述
在计算出D之后,Adaboost对又开始进入下一轮迭代。AdaBoost算法会不断地重复训练和调整权重的过程,直到训练错误率为0或者弱分类器的数目达到用户的指定值为止。
说明:《机器学习实战》在这里对样本权重D的解释与其他的书籍的解释不太一样,其他的解释可以参考博客:http://blog.csdn.net/guyuealian/article/details/70995333
这篇博客写的通俗易懂,非常好。

3、python实现

import numpy as npimport mathdef loadsimpData():    dataMat = np.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 dataMat,classLabelsdef loadDataSet(fileName):      #general function to parse tab -delimited floats    numFeat = len(open(fileName).readline().split('\t')) #get number of fields     dataMat = []; labelMat = []    fr = open(fileName)    for line in fr.readlines():        lineArr =[]        curLine = line.strip().split('\t')        for i in range(numFeat-1):            lineArr.append(float(curLine[i]))        dataMat.append(lineArr)        labelMat.append(float(curLine[-1]))    return dataMat,labelMat# 将数据分类"""根据某个值是否大于或小于某个阈值进行判断参数:    dataMatrix : 数据集矩阵    dimen : 要判断的特征值即为列    threshVal : 阈值    threshIneq : 大于或小于 ['lt', 'gt']"""def stumpClassify(dataMatrix,dimen,threshVal,threshIneq):    retArray = np.ones((np.shape(dataMatrix)[0],1))  # 初始化为 m行1列的值为1 的矩阵    if threshIneq == 'lt':  # less than        retArray[dataMatrix[:,dimen] <= threshVal] = -1.0    else:        retArray[dataMatrix[:,dimen] > threshVal] = -1.0    return retArray"""在一个加权数据集中循环,并找到具有最低错误率的单层决策树。伪代码如下:将最小错误率minError设为+00对数据集中的每一个特征(第一层循环):    对每个步长(第二层循环):        对每个不等号(第三层循环):            建立一棵单层决策树并利用加权数据集对它进行测试            如果错误率低于minError,则将当前单层决策树设为最佳单层决策树返回最佳单雇决策树该函数的功能就是找出错误率最小的决策树,并记录跟决策有关的信息,并没有对权重向量进行改变,所有一开始要假设所有的数据样本的权重一样参数:    dataArr : 数据集    classLabels : 分类标签值    D : 权重向量"""def buildStump(dataArr,classLabels,D):    dataMatrix = np.mat(dataArr)    labelMat = np.mat(classLabels).T    m,n = np.shape(dataMatrix)  # 返回数据集行、列    numSteps = 10.0    bestStump = {}  # 一个空的字典    bestClassEst = np.mat(np.zeros((m,1)))  # m行1列的零矩阵    minError = np.inf    for i in range(n):   #遍历列(特征值)为的是找出单层决策树        rangeMin = dataMatrix[:,i].min()  # 找出第i列的最小值        rangeMax = dataMatrix[:,i].max()   # 找出第i列的最大值        stepSize = (rangeMax - rangeMin)/numSteps  # 计算出极差,并以10为间隔分段        for j in range(-1,int(numSteps)+1): # 遍历每一个分段            for inequal in ['lt','gt']:                threshVal = (rangeMin + float(j)*stepSize)  # 阈值                predictdVals = stumpClassify(dataMatrix,i,threshVal,inequal)                errArr = np.mat(np.ones((m,1)))  # m行1列 用来保存预测的结果                errArr[predictdVals == labelMat] = 0  # 如果与标签值一样,为正确,标0                weightedError = D.T*errArr  # 得到新的权重向量                if weightedError < minError:  # 说明这次的错误比上一次低                    minError = weightedError                    bestClassEst = predictdVals.copy()  # 记录下这一次的预测值                    bestStump['dim'] = i   # 记录这次的列 即特征值                    bestStump['thresh'] = threshVal  # 记录阈值                    bestStump['ineq'] = inequal    return bestStump,minError,bestClassEst"""参数:    dataArr : 数据集    classLabels : 标签值    numIt : 迭代次数如果设置迭代的次数为9,但实际上迭代了3次的错误率就为0了,那就退出迭代"""def adaBoostTrainDS(dataArr,classLabels,numIt=40):    weakClassArr = []    m = np.shape(dataArr)[0]    # D 是一个概率分布向量,除以m是为了保障,每一个分量都相等且和为1    D = np.mat(np.ones((m,1))/m)   # 初始化权重向量    aggClassEst = np.mat(np.zeros((m,1)))  # 记录每个数据点的类别估计累计值    for i in range(numIt): # 遍历迭代        # 建立单层决策树,返回最小错误率以及估计的类别向量        bestStump,error,classEst = buildStump(dataArr,classLabels,D)        alpha = float(0.5*np.log((1.0-error)/max(error,1e-16)))# 本次单层决策树输出结果的权重        bestStump['alpha'] = alpha        # 存储每一层最佳决策树的决策信息        weakClassArr.append(bestStump)        """        由于样本被正确分类权重D乘以一个以e为底的负系数,错误分类样本乘以正系数。        且预测值与标签值都是用-1,和1表示,如果正确双方成绩同号,错误双方成绩为负        所以考虑将两个分类的问题的两个公式使用一个公式来表示,那么两个的成绩是最好的了。        """         expon = np.multiply(-1*alpha*np.mat(classLabels).T,classEst)        D = np.multiply(D,np.exp(expon))                                    D = D/D.sum()  # 不同书籍上的表达不一样。        """        通过aggClasSESt 变量保持一个运行时的类别估计值来实现的.该值只是一个浮点数,        为了得到二值分类结果还需要调用sign()函数。如果总错误率为0 ,则由break中止        sign(n)            取数字n的符号,大于0返回1,小于0返回-1,等于0返回0        """        # 强分类器等于每一次弱分类器乘以权重之和        aggClassEst += alpha*classEst        aggErrors = np.multiply(np.sign(aggClassEst) != np.mat(classLabels).T,np.ones((m,1)))        errorRate = aggErrors.sum()/m        print("total error: ",errorRate)        if errorRate == 0.0: break    return weakClassArr,aggClassEst"""需要做的就只是将弱分类器的训练过程从程序中抽出来,然后应用到某个具体的实例上去。每个弱分类器的结果以其对应的alpha值作为权重。所有这些弱分类器的结果加权求和就得到了最后的结果。参数:    datToClass : 一个或者多个待分类样例    classifierArr : 个弱分类器组成的数组"""def adaClassify(datToClass,classifierArr):    dataMatrix = np.mat(datToClass)  # 转换成numpy矩阵    m = np.shape(dataMatrix)[0]  # 取出带分类的样例数    aggClassEst = np.mat(np.zeros((m,1)))  # 初始化用于存放alpha的矩阵    for i in range(len(classifierArr)):  # 遍历classifierArr中的所有弱分类器        # 根据阈值分类,单层决策树        classEst = stumpClassify(dataMatrix,classifierArr[i]['dim'],                                classifierArr[i]['thresh'],                                classifierArr[i]['ineq'])        # alpha加权每一次单层分类器并累加        aggClassEst += classifierArr[i]['alpha']*classEst        print(aggClassEst)    return sign(aggClassEst)  # 返回强分类器
原创粉丝点击