由于本人也是小白一只,所以本文将基于机器学习实战或者互联网作此记录,如有侵权告知将删……
1、AdaBoost
Adaboost算法是通过改变数据分布来实现的,他根据每次训练集之中的每个样本的分类是否正确,以及上次的总体分类的准确率,来确定每个样本的权值。将修改过权值的新数据集送给下层分类器进行训练,最后将每次得到的分类器最后进行融合起来,作为最后的决策分类器。
AdaBoost是以弱学习作为基分类的分类器,并且输入数据,使其通过权重向量进行加权。在第一迭代当中,所有数据都等权重。但是在后续迭代当中,前次迭代中分错的数据的权重会增大。这种对错误调节的能力正是AdaBoost的长处。AdaBoost可以应用于任意分类器,只要该分类器能够处理加权数据即可。
由于是基于机器学习实战这本书,所以AdaBoost算法是按照书上写的应用于单层决策树分类器之上的。难的我也不会 哇哈哈哈……
#
2、AdaBoost优缺点
优点:泛化错误率低
缺点:对离群点敏感
适用数据范围:数值型和标称型
3、公式
学习AdaBoost先了解一下公式:
错误率
ϵ
:
ϵ=未正确分类的样本数目所有样本数目
而alpha计算公式:
α=12ln(1−ϵϵ)
如果某个样本被正确分类,那么该样本的权重更改为:
D(t+1)i=D(t)ie−aSum(D)
如果某个样本被分错,那么样本的权重更改为:
D(t+1)i=D(t)ieaSum(D)
4、伪代码
构建基于单层决策树弱分类器
将最小错误率minError设为inf
对数据集中的每一特征(第一层循环):
对每个步长(第二层循环):
对每个等号(第三层循环):
建立一个单层决策树利用数据集对它进行测试
如果错误率低于minError,则将当前单层决策树设为最佳单层决策树
返回最佳单层决策树
AdaBoost算法
对每次迭代:
利用buildStump()函数找到最佳单层决策树
将最佳单层决策树加入到单层决策树数组
计算alpha
计算新的权重向量D
更新累计类别估计值
如果错误率等于0.0,退出循环
5、代码
#encoding:utf-8
import numpy as np
from numpy import *
from math import log
#简单的训练集
def loadSimData():
datMat = mat([[1,2],[2,1.1],[1.3,1.],[1,1],[2,1]])
classLabels=[1.0,1.0,-1.0,-1.0,1.0]
return datMat, classLabels
#通过特征值中的阀值进行分类,‘It’,‘gt’用于buildStump函数进行互换分类,
#由于本例是一个二分类问题,所以只有-1,1
def stumpClassify(datMat, dimen, val, Ineq):
reArray = ones((shape(datMat)[0], 1))
if Ineq == 'It':
reArray[datMat[:, dimen] <= val] = -1.0
else:
reArray[datMat[:, dimen] > val] = -1.0
return reArray
#寻找最佳特征值和最佳阀值进行分类
def buildStump(dataArr, classLabels, D):#D为权重向量
datMat = mat(dataArr);labelMat = mat(classLabels).T
m,n = shape(datMat)
numSteps = 10;#用于分割区间用
bestStump = {};#记录最佳的分割信息
bestClasEst = mat(ones((m,1)))#预测最佳的分类
minError = inf
for i in range(n):
rangeMin = datMat[:,i].min();rangeMax = datMat[:, i].max()
stepSize = (rangeMax - rangeMin)/numSteps#步长
for j in range(-1, int(numSteps)+2):#-1和numStep+2,是将他们分到一边,
for inequal in ['It','gt']:#用于分类转换,因为以前已经规定好了分类了
Val = rangeMin + float(j)*stepSize#阀值
preVal = stumpClassify(datMat, i, Val, inequal)#预测的分类
errArr = mat(ones((m,1)))
errArr[preVal == labelMat] = 0#分类一致的errArr置为0
weightedErr = D.T*errArr#计算加权错误率
'''自己的理解
D向量相当于一个惩罚措施,它会使错误的分类样本的对应的权重变大,如果想要
减小加权错误率那么就需要变换的另一边去,这样加权错误率就会减少,通过D就可以改正
错误
'''
# print "split: dim %d, thresh %.2f, thresh ineqal: %s, the weighted error is %.3f" % (i, Val, inequal, weightedErr)
if weightedErr < minError:
minError = weightedErr
bestClasEst = preVal.copy()
bestStump['dim'] = i
bestStump['thresh'] = Val
bestStump['ineq'] = inequal
return bestStump, minError, bestClasEst
#基于单层决策树的AdaBoost训练过程
def adaBoostTrainDS(dataArr, classLabels, numIt = 40):#numIt其实就是弱分类器的个数
weakClassArr=[]#记录不同的弱分类器
m = shape(dataArr)[0]
#D是一个概率分布,所有元素之和为1.0,所以为满足要求D一开始初始化为1/m
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)防止发生0溢出
alpha = float(0.5*log((1 - error)/ max(error, 1e-16)))
bestStump['alpha'] = alpha #将alpha记录到词典当中
weakClassArr.append(bestStump)
print 'classEst',classEst.T
'''迭代D向量'''
#计算 错误的权重 Di+1= Di*e^(a)/sum(D)和正确的权重Di+1= Di*e^(-a)/sum(D)
expon = multiply(-1*(alpha)*classEst, mat(classLabels).T)#这里进行的比较巧妙,
#对于分类相同的乘积一定为1,不同的分类的乘积为-1,利用这个性质可以简化代码
D = multiply(D, exp(expon))
D = D/D.sum()
#累加估计值
'''
个人理解
这里的alpha是根据错误率计算的来的alpha=1/2*ln((1-error)/error),可以看出来error越大alpha
越小,alpha*classEst这里代表的意思其实就可以这样理解,正确率越高说明可信度就越高,占得比重
就得越大
'''
aggClassEst += alpha*classEst
print "aggClassEst",aggClassEst.T
print "classLabels",classLabels
#sign函数将小于0的值变为-1,将大于0的值变为1
aggErrors = multiply(sign(aggClassEst) != mat(classLabels).T,ones((m,1)))
errorRate = float(aggErrors.sum()/m)
print "total error: ",errorRate
if errorRate == 0.0:
break
return weakClassArr
#AdaBoost分类函数
def adaClassify(datToClass, classifierArr):
datMat = mat(datToClass)
m = shape(datMat)[0]
aggClassEst=mat(zeros((m,1)))
for i in range(len(classifierArr)):
preVal = stumpClassify(datMat, classifierArr[i]['dim'], classifierArr[i]['thresh'],
classifierArr[i]['ineq'])
aggClassEst+=preVal*classifierArr[i]['alpha']
# print aggClassEst
return sign(aggClassEst)
#--------------预测马疝病----------------------
def loadDataSet(filename):
numFeat = len(open(filename).readline().strip().split('\t')) - 1
datMat=[];labelMat=[]
for line in open(filename).readlines():
curline = line.strip().split('\t')
furline=map(float,curline)
datMat.append(furline[:-1])
labelMat.append(furline[-1])
return datMat, labelMat
if __name__ == '__main__':
D = mat(ones((5,1))/5)
a,b=loadSimData()
# buildStump(a, b, D)
# classfy = adaBoostTrainDS(a, b, 40)
# adaClassify([[5,5],[0,0]],classfy)
datArr, labelArr = loadDataSet(r'horseColicTraining2.txt')
classifierArr = adaBoostTrainDS(datArr, labelArr, 10)#可以设置数量不同的分类器
'''
当分类器数目设置为50的时候预测的错误率最低。
其实我们发现测试错误率在随着分类器数目增多的同时,测试错误率在达到一个最小值之后又开始上升了
这类学习称为过拟合,有文献称,对于表现好的数据集,AdaBoost测试错误率会达到一个稳定值,并不会
随着分类器的数目增多而增多
'''
testArr, labelArr = loadDataSet(r'horseColicTest2.txt')
preVal = adaClassify(testArr, classifierArr)
print shape(preVal)
errArr = mat(ones((67,1)))
print errArr[preVal != mat(labelArr).T].sum()/67