#encoding=utf-8 __author__ = 'freedom' from numpy import * def LoadData(): 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 def StumnpClassify(dataMatrix,dimen,threshVal,threshIneq): ''' 本函数用于进行最简单分类 :param dataMatrix: 数据集,要求是矩阵形式 :param dimen: 选中的特征,以此特征进行划分 :param threshVal: 选取划分的阈值 :param threshIneq: 选取划分的不等式符号 :return:分类的结果,数组形式 ''' retArray = ones((shape(dataMatrix)[0],1)) #生成返回数组,维度为(样例数*1) if threshIneq == 'lt': #选取的不等式为小于等于 retArray[dataMatrix[:,dimen] <= threshVal] = -1.0 #将所有小于等于阈值的值全部表位-1.0 else: retArray[dataMatrix[:,dimen] > threshVal] = -1.0 return retArray def BuildStump(dataArr,labels,D): ''' 本函数用于产生一个简单的树桩分类器 :param dataArr: 数据集。要求不一定为矩阵形式 :param labels: 标签集,要求不一定为矩阵形式 :param D: 权重 :return:最优分类器,字典形式,包含最佳分类特征、阈值和不等式形式,最小误差和最优分类结果 ''' dataMat = mat(dataArr) labelMat = mat(labels).T #本函数中所有数据均要矩阵化,方便之后的比较工作 m,n = shape(dataMat) numSteps = 10.0 #迭代次数 bestStump = {} bestClassEst = mat(zeros((m,1))) minError = inf for i in range(n): #本层循环是遍历所有的特征,选取误差最小的作为分类器 rangeMin = dataMat[:,i].min() rangeMax = dataMat[:,i].max() stepSize = (rangeMax - rangeMin)/numSteps #迭代的阈值初始化 for j in range(-1,int(numSteps)+1): #遍历所有离散的阈值 for inequal in ['lt','gt']: #遍历两种不等式形式 threshVal = rangeMin+float(j)*stepSize predictVal = StumnpClassify(dataMat,i,threshVal,inequal) #获得分类结果 errArr = mat(ones((m,1))) errArr[predictVal == labelMat] = 0 #获得分类误差列向量,如果与标签不同,该项值为1 weightError = D.T*errArr #加权计算误差,获得的值是一个数,分类正确的数据权重减小,分类错误的数据权重增加,但是在某次寻找最优单分类器时D是保持不变的 if weightError <= minError: minError = weightError #更新误差 bestClassEst = predictVal.copy() #复制分类结果 bestStump['dim'] = i #记录下最佳分类器的三个参数 bestStump['threshVal'] = threshVal bestStump['ineq'] = inequal return bestStump,minError,bestClassEst def AdaBoostTrainDS(dataArr,labels,numIt = 40): ''' 本函数用于AdaBoost学习 :param dataArr: 数据集,不要求为矩阵形式 :param labels: 标签集,不要求为矩阵形式 :param numIt: 迭代次数,可自由设定,默认为40 :return:所有弱分类器,列表形式,嵌套有所有弱分类器,字典形式,包含有有划分特征、阈值、不等式形式和alpha值四个参数 ''' weakClassArr = [] m = shape(dataArr)[0] D = mat(ones((m,1))/m) # 初始化权重,平均分为m份,m为样例数,目的是对分类错误的样例加大权重,详见BuildStump函数 aggClasssEst = mat(zeros((m,1))) for i in range(numIt): #迭代 bestStump,error,classEst = BuildStump(dataArr,labels,D) # 获得弱分类器、分类误差和分类结果 alpha = float(0.5*log((1.0-error)/max(error,1e-16))) # 计算alpha,这里1e-16是为了保证不会出现除零错误 bestStump['alpha'] = alpha # 这里的alpha值就是该弱分类器的权重 weakClassArr.append(bestStump) # 将弱分类器加入列表 expon = (multiply(-1*alpha*mat(labels).T,classEst)) # 更新权重,对于分类错误的要加大权重,分类正确的减小权重#注意,这里multiply应该是列向量的元素对应相乘 #print D D = multiply(D,exp(expon)) D = D/D.sum() aggClasssEst += alpha*classEst #计算叠加了当前弱分类器后的分类结果 aggError = multiply(sign(aggClasssEst)!= mat(labels).T,ones((m,1))) #计算叠加当前分类器后的误差 errorRate = aggError.sum()/m #计算误差率 #print 'Error is ',errorRate,'\n' if errorRate == 0.0:break #如果误差率为0,则提前结束迭代循环 return weakClassArr def AdaClassify(dataSet,classifer): ''' 本函数用于分类 :param dataSet: 数据集,不要求为矩阵形式 :param classifer: 分类器,字典形式,应该是多个弱分类器的组合 :return:类型 ''' dataMat = mat(dataSet) #数据集矩阵化 m = shape(dataMat)[0] aggClassEst = mat(zeros((m,1))) for i in range(len(classifer)): #遍历所有的分类器 ClassEst = StumnpClassify(dataMat,classifer[i]['dim'],classifer[i]['threshVal'],classifer[i]['ineq']) #应用每一个弱分类器分类 aggClassEst += classifer[i]['alpha']*ClassEst#对每个弱分类器的结果加权求和 #print aggClassEst return sign(aggClassEst) def LoadBigData(filename): ''' 本函数用于加载大量数据 :param filename: 数据文件名 :return:数据集和标签集,均为列表形式 ''' numFeat = len(open(filename).readline().split('\t')) #获得特征数目 dataSet = [] labels = [] 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])) #读出的是字符串,要转换为浮点型 dataSet.append(lineArr) labels.append(float(curLine[-1])) return dataSet,labels trainData,trainLabels =LoadBigData('train.txt') testData,testLabels = LoadBigData('test.txt') classifer = AdaBoostTrainDS(trainData,trainLabels,60)# 用数据集进行训练 predictValue = AdaClassify(testData,classifer) # 用测试数据观察分类 numTest = len(testLabels) # 获取测试数据数目 for i in range(len(predictValue)): # 比对预测数值和真实数值 if predictValue[i] == testLabels[i]: print 'YES!' else: print 'No!' errArr = mat(ones((numTest,1))) errRate = errArr[predictValue != mat(testLabels).T].sum()/numTest #求误差率 print errRate ''' d,l = LoadData() AdaBoostTrainDS(d,l,numIt=40) '''