python3.6
代码和训练集:https://pan.baidu.com/s/1MFsCmSTfmRPU0M_W4Shc4g
from numpy import *
import numpy as np
from scipy import *
from math import *
def loadSimpData():
datMat=matrix([[1.0,2.1],[2.0,1.1],[1.3,1.0],[1.0,1.0],[2.0,1.0]])
classLabels=[1.0,1.0,-1.0,-1.0,1.0]
return datMat,classLabels
'''
单层决策树生成函数(弱分类器)思路:
在特征0、情况1、下通过阈值生成1、-1矩阵,在用这个矩阵和classLabels矩阵一一对比计算加权错误率weightedError
在特征0、情况2、下通过阈值生成1、-1矩阵,在用这个矩阵和classLabels矩阵一一对比计算加权错误率weightedError
在特征1、情况1、下通过阈值生成1、-1矩阵,在用这个矩阵和classLabels矩阵一一对比计算加权错误率weightedError
在特征1、情况2、下通过阈值生成1、-1矩阵,在用这个矩阵和classLabels矩阵一一对比计算加权错误率weightedError
保留加权错误率weightedError最小的字典bestStump: bestStump, minError, bestClasEst。
'''
def stumpClassify(dataMatrix,dimen,threshVal,threshIneq):
#ones函数设成shape(dataMatrix)[0]行,1列的矩阵。
retArray=ones((shape(dataMatrix)[0],1))
#'lt'为情况1、'gt'为情况2。
#举例:第dimen=0个特征矩阵为[[1],[2],[1.3],[1],[2]],阈值threshVal为1.3
#情况1下有:retArray为[[-1],[1],[-1],[-1],[1]] 在buildStump()函数下计算weightedError=0.2
#情况2下有:retArray为[[1],[-1],[1],[1],[-1]] 在buildStump()函数下计算weightedError=0.8
if threshIneq=='lt':
retArray[dataMatrix[:,dimen]<=threshVal]=-1.0#情况1
else:
retArray[dataMatrix[:,dimen]>threshVal]=-1.0#情况2
return retArray
def buildStump(dataArr,classLabels,D):
#dataArr、classLabels变成矩阵,.T为转置
dataMatrix = mat(dataArr); labelMat = mat(classLabels).T
#m为行数 n为列数、numSteps用于特征所有可能的值的历遍
#bestStump用于存储给定权值向量D时的所得到的最佳单层决策树信息
#inf是无穷大的意思
m,n = shape(dataMatrix)
numSteps = 10.0; bestStump = {}; bestClasEst = mat(zeros((m,1)))
minError = inf
#第一层循环 对数据集中的每一个特征 n为特征总数
for i in range(n):
#rangeMin、rangeMax第i个特征的最小值,最大值
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']:
#计算阈值
threshVal = rangeMin + float(j) * stepSize
#stumpClassify(矩阵,特征,阈值,不等式)
predictedVals = stumpClassify(dataMatrix,i,threshVal,inequal)
#先假设所有的结果都是错的(标记为1)
errArr = mat(ones((m,1)))
#然后把预测结果正确的标记为0
errArr[predictedVals == labelMat] = 0
#计算加权错误率\D是向量
weightedError = D.T*errArr
print ('split: dim %d, thresh %.2f, thresh inequal: %s, \
the weightederror 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
#输出结果试一试
# ~ D=mat(ones((5,1))/5)
# ~ datMat,classLabels=loadSimpData()
# ~ print(buildStump(datMat,classLabels,D))
'''
这部分公式难以理解请看《统计学习方法》P138-P142(8.1.2节到-8.1.3节)
'''
#参考https://www.cnblogs.com/zy230530/p/6909288.html
#特征矩阵dataArr,类标签classLabels,循环次数。
def adaBoostTrainDS(dataArr,classLabels,numIt=40):
#弱分类器相关信息列表:存储特征、阈值、情况、分类器alpha
weakClassArr=[]
m=shape(dataArr)[0]
#初始化权重向量的每一项值相等
D=mat(ones((m,1))/m)
#累计估计值向量
aggClassEst=mat(zeros((m,1)))
#循环迭代次数
for i in range(numIt):
#根据当前数据集,标签及权重建立最佳单层决策树
bestStump,error,classEst=buildStump(dataArr,classLabels,D)
#打印权重向量
print("D:",D.T)
#求单层决策树的系数alpha\max用法:error不能小于1e-16,小于就为1e-16
alpha=float(0.5*log((1.0-error)/(max(error,1e-16))))
#存储决策树的系数alpha到字典
bestStump['alpha']=alpha
#将该决策树存入列表
weakClassArr.append(bestStump)
#打印决策树的预测结果
print("classEst:",classEst.T)
#expon为列表
expon=multiply(-1*alpha*mat(classLabels).T,classEst)
#print(expon)
#更新权值向量,D为列表,python标准库里面也有exp,换成numpy的exp
D=multiply(D,np.exp(expon))
#print(D)
D=D/D.sum()
#累加当前单层决策树的加权预测值,出现Cannot cast ufunc add output from dtype('float64') to dtype('int32')
#把 aggClassEst+=alpha*classEst改成 aggClassEst=aggClassEst+alpha*classEst
aggClassEst=aggClassEst+alpha*classEst
print("aggClassEst",aggClassEst.T)
#求出分类错的样本个数
aggErrors=multiply(sign(aggClassEst)!=\
mat(classLabels).T,ones((m,1)))
#计算错误率
errorRate=aggErrors.sum()/m
print("total error:",errorRate,"\n")
#错误率为0.0退出循环
if errorRate==0.0:break
#返回弱分类器的组合列表
return weakClassArr,aggClassEst
#测试一下
# ~ datMat,classLabels=loadSimpData()
# ~ classifierArray=adaBoostTrainDS(datMat,classLabels,9)
# ~ print(classifierArray)
#adaBoost分类函数
def adaClassify(datToClass, classifierArr) :
#datToClass转换为矩阵
dataMatrix = mat(datToClass)
m = shape(dataMatrix)[0]
aggClassEst = mat(zeros((m,1)))
#len(classifierArr)为字典数
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 sign(aggClassEst)
#测试一下
# ~ datArr,labelArr=loadSimpData()
# ~ classifierArray=adaBoostTrainDS(datArr,labelArr,30)
# ~ A=adaClassify([[5,5],[0,0]],classifierArray)
# ~ print(A)
#自适应数据加载函数
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
#绘制ROC
#这部分代码参考https://blog.csdn.net/namelessml/article/details/52536514?locationNum=13
def plotROC(predStrengths, classLabels) :
import matplotlib.pyplot as plt
# cur保留的是绘制光标的位置
cur = (1.0, 1.0)
# ySum则用于计算AUC的值
ySum = 0.0
# 通过数组过滤方式计算正例的数目,并赋给numPosClas,接着在x轴和y轴的0.0到1.0区间上绘点
numPosClas = sum(array(classLabels)==1.0)
# 在y轴上的步长
yStep = 1/float(numPosClas)
# 在x轴上的步长
xStep = 1/float(len(classLabels) - numPosClas)
# 获取排好序的索引sortedIndicies,这些索引从小到大排序。需要从<1, 1>开始绘,一直到<0,0>
sortedIndicies = predStrengths.argsort()
fig = plt.figure()
fig.clf()
ax = plt.subplot(111)
# 在所有排序值上进行循环。这些值在一个NumPy数组或矩阵中进行排序,
# python则需要一个表来进行迭代循环,因此需要调用tolist()方法
for index in sortedIndicies.tolist()[0] :
# 每得到一个标签为1.0的类,则要沿着y轴的方向下降一个步长,即降低真阳率
if classLabels[index] == 1.0 :
delX = 0; delY = yStep
# 对于每个其他的标签,则是x轴方向上倒退一个步长(假阴率方向),
# 代码只关注1这个类别标签,采用1/0标签还是+1/-1标签就无所谓了
else :
delX = xStep; delY = 0
# 所有高度的和ySum随着x轴的每次移动而渐次增加
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.ylabel('True Positive Rate')
plt.title('ROC curve for AdaBoost Horse Colic Detection System')
ax.axis([0,1,0,1])
plt.show()
# 计算AUC需要对多个小矩形的面积进行累加,这些小矩形的宽度都是xStep,
# 因此可对所有矩形的高度进行累加,然后再乘以xStep得到其总面积
print ("the Area Under the Curve is: ", ySum*xStep)
#测试一下
dataMat, labelMat=loadDataSet("horseColicTraining2.txt")
weakClassArr,aggClassEst=adaBoostTrainDS(dataMat,labelMat,10)
dataMat1, labelMat1=loadDataSet("horseColicTest2.txt")
A=adaClassify(dataMat1, weakClassArr)
print(A)
plotROC(aggClassEst.T, labelMat)