首先我们可以将不同的分类器进行组合,这种方法叫做集成方法(ensemble method)或元算法(meta-algorithm)。
bagging:
bootstrapping的简称,我的理解:重复采样,每次都将新采样的样本作为数据集,随机采样替换的方式,得到与原来数据集规模一样的的数据集,以此来得到不一样的结果。
boosting:
通过对弱分类器结果进行分析,将正确的缩小权重,错误的加大权重来重新分配权重,不停地进行调整来降低错误率。
应用多个不同的分类器。
Adaboost:
详细看笔记,简要写一下基本原理:先用一个弱分类器去处理训练集,得出它的错误率。然后对错误量重新分配它的权重(重视程度),分对则是降低它的权重。经过几次迭代后,得出了最终分类结果,因为不止一个分类器(重新分配一次权重代表用了一种分类器),然后计算将它们组成线性组合时前面的值。
未正确分类的样本数目/所有样本数目
计算出alpha值之后,对权重向量进行更新,降低正确分类权重,增加错误分类权重。
被正确分类:
被错误分类:
import random
import numpy as np
from numpy import *
import matplotlib.pyplot as plt
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import AdaBoostClassifier
#构建一个简单数据集
def loadSimpleData():
dataMat = 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 stumpClassify(dataMatrix,dimen,threshVal,threshIneq):
retArray = ones((shape(dataMatrix)[0],1)) #初始化
if threshIneq == 'It':
retArray[dataMatrix[:,dimen] <= threshVal] = -1.0
else:
retArray[dataMatrix[:,dimen] > threshVal] = 1.0
return retArray
#寻找到最佳的单层决策树
def buildStump(dataArr, classLabels, D):
dataMatrix = mat(dataArr);labelMat = mat(classLabels).T
m,n = shape(dataMatrix)
numSteps = 10.0 #用于在特征上所有可能值进行遍历
bestStump = {}#字典,用于储存最低错误率情况下的单层决策树信息
bestClassEst = 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 ['It','gt']:#来回切换
threshVal = (rangeMin + float(j) * stepSize) #设定的阈值
predictedVals = stumpClassify(dataMatrix,i,threshVal,inequal)
errArr = mat(ones((m,1)))
errArr[predictedVals == labelMat] = 0
weightedError = D.T * errArr #通过权重向量D的相应元素与错误向量相乘并求和
#print 'split: dim %d, thresh %.2f, thresh ineqal:\
# %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
#基于单层决策树的AdaBoost训练过程
def adaBoostTrainDs(dataArr,classLabels,numIt=40):
#输入参数为数据集、类别以及迭代次数
weakClassArr = [] #
m = shape(dataArr)[0]
D = mat(ones((m,1))/m) #权重向量D,初始化时都是1/m
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)))
#其中log里这样写是为了确保在没有错误时不会发生分母上出现0
bestStump['alpha'] = alpha #更新alpha值
weakClassArr.append(bestStump)
#print 'classEst:',classEst.T #预测估计
expon = multiply(-1*alpha*mat(classLabels).T,classEst)
#如果正确即classLabels和classEst相同时,则相乘为1,否则为-1
D = multiply(D,exp(expon))
D = D/D.sum()
aggClassEst += alpha * classEst
#print 'aggClassEst:',aggClassEst#累积的预测估计(已经乘以alpha分量)
aggErrors = multiply(sign(aggClassEst) != mat(classLabels).T,ones((m,1)))
#利用sign函数得到二值分类结果
errorRate = aggErrors.sum() / m
print 'total error: ',errorRate,'\n' #总的错误率
if errorRate == 0.0 :
break
return weakClassArr,aggClassEst
#datMat,classLabels = loadSimpleData()
#adaBoostTrainDs(datMat,classLabels,9)
利用该算法对简单数据分类的结果:
#7-3AdaBoost分类函数
def adaClassify(datToClass,classifierArr):
dataMatrix = mat(datToClass)#将输入的数据集转变为一个Numpy数组
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'])
aggClassEst += classifierArr[i]['alpha'] * classEst
#输出的类别估计值乘上该单层决策树的alpha权重然后累加到aggClassEst上
print aggClassEst
return sign(aggClassEst)
#第五章用logistic预测病马,这里利用多个单层决策树和AdaBoost来试试
#自适应数据加载函数
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
#datArr,labelArr = loadDataSet('D:\pythonml\horseColicTraining2.txt')
def classify():
#利用训练集训练分类器
datArr,labelArr = loadDataSet('horseColicTraining.txt')
#得到训练好的分类器
classifierArray = adaBoostTrainDs(datArr,labelArr,10)
#利用测试集测试分类器的分类效果
testArr,testLabelArr = loadDataSet('horseColicTest.txt')
prediction = adaClassify(testArr,classifierArray)
#输出错误率
num=shape(mat(testLabelArr))[1]
#print num
errArr = mat(ones((num,1)))
error = errArr[prediction != mat(testLabelArr).T].sum()
print 'the errorRate is: %.2f'%(float(error)/float(num))
对第五章logistic回归的病马预测,现在使用Adaboost配合决策树算法来实现,结果如下:
采用10个分类器:
运用sklearn库,使用Adaboost:
如何调参:https://www.cnblogs.com/pinard/p/6136914.html
#使用sklearn来实现Adaboost病马预测
datArr,labelArr = loadDataSet('D:\pythonml\horseColicTraining2.txt')#训练集
testArr,testLabelArr = loadDataSet('D:\pythonml\horseColicTest2.txt')#测试集
#决策树桩
dt_stump=DecisionTreeClassifier()
#dt_stump.fit(datArr,labelArr)
#dt_stump_err=1.0-dt_stump.score(testArr,testLabelArr)
ada_discrete=AdaBoostClassifier(base_estimator=dt_stump,learning_rate=0.35,n_estimators=10,algorithm='SAMME.R')
ada_discrete.fit(datArr,labelArr) #训练样本
print 'score:',ada_discrete.score(datArr,labelArr)
test = ada_discrete.predict(testArr)
errArr = mat(ones((67,1)))
error = errArr[test != testLabelArr].sum()
print 'the errorRate is: %.2f'%(float(error)/67)
最优结果:
参数:learning_rate=0.35,n_estimators=10
正确率、召回率和ROC曲线:
预测结果 | |||
+1 | -1 | ||
真实结果 | +1 | 真正例(TP) | 伪反例(FN) |
-1 | 伪正例(FP) | 真反例(TN) |
正确率:TP/(TP+FP) 预测为正例的样本中的真正正例的比例
召回率:TP/(TP+FN) 预测为正例的真实正例占所有真实正例的比例
我们很难构造一个正确率和召回率都很大的分类器。
ROC曲线(receiver operating characteristic 接收者操作特征):横轴是伪正例比例(FP/FP+TN),纵轴是真正例的比例(TP/TP+FN)。在理想情况下最佳分类器应该处于左上角,在假阳率很低的同时获得了很高的真阳率。对不同的ROC曲线进行比较的一个指标是曲线下的面积(Area Unser the Curve,AUC)
#7-5ROC曲线的绘制及AUC计算函数
def plotROC(predStrengths, classLabels):
#第一个参数是一个Numpy数组,代表着分类器的预测强度;第二个参数是标签
cur = (1.0,1.0)#绘制光标的位置
ySum = 0.0#该变量用于计算AUC的值(Area Under the Curve曲线下的面积)
numPosClas = sum(array(classLabels) == 1.0)#标签只有-1和1,统计标签为1的数目
yStep = 1 / float(numPosClas) #y的步长
xStep = 1 / float(len(classLabels) - numPosClas) #x的步长
sortedIndicies = predStrengths.argsort() #排序
fig = plt.figure()
fig.clf()
ax = plt.subplot(111)
for index in sortedIndicies.tolist()[0]:#tolist():将数组或者矩阵转换成列表
if classLabels[index] == 1.0:
delX = 0;delY = yStep;
#当遍历表时,每得到一个标签为1.0的类,则要沿着y轴的方向下降一个步长,即不断降低真阳率
else:
delX = xStep;delY = 0;
ySum += cur[1]
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()
print 'the Area Under the Curve is: ',ySum*xStep
datArr,labelArr = loadDataSet('D:\pythonml\horseColicTraining2.txt')
classifierArray,aggClassEst = adaBoostTrainDs(datArr,labelArr,60)
plotROC(aggClassEst.T,labelArr)