大数据,机器学习,人工智能机器学习和人工智能入门机器学习与数据挖掘

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

2018-10-21  本文已影响8人  3975977c74f4

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

#!/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]的类别

以上,祝好!

上一篇下一篇

猜你喜欢

热点阅读