机器学习实战--AdaBoost集成学习方法

from numpy import *

def loadSimpData():
    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

#函数功能:		通过阀值比较对数据进行分类
#dataMatrix:	数据集的特征矩阵
#dimen: 		第dimen个特征
#threshVal: 	阀值
#threshIneq:	标志
#函数返回:		一个分类结果的数组    
def stumpClassify(dataMatrix,dimen,threshVal,threshIneq):
	retArray = ones((shape(dataMatrix)[0],1))
	if threshIneq == 'It': #'It'是less than
		retArray[dataMatrix[:,dimen] <= threshVal] = -1.0 #小于阀值都是-1,大于阀值都是1
	else:					#'It'是greater than
		retArray[dataMatrix[:,dimen] > threshVal] = -1.0  #小于阀值都是1,大于阀值都是-1	
	return retArray

#函数功能:		遍历数据集的每一个特征,每一个特征情况下遍历的不同阀值,在每一个不同阀值下遍历‘Lt’‘Gt’,并找到数据集上最佳的单层决策树 ,这个单层决策树只用一个特征就将数据集划分
#dataArr: 		列表格式的特征矩阵
#classLabels:	列表格式的标签向量
#D:				数据样本的权重向量
#函数的返回值:	最佳决策树信息,最小错误率,最好的预测分类结果
def buildStump(dataArr,classLabels,D):
	dataMatrix = mat(dataArr); labelMat = mat(classLabels).T
	m,n = shape(dataMatrix)
	
	numSteps = 10.0; 	#用于固定一个特征时,遍历该特征的不同取值,以确定分类结果的一个变量
	bestStump = {}; 	#用于存储给定权值向量D时,所得到的单层最佳决策树的相关信息,比如特征结点是啥,阀值是多少,大于还是小于分类
	bestClasEst = mat(zeros((m,1)))
    minError = 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']:  	# 在特征固定取某个阀值时,分类为-1,1和1,-1的情况
				threshVal = (rangeMin + float(j) * stepSize)  #当前阀值取值
				predictedVals = stumpClassify(dataMatrix,i,threshVal,inequal)#调用stumpClassify()返回一个分类结果数组
				
				#下面要去记录当前这个分类结果的错误率
				errArr = mat(ones((m,1)))
                errArr[predictedVals == labelMat] = 0
                #errArr数组,该样本点分类正确就为0,分类错误就为1
                
                weightedError = D.T*errArr 
                #按理说,当前分类错误率是:sum(errArr)/shape(errArr)[0]
                #但是这里设置了最佳权重D
                
                print "split: dim %d, thresh %.2f, thresh ineqal: %s, the weighted error is %.3f" 
						% (i, threshVal, inequal, weightedError)
						
				if weightedError < minError:
                    minError = weightedError
                    bestClasEst = predictedVals.copy() 
                    bestStump['dim'] = i
                    bestStump['thresh'] = threshVal
                    bestStump['ineq'] = inequal
     
	return bestStump,minError,bestClasEst
	
		
def adaBoostTrainDS(dataArr,classLabels,numIt=40):
	weakClassArr = []
    m = shape(dataArr)[0]
    D = mat(ones((m,1))/m)   #初始化数据权值分布D
    aggClassEst = mat(zeros((m,1)))	#用来记录每个数据点的类别估计累计值
    
    for i in range(numIt):
		bestStump,error,classEst = buildStump(dataArr,classLabels,D)
		print "D:",D.T
		alpha = float(0.5*log((1.0-error)/max(error,1e-16))) #计算弱分类器的系数alpha,max(error,1e-16)用于在没有错误时不会发生零溢出
		bestStump['alpha'] = alpha #bestStump字典包括了‘dim’,‘thresh’,‘ineq’,‘alpha’
		weakClassArr.append(bestStump) #将这个弱分类器,加入到列表当中
		#以下要做的是更新D
		expon = multiply(-1*alpha*mat(classLabels).T,classEst)
		D = multiply(D,exp(expon))                       
        D = D/D.sum()  #D.sum()就是书中的Zm
        
        #下面计算当前已经计算的弱分类器的线性组合的分类误差,当误差为零时,就退出循环
        aggClassEst += alpha*classEst	#classEst是当前弱分类器的分类结果
        
        aggErrors = multiply(sign(aggClassEst) != mat(classLabels).T,ones((m,1)))
        #sign(aggClassEst) != mat(classLabels).T ,这一项是返回的是一个元素未true,false的向量
        errorRate = aggErrors.sum()/m	#计算当前弱分类线性组合的误差率
        
        print "total error: ",errorRate
        if errorRate == 0.0: break
	return weakClassArr,aggClassEst


#datToClass:		待分类样列
#classifierArr:		由adaBoostTrainDS()函数计算好的多个弱分类器列表
def adaClassify(datToClass,classifierArr):
	dataMatrix = mat(datToClass)
	m=shape(dataMatrix)[0]
	aggClassEst = mat(zeros((m,1)))
	for i in range(len(classifierArr)): #对于每个弱分类器
		#都拿来计算一遍样例的分类结果
		classEst = stumpClassify(dataMatrix,classifierArr[i]['dim'],classifierArr[i]['thresh'],classifierArr[i]['ineq'])#call stump classify
		aggClassEst += classifierArr[i]['alpha']*classEst  #计算一下每个弱分类器分类结果的线性组合
		print aggClassEst
    return sign(aggClassEst)	#返回最终的分类结果
    
def loadDataSet(fileName):
	numFeat = len(open(fileName).readline().split('\t'))
	dataMat=[];	labelMat=[]
	fr = open(fileName)
	for line in fr.readlines():
		curLine = line.strip().split('\t') #curLine是一个字符串的列表
		for i in range(numFeat-1):
			lineArr.append(float(curLine[i]))
		dataMat.append(lineArr)
		labelMat.append(float(curLine[-1]))
	return dataMat,labelMat

猜你喜欢

转载自blog.csdn.net/carl95271/article/details/80766168