Adaboost底层代码(python)——非常详细

作者: 3975977c74f4 | 来源:发表于2018-10-21 12:10 被阅读8次

    参考《机器学习实战》,代码可运行

    #!/user/bin/python3
    # Author: HuangCong
    # -*- coding:utf-8 -*-
    import numpy as np
    
    #建立简单数据集
    def loadSimpData():
        datMat = np.mat([[1., 2.1],
                         [2., 1.1],
                         [1.3, 1.],
                         [1., 1.],
                         [2., 1.]])
        classLabel = [1.0, 1.0, -1.0, -1.0, 1.0]
        return datMat, classLabel
    
    
    #通过阈值比较对数据进行分类——(特征矩阵、维度、阈值、阈值不等号)
    def stumpClassify(dataMatrix, dimen, threshVal, threshIneq):
        retArray = np.ones((dataMatrix.shape[0], 1))  #建立列向量[m, 1]——与标签列相对应
        if threshIneq == 'lt':
            retArray[dataMatrix[:, dimen] <= threshVal] = -1  #在该dimen维度的特征值小于等于阈值时,取-1
        else:
            retArray[dataMatrix[:, dimen] > threshVal] = -1
        return retArray
    
    
    #该函数会遍历stumpClassify()函数所有可能的输入值,并找到该数据集上的最佳单层树——根据数据权重向量D来定义
    def buildStump(dataArr, classLabels, D):
        dataMatrix = np.mat(dataArr); labelMat = np.mat(classLabels).T #classLabel向量为[1,n],需要转置
        m, n = dataMatrix.shape  #m个样本,n个特征
        numSteps = 10.0  #用于在特征的所有可能值上进行遍历
        bestStump = {} #该词典保存最佳单层决策树的相应参数
        bestClasEst = np.mat(np.zeros((m, 1)))    #保存最佳估计标签值,先初始化[m,1]零向量
        minError = np.inf  #初始化为无穷大,用于寻找可能的最小错误率
        for i in range(n):  #在所有的特征上进行遍历
            rangeMin = dataMatrix[:, i].min()  #取该列特征值中的最小值
            rangeMax = dataMatrix[:, i].max()  #同理以上
            stepSize = (rangeMax - rangeMin)/numSteps  #确定步长
            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)))   #错误矩阵,如果predictedVals值不等于labelMat中真正类别值,置为一
                    errArr[predictdVals == labelMat] = 0
                    weightedError = D.T * errArr  #权重向量与错误向量相乘得到错误率
                    #适当打印,帮助理解函数的运行
                    #print("split: dim %d, thresh %.2f, thresh ineqal: %s, the weighted error is %.3f"% (i, threshVal, inequal, weightedError))
                    if weightedError < minError:  #当前错误率小于已有的最小错误率
                        minError = weightedError  #进行更新
                        bestClasEst = predictdVals.copy()  #保存预测值
                        bestStump['dim'] = i  #保存维度
                        bestStump['thresh'] = threshVal  #保存阈值
                        bestStump['ineq'] = inequal  #保存不等号
        return bestStump, minError, bestClasEst
    
    
    #基于单层决策树的AdaBoost的训练过程 (数据集、类别标签、迭代次数),尾部DS代表(decision stump单层决策树)
    def adaBoostTrainDS(dataArr, classLabels, numIt=40):  #迭代次数是算法中唯一需要用户指定的参数
        weakClassArr = []   #聚焦该分类器的所有信息,最后返回
        m = dataArr.shape[0]  #样本数为m
        D = np.mat(np.ones((m, 1)) / m)  #样本权重初始化,都相等,后续迭代中会增加错分数据的权重同时,降低正确分类数据的权重
        aggClassEst = np.mat(np.zeros((m, 1)))  #记录每个数据点的类别估计累计值
        for i in range(numIt):  #numIt次迭代
            bestStump, error, classEst = buildStump(dataArr, classLabels, D)
            #上一行返回利用D得到的具有最小错误率的单层决策树,同时返回最小错误率和估计的类别向量
            print("D:", D.T)
            #下一行alpha的计算公式可详见李航蓝本,max()函数以防发生除零错误
            alpha = float(0.5 * np.log((1.0 - error) / max(error, 1e-16)))
            bestStump['alpha'] = alpha  #继续存入该字典——包括了分类所需要的所有信息
            weakClassArr.append(bestStump)   #保存信息到列表中
            print("classEst: ", classEst.T) #打印类别估计值
            #以下三行用于计算下一次迭代中的新的数据权重向量D,公式可见李航蓝本
            expon = np.multiply(-1 * alpha * np.mat(classLabels).T, classEst)
            D = np.multiply(D, np.exp(expon))
            D = D/D.sum()
            #以下四行用于错误率累加的计算,通过aggClassEst变量保持一个运行时的类别估计值来实现
            aggClassEst += alpha * classEst
            print("aggClassEst: ", aggClassEst)  #由于aggClassEst是浮点数,需要调用sign()函数
            aggErrors = np.multiply(np.sign(aggClassEst) != np.mat(classLabels).T, np.ones((m, 1)))
            errorRate = aggErrors.sum() / m
    
            print("errorRate: ", errorRate)
            if errorRate == 0.0:  #如果错误率为0,停止for循环
                break
        return weakClassArr  #返回信息列表
    
    
    #基于adaboost进行分类——(待分类样例,多个弱分类器组成的数组)
    def adaClassify(dataToClass, classifierArr):
        dataMatrix = np.mat(dataToClass)  #首先转成numpy矩阵
        m = dataMatrix.shape[0] #待分类样例的个数为m
        aggClassEst = np.mat(np.zeros((m, 1)))  #构建0列向量,与adaBoostTrainDS中含义一样
        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 np.sign(aggClassEst)
    
    
    # #定义自适应加载函数(很有用)
    # def loadDataSet(fileName):
    #     numFeat = len(open(fileName).readline().split('\t'))
    #     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
    
    
    if __name__ == "__main__":
        dataMat, classLabels = loadSimpData()
        classifierArr = adaBoostTrainDS(dataMat, classLabels, 30)
        print(adaClassify([0, 0], classifierArr))  #估计数据点[0,0]的类别
        print(adaClassify([[5, 5], [0, 0]], classifierArr))  #估计数据点[5,5],[0,0]的类别
    

    以上,祝好!

    相关文章

      网友评论

        本文标题:Adaboost底层代码(python)——非常详细

        本文链接:https://www.haomeiwen.com/subject/ishbzftx.html