参考《机器学习实战》,代码可运行
#!/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, labelMatif __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]的类别
以上,祝好!
作者:Huang_Cong
链接:https://www.jianshu.com/p/15029613c19f