机器学习实战笔记:集成学习

    集成学习分为两类:

  1. 个体学习器间存在强依赖关系,必须串行生成的序列方法:Boosting
  2. 个体学习器之间不存在强一赖关系,可同时生成的并行方法:Bagging和随机森林

    Boosting:

    先从初始训练集训练出一个基学习器,再根据基学习器的表现对训练样本分布进行调整(增加前一个基学习器在训练过程中预测错误的样本的权重)使先前基学习器做错的训练样本在后续学习中收到更多关注,尽可能纠正这些错误,然后基于调整后的样本分布来训练下一个基学习器;如此重复,直到基学习器数目达到T(人为设置),最终将这T个基学习器加权结合。

    AdaBoost算法:

     采用指数损失函数,yi∈{-1,+1},f是真实函数。

    AdaBoost的一般流程:

  1. 收集数据;
  2. 准备数据:依赖于所使用的弱分类器类型,这里我们采用的是单层决策树
  3. 分析数据;
  4. 训练算法:分类器将多次在同一数据集上训练弱分类器
  5. 测试算法:计算分类的错误率
  6. 使用算法;

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

    单层决策树:简单的决策树,仅基于单个特征来做决策,只有一侧分裂过程。故一般性数据集是无法通过 一个单层决策树正确分类的,必须使用多个单层决策树。

     首先构建如下的简单数据集

"""构建简单的数据集"""
def loadSimpData():
    datMat=matrix(
        [[1.0,2.1],
         [2.0,1.1],
         [1.3,1.0],
         [1.0,1.0],
         [2.0,1.0]]
    )
    classLabels=[1.0,1.0,-1.0,-1.0,1.0]
    return datMat,classLabels

    通过以下函数建立单层决策树:

    伪代码如下:

将minError设置为无穷大
对数据集中每一个特征:
    对每个步长:
        对每个不等号:
            建立一棵单层决策树并利用加权数据集对其进行测试
            if 错误率<minError:
                当前单层决策树设为最佳单层决策树
return 最佳单层决策树
    实际代码如下:
"""测试是否有某个值小于或大于我们正在测试的阈值"""
def stumpClassify(dataMatrix,dimen,threshVal,threshIneq):
    retArray=ones((shape(dataMatrix)[0],1))     #构建一个全1向量
    if threshIneq=='lt':   #小于阈值的分类为gt,大于阈值的分类为lt
        retArray[dataMatrix[:,dimen]<=threshVal]=-1.0   #<=阈值的置为-1
    else:
        retArray[dataMatrix[:, dimen] >threshVal] = -1.0  #>阈值的置为-1
    return retArray

"""遍历stumpClassify的所有可能输入值,并找到数据集上最佳的单层决策树"""
def buildStump(dataArr,classLabels,D):
    dataMatrix=mat(dataArr)
    labelMat=mat(classLabels).T
    m,n=shape(dataMatrix)  #m个样本,n个特征
    numSteps=10.0   #用于在特征的所有可能值上进行遍历
    bestStump={}    #定义一个字典,用于存储给定权重向量D时所得到的的最佳单层决策树的相关信息
    bestClasEst=mat(zeros((m,1)))
    minError=inf    #最小错误率,初始化为无穷大
    for i in range(n):  #在所有特征上遍历(第一次循环),即按照第i个特征来划分类别
        rangeMin=dataMatrix[:,i].min()   #找出所有样本中在特征i上的最小值
        rangeMax=dataMatrix[:,i].max()   #找出所有样本中在特征i上的最大值
        stepSize=(rangeMax-rangeMin)/numSteps  #确定步长(步长是用于比较特征值和阈值的)
        for j in range(-1,int(numSteps)+1):   #在特征i的所有可能取值上遍历,每次讲特征值加j*stepSize的大小(第二层循环)
            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  #如果预测和真实标签一致置为0,不一致置为1
                weightedError=D.T*errArr    #根据错误向量*权重向量得到数值weightedError
                if weightedError<minError:  #更新最小错误率
                    minError=weightedError
                    bestClasEst=predictedVals.copy()  #当前最好的分类预测向量
                    bestStump['dim']=i   #当前最好的分类特征
                    bestStump['thresh']=threshVal   #当前的分类阈值
                    bestStump['ineq']=inequal   #分类结果
    return bestStump,minError,bestClasEst



if __name__=='__main__':
    dataMatrix, classLabels = loadSimpData()
    D=mat(ones((5,1))/5)
    bestStump, minError, bestClasEst=buildStump(dataMatrix,classLabels,D)
    print("当前最好的分类方法(dim:选取的特征,thresh:阈值,ineq:分类名称):{}".format(bestStump))
    print("最小错误率:{}".format(minError))
    print("当前最好分类的预测值:{}".format(bestClasEst))

    测试输出如下:

    

    完整的AdaBoost学习器构建:

    利用上述代码构建的单层决策树来实现AdaBoost学习器,伪代码如下:

对每次迭代:  
    利用buildStump()找到最佳的单层决策树
    将最佳单层决策树加入到单层决策树数组
    计算alpha
    计算新的权重向量D
    更新累计类别估计值
    如果错误率等于0.0,退出循环

    其中:

  1. D:训练数据中的每个样本拥有一个权重,这些权重构成向量D,初始时所有权重相等,分类错的样本下一次分类时权重增加,分类正确的权重在下次分类时会降低
  2. AdaBoost为每个分类器分配一个权重alpha,alpha基于每个弱分类器的错误率进行计算:    

                                错误率ε=为正确分类的样本数目/所有样本数目

                                alpha=1/2ln(1-ε/ε)

        某个样本被正确分类,该样本权重更改为:Di(t+1)=Di(t)*e^-alpha/sum(D)

        某个样本被错误分类,该样本权重更改为:Di(t+1)=Di(t)*e^alpha/sum(D)

        计算出新的D之后,AdaBoost开始进入下一轮迭代。

        AdaBoost的训练就是训练出若干弱分类器以及这些弱分类器相应的权重。               

"""基于单层决策树的AdaBoost训练过程"""
def adaBoostTrainDS(dataArr,classLabels,numIt=40):   #数据集,类别标签以及迭代次数(若小于迭代次数时错误率已经为0则直接退出)
    weakClassArr=[]  #弱分类器列表
    m=shape(dataArr)[0]  #m为样本数
    D=mat(ones((m,1))/m)  #初始化每个样本的权值,初始化所有权重均为1/m
    aggClassEst=mat(zeros((m,1)))   #向量aggClassEst,记录每个数据点的类别估计累计值
    for i in range(numIt):   #迭代
        bestStump,error,classEst=buildStump(dataArr,classLabels,D)  #建立一个当前性能最优的单层决策树
        weakClassArr.append(bestStump)     #将当前选出的决策树信息存入列表
        print("各样本权值向量D为:{}".format(D.T))   #打印此时的各样本权重
        alpha=float(0.5*log((1.0-error)/max(error,1e-16)))    #计算alpha
        bestStump['alpha']=alpha   #将测试的alpha加入单层决策树信息中
        weakClassArr.append(bestStump)
        print("分类预测结果向量classEst:{}".format(classEst.T))
        #以下三步均为更新D的步骤
        expon=multiply(-1*alpha*mat(classLabels).T,classEst)    
        D=multiply(D,exp(expon))
        D=D/D.sum()
        aggClassEst+=alpha*classEst
        print("aggClassEst:{}".format(aggClassEst.T))
        aggErrors=multiply(sign(aggClassEst)!=mat(classLabels).T,ones((m,1)))  #通过aggClassEst来计算总的错误率
        errorRate=aggErrors.sum()/m
        print("总错误率:{}".format(errorRate))
        if errorRate==0.0:   #当总的错误率为0.0时退出迭代
            break
    return weakClassArr

        根据弱分类器和权重进行样本分类:

"""基于AdaBoost的分类函数"""
def adaClassify(datToClass,classifierArr):   #datToClass为待分类样本,classifierArr是训练出来的弱分类器集合
    dataMatrix=mat(datToClass)
    m=shape(dataMatrix)[0]   #要分类的样本数
    aggClassEst=mat(zeros((m,1)))
    for i in range(len(classifierArr)):   #遍历所有的弱分类器,通过stumpClassify对每个分类器得到一个类别的估计值
        classEst=stumpClassify(dataMatrix,classifierArr[i]['dim'],classifierArr[i]['thresh'],classifierArr[i]['ineq'])
        aggClassEst+=classifierArr[i]['alpha']*classEst  #然后得到各弱分类器的加权和,就是预测值
        print(aggClassEst)
    return sign(aggClassEst)

        样本[0,0]和[5,5]分类测试结果如下:

if __name__=='__main__':
    dataMatrix, classLabels = loadSimpData()
    classifierArr=adaBoostTrainDS(dataMatrix,classLabels,30)
    result=adaClassify([[0,0],[5,5]],classifierArr)

                                

猜你喜欢

转载自blog.csdn.net/qq_29599907/article/details/80565615
今日推荐