#coding=utf-8
from numpy import *
def loadSimpData():
dataMat = 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 dataMat, classLabels
#单层决策树生成函数
def stumpClassify(dataMatrix, dimen, threshVal, threshIneq):
retArray = ones((shape(dataMatrix)[0], 1))
if threshIneq == 'lt':
retArray[dataMatrix[:,dimen] <= threshVal] = -1.0
else:
retArray[dataMatrix[:,dimen] > threshVal] =-1.0
return retArray
#最佳单层决策树寻找函数,D权重向量
def buildStump(dataArr, classLabels, D):
dataMatrix = mat(dataArr); labelMat = mat(classLabels).T
m, n = shape(dataMatrix)
numSteps = 10.0; bestStump = {}; 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']:
threshVal = (rangeMin + float(j) * stepSize) #阈值以步长为单位选取
predictedVals = stumpClassify(dataMatrix, i, threshVal, inequal) #预测
errArr = mat(ones((m, 1))) #错误列向量
errArr[predictedVals == labelMat] = 0 #预测正确的错误列向量中对应的值为0,否则为1
weightedError = D.T*errArr #错误列向量和权重向量相乘求和得到weightedError
if weightedError < minError: #如果错误率较小,则保存最小分类器
minError = weightedError
bestClasEst = predictedVals.copy()
bestStump['dim'] = i #保存最佳分类器信息
bestStump['thresh'] = threshVal
bestStump['ineq'] = inequal
return bestStump, minError, bestClasEst
#基于单层决策树的adaBoost训练过程
def adaBoostTrainDS(dataArr, classLabels, numIt = 40):
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) #当前D下最佳单层决策树寻找函数,D权重向量
print "D: ", D.T
alpha = float(0.5 * log((1 - error) / max(error, 1e-6))) #计算alpha
bestStump['alpha'] = alpha
weakClassArr.append(bestStump) #保存弱分类器
print "classEst: ", classEst.T
expon = multiply(-1 * alpha * mat(classLabels).T,classEst) #按公式更新权重系数
D = multiply(D, exp(expon))
aggClassEst += alpha * classEst #计算样本的分类结果
aggErrors = multiply(sign(aggClassEst) != mat(classLabels).T, ones((m, 1)))
errorRate = aggErrors.sum()/m #计算错误率
print "total error: ", errorRate, "\n"
if errorRate == 0.0: break #错误率为0,退出
return weakClassArr
#AdaBoost分类函数
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'])
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():
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
总结
- 多个分类器组合可能进一步凸显出单分类器的不足,比如过拟合问题。如果分类器之间差别显著,那么多个分类器组合就可能换缓解这一问题。分类器之间的差别可以是算法本身或者是应用于算法上的数据不同。
- boosting方法中最流行的一个被称为AdaBoosting的算法,AdaBoosting以弱学习器作为基础分类器,并且输入s数据,使其通过权重向量进行加权。在第一次迭代过程中,所有数据都等权重。但是在后续的迭代之中,前次迭代中分错的数据权重会增大。这种针对错误的调节能力正式AdaBoost的长处。
- 本章以单层决策树作为弱分类器构建Adaboost分类器。实际上,AdaBoost函数应用任何分类器,只要该分类器能够处理加权数据即可。AdaBoost算法十分强大,它能够快速处理其他分类器难处理的数据集。
- 非均衡分类问题是指在分类器训练时正列数目和反例数目不相等(相差很大)。该问题在错分正列和反例的代价不同时也存在。
- 本章介绍了通过过抽样和欠抽样方法来调节数据集中的正列和反例数目。另外一种可能更好的非均衡问题的处理方法,就是在训练分类器时将错误代价考虑在内。