python机器学习实战:Adaboost

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的工作原理如图:

python机器学习实战:Adaboost_第1张图片



首先我们需要创建一个单层决策数分类器:

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={}#保存最佳分类器
    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

上面有两个函数,这两个函数的功能就是构建一个最佳的决策树分类器。为下面的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)

运行的结果为:

python机器学习实战:Adaboost_第2张图片

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

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

每次迭代:

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

其中权重的更新算法为:

python机器学习实战:Adaboost_第3张图片



 代码如下:

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分类器,哎呀,终于写完了,说实话,在下对机器学习的理解也还有限,如果有错误的地方还请大家指出。











你可能感兴趣的:(python,机器学习实战)