AdaBoost算法

由于本人也是小白一只,所以本文将基于机器学习实战或者互联网作此记录,如有侵权告知将删……

1、AdaBoost

Adaboost算法是通过改变数据分布来实现的,他根据每次训练集之中的每个样本的分类是否正确,以及上次的总体分类的准确率,来确定每个样本的权值。将修改过权值的新数据集送给下层分类器进行训练,最后将每次得到的分类器最后进行融合起来,作为最后的决策分类器。
AdaBoost是以弱学习作为基分类的分类器,并且输入数据,使其通过权重向量进行加权。在第一迭代当中,所有数据都等权重。但是在后续迭代当中,前次迭代中分错的数据的权重会增大。这种对错误调节的能力正是AdaBoost的长处。AdaBoost可以应用于任意分类器,只要该分类器能够处理加权数据即可。
由于是基于机器学习实战这本书,所以AdaBoost算法是按照书上写的应用于单层决策树分类器之上的。难的我也不会 哇哈哈哈……
#

2、AdaBoost优缺点

优点:泛化错误率低
缺点:对离群点敏感
适用数据范围:数值型和标称型

3、公式

学习AdaBoost先了解一下公式:
错误率 ϵ

ϵ=

而alpha计算公式:
α=12ln(1ϵϵ)

如果某个样本被正确分类,那么该样本的权重更改为:
D(t+1)i=D(t)ieaSum(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



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值