#-*-coding:utf-8-*-
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
# 7.1 单层决策树生成函数
# 函数1stumpClassify(),通过阈值比较对数据进行分类
# 所有在阈值一边的数据会分到类别-1,而在另一边的数据分到类别+1
def stumpClassify(dataMatrix, dimen, threshVal, threshIneq):
# 数组过滤,首先将返回数组的全部元素设置为1
retArray = ones((shape(dataMatrix)[0], 1))
if threshIneq == 'lt':
retArray[dataMatrix[:, dimen] <= threshVal] = -1.0
else:
retArray[dataMatrix[:, dimen] > threshVal] = -1.0
return retArray
# 函数2builstump()遍历stumpClassify()函数所有可能的输入值,并找到数据集上最佳的单层决策树
# 权重向量D定义“最佳”
def buildStump(dataArr, classLabels, D):
dataMatrix = mat(dataArr)
labelMat = mat(classLabels).T
m, n = shape(dataMatrix)
numSteps = 10.0 # 变量numsteps,用于在特征的所有可能值上进行遍历
bestStump = {} # 构建空字典,存储给定权重向量D时所得最佳单层决策树的相关信息
bestClasEst = mat(zeros((m, 1)))
minError = inf # 变量minError,初始为正无穷,用于之后寻找可能的最小错误率
# 三层嵌套for函数
# 第一层在数据集的所有特征上遍历,最小值和最大值
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):
# 第三层循环,调用stumpClassify()函数,该函数返回分类预测结果
for inequal in ['lt','gt']:
threshVal = (rangeMin + float(j)*stepSize)
predictedVals = stumpClassify(dataMatrix,i,threshVal,inequal)
errArr = mat(ones((m,1))) # 构建列向量errArr
errArr[predictedVals == labelMat] = 0 # 如果predictedVals中值不等于labelMat中的真正类别标签值,errArr相应位置为1
weightedError = D.T * errArr # adaBoost和分类器交互的地方:基于权重向量D评价分类器
if weightedError < minError:
minError = weightedError
bestClasEst = predictedVals.copy()
bestStump['dim'] = i
bestStump['thresh'] = threshVal
bestStump['ineq'] = inequal
return bestStump, minError, bestClasEst
# 7.2 基于单决策树的AdaBoost训练过程
# AdaBoost算法参数包括数据集,类别标签, 迭代次数numIt(numIt是唯一需要用户指定的参数)
# (假定迭代次数为9,如果在第三次迭代之后错误率为0, 那么就会退出迭代过程)
# 函数名称内部DS代表单层决策树(decision stump),它是AdaBoost中最流行的弱分类器
def adaboostTrainDS(dataArr, classLabels,numIt=4.0):
weakClassArr = [] # 算法会输出一个DS的数组,因此首先需要建立一个新的表来对其进行存储
m = shape(dataArr)[0] # 然后,得到一个数据集中的数据点的数目m
D = mat(ones((m,1))/m) # 建立一个列向量D
# 列向量D非常重要,它包含了每个数据点的权重,一开始赋予每个权重等值,在后续迭代中,AdaBoost算法在增加错分数据的权重同时,降低正确分类数据的权重
# D是一个概率分布向量,因此其所有的元素之和为1.0,为此所有向量初始化为1/m
aggClassEst = mat(zeros((m,1))) # 同时建立一个aggClassEst列向量,记录每个数据点的类别估计累计值
# 算法核心for循环,运行numIt次或者直到错误率为0为止
for i in range(numIt):
bestStump, error, classEst = buildStump(dataArr,classLabels,D) # 循环的第一件事就是利用前面的buildStump()函数建立一个单层决策树
# 返回的是利用D而得到的具有最小错误率的单层决策树,和最小错误率,以及估计的类别向量
print("D:", D.T) # 该函数的输入为权重向量D,
alpha = float(0.5*log((1.0 - error)/max(error, 1e-16))) # 计算alpha值,该值会告诉分类器本次单层决策树输出结果的权重
# max(error, 1e-16)用于确保在没有错误时不会发生除零溢出
weakClassArr.append(bestStump) # 而后,alpha值加入到bestStump字典中,该字典又添加到列表中,该字典包含了分类所需要的所有信息
print("classEst: ", classEst.T)
# 下三行,用于计算下一次迭代中的新权重向量D
expon = multiply(-1*alpha*mat(classLabels).T, classEst)
D = multiply(D, exp(expon))
D = D/D.sum()
# aggClassEst变量保持一个运行时的类别估计值,来实现在训练错误率为0时,提前结束for循环
aggClassEst += alpha*classEst
print("aggClassEst:" ,aggClassEst.T)
# 该值只是一个浮点数,调用sign()函数得到一个二值分类结果
aggErrors = multiply(sign(aggClassEst) != mat(classLabels).T, ones((m,1)))
errorRate = aggErrors.sum()/m
print("total error:", errorRate,"\n")
if errorRate == 0.0:
break
return weakClassArr, aggClassEst
# 7.3 AdaBoost分类函数
# adaClassify()函数就是利用训练出的多个弱分类器进行分类的函数
# 输入是由一个或者多个待分类样例datToClass以及多个弱分类器组成的数组classifierArr
def adaClassify(datToClass, classifierArr):
dataMatrix = mat(datToClass) # 转换成numpyjuzhen
m = shape(dataMatrix)[0] # 得到待分类样例的个数m
aggClassEst = mat(zeros((m,1))) # 构建0列向量aggCLassEst(同adaBoostTrain()中的含义)
# 遍历classifierA中的所有弱分类器,
for i in range(len(classifierArr)):
# 基于stumpClassify()对每个分类器得到一个类别的估计值
# 在这里只是简单了应用了DS:输出的类别估计乘上该DS的alpha权重然后累加到aggClassEst上
ClassEst = stumpClassify(dataMatrix,classifierArr[i]['dim'],classifierArr[i]['thresh'],classifierArr[i]['ineq'])
aggClassEst += classifierArr[i]['alpha']*ClassEst
# 加入print语句,以便了解每次迭代后的变化结果
print aggClassEst
# 最后返回aggClassEst的符号,如果大于0返回+1, 如果小于0返回-1
return sign(aggClassEst)
# 在一个难数据集上应用AdaBoost
# 7.4 自适应数据加载函数
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, labelMat
# 7.5 ROC曲线的绘制及AUC计算函数
# 两个参数输入
# 第一个是NumPy数组活着一个行向量组成的矩阵,代表的是分类器的预测强度
# 第二个是先前使用过的classLabels
def plotROC(predStrengths, classLabels):
import matplotlib.pyplot as plt
cur = (1.0,1.0) # 构建一个浮点数二元组,并初始化。该元组保留的是绘制光标的位置
ySum = 0.0 # ySum则用于计算AUC的值
# 通过数组过滤方式计算正例的数目,并将该值赋给numPosClas
numPosClas = sum(array(classLabels) == 1.0)
# 该值先是确定了在y坐标轴上的步进数目
# 接着在x、y轴上绘点,y轴上步长是1.0/numPosCLas
yStep = 1/float(numPosClas)
# 类似得到x轴步长
xStep = 1/float(len(classLabels) - numPosClas)
# 得到排序索引,但是这些索引是按照最小到最大的顺序排列,因此需要从点(1.0,1.0)到(0.0)
sortedIndicies = predStrengths.argsort()
# 下三行,构建画笔,
fig = plt.figure()
fig.clf()
ax = plt.subplot(111)
# 在所有排序值上进行循环。
# 这些值在一个NumPy数组或矩阵中进行排序,需要一个表来进行迭代循环,因此需要调用tolist()方法
for index in sortedIndicies.tolist()[0]:
# 只关注1这个类别标签,无所谓1/0或1/-1
# 每得到一个标签为1.0的类,则要沿着y轴方向下降一个步长,即不断降低真阳率v
if classLabels[index] == 1.0:
delX = 0
delY = yStep
# 类似对于其他类别标签,则是在x轴上倒退一个步长,即假阴率
# 为了计算AUC,需要对多个小矩形的面积进行累加,小矩形宽度为xStep,所有高度和随着x轴的每次移动而渐次增加
else:
delX = xStep
delY = 0
ySum += cur[1]
#一旦决定了是在x轴还是y轴方向上移动,我们就可以在当前点和新点之间画出一条线段
ax.plot([cur[0],cur[0]-delX],[cur[1],cur[1]-delY],c='b')
cur = (cur[0] - delX, cur[1] - delY)
ax.plot([0,1],[0,1],'b--')
plt.xlabel('False Positive Rate')
plt.title('ROC curve for AdaBoost Horse Colic Detection System')
ax.axis([0,1,0,1])
plt.show()
MLiA笔记_adaBoost
猜你喜欢
转载自blog.csdn.net/weixin_42836351/article/details/81393051
今日推荐
周排行