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