• 《机器学习实战第7章:利用AdaBoost元算法提高分类性能》


    import numpy as np
    import matplotlib.pyplot as plt
    def loadSimpData():
    	dataMat = np.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 dataMat, classLabels
    
    def showDataSet(dataMat, label):
    	"""
    	数据可视化
    	Parameters:
    		dataMat - 数据矩阵
    		label - 数据标签
    	Returns:
    	    无
    	"""
    	
    	# 方法一 via CHJ
    	data = np.array(dataMat)
    	#print(data)
    	for i in range(len(data)):
    		if label[i] == 1.0:
    			#用plt.scatter画散点图也行
    			plt.plot(data[i][0], data[i][1], marker = 'o', color = 'red')
    		else:
    			plt.plot(data[i][0], data[i][1],  marker = 's',color = 'blue')
    
    	plt.show()
    
    	# # 方法二	
    	# data_plus = [] #正样本
    	# data_mins = [] #负样本
    	# for i in range(len(dataMat)):
    	# 	if label[i] > 0:
    	# 		data_plus.append(dataMat[i])
    	# 	else:
    	# 		data_mins.append(dataMat[i])
    
    	# data_plus_np = np.array(data_plus)  #转换成numpy矩阵  #[[[1.  2.1]], [[2.  1.1]], [[2.  1. ]]]
    	# data_mins_np = np.array(data_mins)  #转换成numpy矩阵  #[[[1.3 1. ]], [[1.  1. ]]]
    	# #需要转置,否则绘图不正确
    	# x = np.transpose(data_plus_np)  # [[[1.  2.  2. ]], [[2.1 1.1 1. ]]]
    	# y = np.transpose(data_mins_np)  # [[[1.3 1. ]], [[1.  1. ]]]
    	# plt.scatter(x[0], x[1])  # 正样本散点图
    	# plt.scatter(y[0], y[1])  # 负样本散点图
    	# plt.show()
    
    
    print("------------7.4节:基于单层决策树构建分类器-----------------------")
    
    def stumpClassify(dataMatrix, dimen, threshVal, threshIneq):
    	"""
    	(将数据集,按照feature列的value进行 二分法切分比较来赋值分类)
    	单层决策树分类函数
    	Parameters:
    	    dataMatrix - 数据矩阵
    	    dimen - 第dimen列,也就是第几列特征
    	    threshVal - 阈值(特征列要比较的值)
    	    threshIneq - 阈值不等式(这里有两个:lt和gt)
    	Returns:
    	    retArray - 分类结果(np.array类型)
    	"""
    	retArray = np.ones((np.shape(dataMatrix)[0], 1))  # 生成m 行1列的单位矩阵
    	# thresh_ineq == 'lt'表示阈值不等式取lt(less than)
    	if threshIneq == 'lt':
    		# data_mat[:, dimen] 表示数据集中第dimen列的所有值
    		retArray[dataMatrix[:, dimen] <= threshVal] = -1.0   # 如果小于等于阈值,则赋值为-1
    
    
    	else:  # 表示阈值不等式取gt(great than)
    		retArray[dataMatrix[:, dimen] > threshVal] = -1.0	 # 如果大于阈值,则赋值为-1
    
    	return retArray
    
    def buildStump(dataArr, classLabels, D):
    
    	"""
        找到数据集上的最佳单层决策树 -- 单层决策树是指只考虑其中的一个特征,在该特征的基础上进行分类,
        寻找分类错误率最低的阈值即可, 非常简单
        例如本文例子中,如果以第一列特征(dimen = 1)为基础,阈值v选择1.3,并且设置lt:<=1.3的为-1,< 1.3的为+1; gt: <1.3的为+1,<= 1.3的为-1, 
        这样就构造出了一个二分类器
    	Parameters:
    	    dataArr - 数据矩阵
    	    classLabels - 数据标签
    	    D - 样本权重
    	Returns:
    	    bestStump - 最佳单层决策树信息
    	    minError - 最小误差
    	    bestClassEst - 最佳的分类结果   
    	"""
    
    	dataMatrix = np.mat(dataArr)
    	labelMat = np.mat(classLabels).T
    	m, n = np.shape(dataMatrix)   # m行n列
    	
    	
         # numSteps用于在特征的所有可能值上进行遍历
    	numSteps = 10.0
    	bestStump = {}
    	bestClassEst = np.mat(np.zeros((m, 1)))  
    	minError = float('inf')   # np.inf    # 最小误差初始化为正无穷大
        # 第一层循环:对n列特征进行遍历(如本例中,n =2 )
    	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):
    	    	'''
    			lt(less than)是指在该阈值下,如果<阈值,则分类为-1
    			gt(greater than)是指在该阈值下,如果>阈值,则分类为-1
    			就这个题目来说,两者加起来误差肯定为1
    			'''
                #第三层循环是在大于和小于之间切换不等式
    	    	for inequal in ['lt', 'gt']:  # 遍历小于和大于的情况。
        			threshVal = (rangeMin + float(j) * stepSize)   # 计算阈值
        			predictedVals = stumpClassify(dataMatrix, i , threshVal, inequal) # 计算分类结果
        			errArr = np.mat(np.ones((m,1)))   # 初始化误差矩阵
        			
        			errArr[predictedVals == labelMat] = 0  # 分类正确的,赋值为0
        			# 基于权重向量D而不是其他错误指标来评价分类器的,不同的分类器计算方法不一样
        			weightedError = D.T * errArr # 计算误差--这里没有采用常规方法来评价这个分类器的分类准确率,而是乘上了权重
        			# print('split: dim %d, thresh %.2f, thresh inequal: %s, the weighted error is %.3f' 
        			# 	%(i, threshVal, inequal, weightedError))
        			if weightedError < minError:
        				minError = weightedError
        				bestClassEst = predictedVals.copy()
        				bestStump['dim'] = i
        				bestStump['thresh'] = threshVal
        				bestStump['ineq'] = inequal
    
    
    	return bestStump, minError,bestClassEst
    
    
    print("----------7.4:完整AdaBoost算法的实现----------------------")
    def adaBoostTrainDS(dataArr, classLabels, numIt= 40):
    	"""
    	使用AdaBoost算法提升分类器性能
    	Parameters:
    	    dataArr - 数据矩阵
    	    classLabels - 数据标签
    	    numIt - 最大迭代次数
    	Returns:
    		weakClassArr - 训练好的分类器
    		aggClassEst - 类别估计累计值
    	"""
    	weakClassArr = []
    	m = np.shape(dataArr)[0]
    	D = np.mat(np.ones((m,1))/m)  # 初始化权重
    	aggClassEst = np.mat(np.zeros((m,1)))
    
    	for i in range(numIt):  # 迭代次数
    		# 得到决策树的模型
    		bestStump, error, classEst = buildStump(dataArr, classLabels, D)  #构建单个单层决策树
    		# print("D: ", D.T)
    		# 计算弱学习算法的权重alpha,使error不等于0,因为分母不能为0
    		# alpha 目的主要是计算每一个分类器实例的权重(加和就是分类结果)
    		# 计算每个分类器的 alpha 权重值
    		alpha = float(0.5 * np.log((1.0 - error) / max(error, 1e-16)))
    
    		bestStump['alpha'] = alpha  # 存储若学习算法的权重  # store Stump Params in Array
    		
    		weakClassArr.append(bestStump)  # 存储单层决策树
    		#print("classEst = ", classEst.T)
    		expon = np.multiply(-1 * alpha * np.mat(classLabels).T, classEst)
    		# print("expon = ", expon.T)
    		D = np.multiply(D, np.exp(expon)) 
    		# print("权重分布D = ", D.T)  
    		D = D / D.sum() # 根据样本权重公式,更新样本权重
    		# print("更新后权重分布D = ", D.T)  # 使D成为一个概率分布
    
    		#计算AdaBoost的误差,当误差errorRate为0时,退出循环
    		# 计算所有类别估计累计值--注意 这里包括了目前已经训练好的每一个弱分类器
    		aggClassEst = aggClassEst + alpha * classEst
    		#print("aggClassEst: ", aggClassEst.T)
    
    		#计算分类器集成后的错误矩阵,错误设置为1,便于后续计算
    		aggErrors = np.multiply(np.sign(aggClassEst) != np.mat(classLabels).T, np.ones((m, 1)))  #目前的集成分类器,分类错误
    		# print("aggErrors = 
    ", aggErrors)
    		errorRate = aggErrors.sum() / m  
    		# errorRate:集成分类器分类错误率(平均),如果错误率为0,则整个集成算法停止,训练完成
    		#print("total error: ", errorRate)
    		print("集成第%s个弱分类器后的错误率ε = %.3f" %(i, errorRate))
    		# 如错误率为0,此时分类器以达最佳,循环终止
    		if errorRate == 0.0:
    			break
    
    	return weakClassArr, aggClassEst
    
    def adaClassify(datToClass, classifierArr):
    	"""
    	Parameters:
    		datToClass - 待分类样例
    		classifierArr - 训练好的分类器
    	Returns:
    		分类结果
    	"""
    
    	dataMatrix = np.mat(datToClass)
    	m = np.shape(dataMatrix)[0]
    	aggClassEst = np.mat(np.zeros((m,1)))
    	for i in range(len(classifierArr)):   # 遍历所有的分类器,进行分类
    		classEst = stumpClassify(dataMatrix, classifierArr[i]['dim'], classifierArr[i]['thresh'], classifierArr[i]['ineq'])
    		aggClassEst += classifierArr[i]['alpha'] * classEst
    		print(aggClassEst)  
    
    	return np.sign(aggClassEst)
    
    
    ##########################7.6 示例: 在一个难数据集上应用AdaBoost##########################
    def loadDataSet(fileName):
    	numFeat = len(open(fileName).readline().split('	'))  #获得特征(包括类别标签列)的个数
    	# print("特征的个数: ", numFeat)  # 输出22个(包括类别标签列)
    	dataMat = [] ; labelMat = []
    	fr = open(fileName)
    	for line in fr.readlines():   # 遍历行数(样本行)
    		lineArr = []
    		curLine = line.strip().split('	')  # curLine该行(当前行)的所有特征的数据
    		# print("curLine = ", curLine)
    		for i in range(numFeat - 1):  # 遍历所有特征(除去类别标签列的)
    			lineArr.append(float(curLine[i]))  # 获得该行(当前行)除最后一列的其他所有特征的数据(格式化为浮点型)
    		dataMat.append(lineArr)
    		# i = 0列时,dataMat =  [[2.0, 1.0, 38.5, 66.0, 28.0, 3.0, 3.0, 0.0, 2.0, 5.0, 4.0, 4.0, 
    		#                        0.0, 0.0, 0.0, 3.0, 5.0, 45.0, 8.4, 0.0, 0.0]]
    		# print("dataMat = ", dataMat)
    		labelMat.append(float(curLine[-1]))
    	return dataMat, labelMat
    
    #################7.7节:非均衡分类问题--TPR和FPR和ROC曲线绘制-###########################
    
    
    def plotRoc(predStrengths, classLabels):
    	"""
    	Parameters:
    		predStrengths--分类器的预测强度
    		classLabels--类别
    	Returns:
    	无
    	"""
    	import matplotlib.pyplot as plt
    	cur = (1.0, 1.0)  # 绘制光标的位置
    	ySum = 0.0         # 用于计算AUC面积
    	numPosClas = np.sum(np.array(classLabels) == 1.0) # 统计正类的数量
    	yStep = 1 / float(numPosClas)   # y轴步长
    	xStep = 1 / float(len(classLabels) - numPosClas)  # x轴步长
    
    	sortedIndicies = predStrengths.argsort()  # 预测强度排序,从低到高
    	# print("sortedIndicies = 
    ", sortedIndicies)
    	fig = plt.figure()
    	fig.clf()
    	ax = plt.subplot(111)
    	# print("sortedIndicies.tolist()[0] = 
    ", sortedIndicies.tolist()[0])
    	for index in sortedIndicies.tolist()[0]:
    		if classLabels[index] == 1.0:
    			delX = 0 ; delY = yStep
    		else:
    			delX = xStep; delY = 0
    			# 高度累加(xStep是固定的,最后ySum * xStep即可求AUC面积)
    			ySum = ySum + cur[1]  # 注意每次cur[1]都可能变化了
    		# 绘制ROC(两点一线) 每次点(cur[0],cur[1])和点(cur[0] - delX, cur[1] - delY)连成一条直线
    		ax.plot([cur[0], cur[0] - delX], [cur[1], cur[1] - delY], c = 'b') 
    		cur = (cur[0] - delX, cur[1] - delY)    # 更新绘制光标的位置
    		#print("cur ====== 
    ",cur)
    
    	ax.plot([0,1], [0,1], 'b--')  # 画虚线(即随机猜测的结果曲线)
    	plt.xlabel('False Positive Rate')
    	plt.ylabel('True Positive Rate')
    	plt.title('ROC curve for AdaBoost Horse Colic Detection System')
    	ax.axis([0,1,0,1])
    	print("AUC面积为:", ySum * xStep)
    	plt.show()
    
    
    
    
    if __name__ == '__main__':
    	
    	dataMat, classLabels = loadSimpData()
    	# print(dataMat, classLabels)
    	# showDataSet(dataMat, classLabels)
    	D = np.mat(np.ones((5,1))/5)
    	# print(buildStump(dataMat, classLabels, D))
    	weakClassArr, aggClassEst = adaBoostTrainDS(dataMat, classLabels, 9)
    	# print("weakClassArr = ", weakClassArr) # 打印出所有弱分类器
    	# print("aggClassEst = ", aggClassEst)
    	# print('-------分割线-------')
    	# print(adaClassify([0,0], weakClassArr))
    	# print('=======分割线=======')
    	# print(adaClassify([[5,5], [0,0]], weakClassArr))
    	print()
    
    	print("-----第7.6节 示例:在一个难数据集上应用AdaBoost-----")
    	print()
    	dataArr, LabelArr = loadDataSet('horseColicTraining2.txt')
    	weakClassArr, aggClassEst = adaBoostTrainDS(dataArr, LabelArr)
    	print("----------用在测试集试试-----------------------")
    	testArr, testLabelArr = loadDataSet('horseColicTest2.txt')
    	# print("weakClassArr = ", weakClassArr)
    	predictions = adaClassify(dataArr,weakClassArr)
    	errArr = np.mat(np.ones((len(dataArr), 1)))
    	print("训练集上的错误数:%s" %(errArr[predictions != np.mat(LabelArr).T].sum()))
    	print('训练集上的错误率: %.3f%%' %float(errArr[predictions != np.mat(LabelArr).T].sum() / len(dataArr) * 100))
    
    	predictions = adaClassify(testArr, weakClassArr)
    	errArr = np.mat(np.ones((len(testArr), 1)))
    	print("测试集上的错误数:%s" %(errArr[predictions != np.mat(testLabelArr).T].sum()))
    	print('测试集上的错误率: %.3f%%' %float(errArr[predictions != np.mat(testLabelArr).T].sum() / len(testArr) * 100))
    	print("-------------7.7节:非均衡分类问题--TPR和FPR和ROC曲线绘制--------------------")
    	print()
    	plotRoc(aggClassEst.T, LabelArr)
    
    
    	
    
  • 相关阅读:
    iOS MDM证书制作
    iOS 跳转到设置界面
    创建自己的远程私有库
    制作属于自己的cocoapod仓库和spec
    iOS 推送通知证书制作
    自定义导航栏之滑动返回
    xcode使用xib创建cell ,出现崩溃问题
    Xcode使用xib拖线时出现: could not insert new outlet connection
    2014年糯米网校招测试工程师题目解析
    JAVA操作LDAP的详解(JLDAP)
  • 原文地址:https://www.cnblogs.com/HongjianChen/p/9647845.html
Copyright © 2020-2023  润新知