AdaBoost算法理解与提升树原理及实现

AdaBoost算法理解与提升树原理及实现

从机器学习三要素理解AdaBoost算法

AdaBoost

  • 算法模型:加法模型 f(x)=m=1MalphamGm(x) f ( x ) = ∑ m = 1 M a l p h a m G m ( x ) , : 最 终 模 型 : G(x) = sign(f(x))$$
  • 损失函数:指数函数 基分类器分类错误或正确时 对数据集权值的调整 更为关注误分类 wm+1,i=WmiZmexpαmyiGm(xi) w m + 1 , i = W m i Z m exp − α m y i G m ( x i ) , Zm=i=1NWmiexpαmyiGm(xi) Z m = ∑ i = 1 N W m i exp − α m y i G m ( x i )
  • 算法:前向分步算法

前向分步算法

什么是前向分步算法
原理: 由于模型是加法模型, 如果从前向后, 每一步只学习上个基函数及其系数, 逐步逼近损失函数最小化函数,就可以简化优化的复杂度
从局部最优到全局最优

  • 模型: f(x)=m=1Mβmb(x;rm) f ( x ) = ∑ m = 1 M β m b ( x ; r m )
    其中: b(x;rm),,rm b ( x ; r m ) 是 基 函 数 , 弱 分 类 器 , r m 是 基 函 数 的 参 数
  • 损失函数: L(y,f(x)) L ( y , f ( x ) )
    结合损失函数及算法模型: 学习加法模型f(x)
    经验风险极小化即损失函数极小化问题
    极小化损失函数模型为: minβm,rmi=1NL(yi,m=1Mβmb(x;,rm) min β m , r m ∑ i = 1 N L ( y i , ∑ m = 1 M β m b ( x ; , r m )

根据前向分布算法将损失函数简化–求每步的损失函数的最小化 那么最终的损失函数就是最小
即: minβ,ri=1NL(yi,βb(x;r)) min β , r ∑ i = 1 N L ( y i , β b ( x ; r ) )

前向分步算法实现步骤

Input: dataSetT=(x1,y1),(x2,y2),....,(xN,yN) d a t a S e t T = ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . . , ( x N , y N ) 损失函数L(y_i, f(x)) 基函数集合{b(x;, r)}
Output: f(x) 加 法 模 型 f ( x )
前向分步算法将: 将同时求解m=1,…,M的所有参数 βm,rm β m , r m 简化为求解各个参数 βm,rm β m , r m 的最优解

具体步骤:

  • step1: 初始化f_0(x) = 0
  • step2: 对M个弱分类器 有m=1,2,…,M轮迭代
    (a) 极小化损失函数
    (\beta_m, r_m) = \arg\min\limits_{\beta, r}\sum\limits_{i=1}^{N}L(y_i, f_{m-1}(x_i) + \beta b(x_i;r)) 得 到 参 数 \beta_m, r_m (b): 分 别 表 示 基 函 数 系 数 以 及 基 函 数 参 数 ( b ) 更 新 : f(x) = f_{m-1}(x) + \beta_m b(x;r_m)$

  • step3: 得出最终模型
    f(x)=fm(x)=m=1M=1βmb(x;rm) f ( x ) = f m ( x ) = ∑ m = 1 M = 1 β m b ( x ; r m )

前向分布算法与AdaBoost

定理: AdaBoost算法是前向分布加法算法的特例, 模型是由基本分类器组成的加法模型
损失函数为指数函数
前向分布算法学习的是加法模型 当基函数为基本分类器时, 该加法模型等价于AdaBoost的最终分类器
f(x)=m=1MαmGm(x) f ( x ) = ∑ m = 1 M α m G m ( x )
损失函数: L(y,f(x))=exp[yf(x)] L ( y , f ( x ) ) = exp [ − y f ( x ) ]

扩展: 证明前向分布算法损失函数是指数损失函数
假设: m-1迭代,前向分布算法已经得到了 fm1(x) f m − 1 ( x )
fm1(x)=f(m2)f(x)+αm1Gm1(x)=alpha1G1(x)+...+αm1Gm1f(x) f m − 1 ( x ) = f ( m − 2 ) f ( x ) + α m − 1 G m − 1 ( x ) = a l p h a 1 G 1 ( x ) + . . . + α m − 1 G m − 1 f ( x )
即: fm(x)=f(m1)(x)+αmGm(x) f m ( x ) = f ( m − 1 ) ( x ) + α m G m ( x )

目标函数: (αm,Gm(x)=argminα,Gi=1Nexp[y(fm1(xi)+αG(xi)] ( α m , G m ( x ) = arg ⁡ min α , G ∑ i = 1 N exp [ − y ( f m − 1 ( x i ) + α G ( x i ) ]
:(alpham,Gm(x))=argminα,Gi=1NWmiexp[yiαG(xi)] 即 为 : ( a l p h a m , G m ( x ) ) = arg ⁡ min α , G ∑ i = 1 N W m i exp [ − y i α G ( x i ) ]
其中 Wmi=exp[yifm1(xi)] W m i = exp [ − y i f m − 1 ( x i ) ] , Wmiα,G,fm1(x) W m i 即 不 依 赖 α , 也 不 依 赖 G , 但 是 与 f m − 1 ( x ) 有 关

接下来证明公式中达到的最小 αmGm(x)AdaBoostαmGmx α m ∗ 和 G m ∗ ( x ) 就 是 A d a B o o s t 算 法 所 得 到 的 α m 和 G m x

  • 1.先求:G_m^*(x),对任意\alpha>0
    Gm(x)=argminα,Gi=1NWmiI(yiG(xi)) G m ∗ ( x ) = arg ⁡ min α , G ∑ i = 1 N W m i I ( y i ≠ G ( x i ) )
    其中: Wmi=exp[yifm1(xi)] W m i = exp [ − y i f m − 1 ( x i ) ]
  • 2.求 αm,i=1NWmiexp[yiαG(xi)]=yi=Gm(xi)Wmiexpα+yiGm(xi)Wmiexpα(expαexpα)i=1NWmiI(yiG(xi))+expαi=1NWmi α m ∗ , ∑ i = 1 N W m i exp [ − y i α G ( x i ) ] = ∑ y i = G m ( x i ) W m i exp − α + ∑ y i ≠ G m ( x i ) W m i exp α ( exp α − exp − α ) ∑ i = 1 N W m i I ( y i ≠ G ( x i ) ) + exp − α ⁡ ∑ i = 1 N W m i

Gmx,α:α=12log1emem G m x 代 入 , 对 α 求 导 : α = 1 2 log ⁡ 1 − e m e m
em,em=i=1NWmiI(yiGm(xi)) e m 是 误 分 类 率 , e m = ∑ i = 1 N W m i I ( y i ≠ G m ( x i ) )
权值更新为: Wmi+1,i=Wmiexp[yiαmGm(xi)] W m i + 1 , i = W m i exp ⁡ [ − y i α m G m ( x i ) ]

提升树原理及实现

提升树原理及实现

提升树是以分类数或回归数为基本分类器的提升方法.提升树被认为是统计学习中性能最好的方法之一

提升树模型

提升数模型实际上采用加法模型(即基函数的线性组合)与前向分步算法,以决策树为基函数的提升方法称为提升树
该基函数模型仅仅略优于随机猜测,因此是使用单层决策树

单层决策树的原理及实现:

单层决策树:decision stump 决策树桩
原理: 仅仅基于单个特征来说决策  实质上只有一次分裂过程 就是个树桩


伪代码实现
将最小错误率minError设置为 正无穷大
对数据集中每一个特征(第一层循环):
    对每个步长(第二层循环):
        对每个不等号(第三层循环):
            建立一颗单层决策树并利用加权数据对它进行测试(错误率)
            如果错误率低于minError,则将当前单层决策树设置为最佳单层决策树
返回最佳单层决策树
import numpy as np

def loadSimpData():
    """ 测试数据
    Returns:
        dataArr   feature对应的数据集
        labelArr  feature对应的分类标签
    """
    dataSet = np.array([[1., 2.1], [2., 1.1], [1.3, 1.], [1., 1.], [2., 1.]])
    labelMat = [1.0, 1.0, -1.0, -1.0, 1.0]
    return dataSet, labelMat


# 建立单层决策树
def stumpTree(dataSet, labelMat, D):
    """
    建立单层决策树
    :param dataSet: 训练数据集   特征值
    :param labelMat: 训练数据集  类别标签
    :param D: 权重值
    :return
        bestStumpTree  最佳单层决策树
    """
    dataMat = np.mat(dataSet)
    labelMat = np.mat(labelMat).T
    m, n = np.shape(dataMat)
    # print('m, n', m, n)
    # print('dataMat:', dataMat)
    # print('labelMat:', labelMat)
    # step1 设置最小误差
    minError = np.inf  # 最小误差率设置为正无穷

    numSteps = 10.0
    bestStump = dict()
    bestClasEst = np.mat(np.zeros((m, 1)))
    # step2 对每一个特征进行循环 计算步长

    # print('训练数据集特征', featureNums)
    for index in range(n):

        # 连续性数据 分类  需要计算步长
        rangeMin = dataMat[:, index].min()
        rangeMax = dataMat[:, index].max()
        delta = (rangeMax - rangeMin) / numSteps
        # step3 第二层循环
        for j in range(-1, int(numSteps)+1):
            # step4 第三层循环 建立一颗单层决策树并利用加权数据对它进行测试(错误率)
            for inequal in ['lt', 'gt']:
                threshVal = (rangeMin + j * delta)
                predictedVals = stumpClassify(dataMat, index, threshVal, inequal)
                # print('predictedVals 结果集', predictedVals)   # matrix 形式的结果集

                # 计算加权错误率 weightedError
                errorMat = np.mat(np.ones((m, 1)))

                errorMat[predictedVals == labelMat] = 0

                weightedError = D.T * errorMat
                # print('index', index)

                if weightedError < minError:
                    minError = weightedError
                    bestClasEst = predictedVals.copy()
                    bestStump['dim'] = index
                    bestStump['thresh'] = threshVal
                    bestStump['ineq'] = inequal

    return bestStump, minError, bestClasEst


def stumpClassify(dataMat, index, threshVal, threshIneq):
    """
    单层决策树分类
    在阈值一边的数据会分到类别-1
    另一边的阈值分到类别1
    首先将全部数组元素设置为1 然后将不满足不等式要求的元素设置为-1
    :param dataMat: 训练数据集 输入空间
    :param index:   训练数据集 特征index
    :param threshVal: 阈值
    :param threshIneq: 小于或大于
    :return
        retArray: 结果集
    """
    # print('try', (np.shape(dataMat))[0])
    dimen = (np.shape(dataMat))[0]
    retArray = np.ones((((np.shape(dataMat))[0]), 1))  # 5x1
    if threshIneq == 'lt':
        retArray[dataMat[:, index] <= threshVal] = -1.0
    else:
        retArray[dataMat[:, index] > threshVal] = -1.0
    return retArray

基于单层决策树的AdaBoost算法实现

伪代码
对每次迭代:
    利用stumpTree()函数找到最佳的单层决策树
    将最佳的单层决策树加入到决策树组
    计算alpha
    计算新的权重向量D
    更新累计类别估计值
    如果错误率==0, 退出循环
def adaBoostTrainDT(dataMat, labelMat, maxCycle):
    """
    基于单层决策树的AdaBoost算法实现
    :param dataMat: 训练数据集   输入空间
    :param labelMat: 训练数据集  输出空间
    :param maxCycle: 最大迭代次数
    :return
        strongDtree 决策数组
    """
    strongDtree = list()
    m, n = np.shape(dataMat)
    # 初始化权重向量D
    D = np.ones((m, 1)) / m
    # print('初始化权重向量D', D)

    upClassEst = np.mat(np.zeros((m, 1)))
    for cycle in range(maxCycle):
        bestStump, minError, bestClasEst = stumpTree(dataMat, labelMat, D)
        # print('predictedVals 结果', bestClasEst)   # 结果

        # 计算 alpha 系数
        alpha = float(0.5 * np.log((1-minError)/max(minError, 0.001)))
        bestStump['alpha'] = alpha
        strongDtree.append(bestStump)

        # 更新D 权重向量
        # 错误分类的加重权重 正确分类的减少权重
        expon = np.multiply(-1*alpha*np.mat(labelMat).T, bestClasEst)
        D = np.multiply(D, np.exp(expon))
        D = D/D.sum()


        # 更新累计类别估计值
        upClassEst += alpha * bestClasEst
        aggError = np.multiply(np.sign(upClassEst) != np.mat(labelMat).T, np.ones((m, 1)))
        errorRate = aggError.sum() / m
        print('errorRate', errorRate)
        if errorRate == 0.0:
            break

    return strongDtree

测试算法及效果

# 测试算法: 基于AdaBoost的分类
def adaClassify(dataToClass, classifierArr):
    """
    基于AdaBoost的强分类器的分类
    :param dataToClass: 输入变量
    :param classifierArr: 强分类器
    :return
        np.sign(aggClassEst) 分类结果
    """
    # do stuff similar to last aggClassEst in adaBoostTrainDS
    dataMat = np.mat(dataToClass)
    m = np.shape(dataMat)[0]

    aggClassEst = np.mat(np.zeros((m, 1)))


    # 循环 多个分类器
    for i in range(len(classifierArr)):
        # 前提: 我们已经知道了最佳的分类器的实例
        # 通过分类器来核算每一次的分类结果,然后通过alpha*每一次的结果 得到最后的权重加和的值。
        classEst = stumpClassify(dataMat, classifierArr[i]['dim'], classifierArr[i]['thresh'],
                                 classifierArr[i]['ineq'])
        aggClassEst += classifierArr[i]['alpha'] * classEst
        print(aggClassEst)
    return np.sign(aggClassEst)


def main():
    dataSet, labelMat = loadSimpData()

    strongDtree = adaBoostTrainDT(dataSet, labelMat, maxCycle=40)
    print('最终分类器:', strongDtree)
    result = adaClassify([[5, 5], [0, 0]], strongDtree)
    print('测试结果:', result)



if __name__ == '__main__':
    main()

提升树-疝气病马预测

def loadDataSet(filename):
    dataSet = list()
    labelMat = list()
    with open(filename, 'r') as f:
        for lines in f.readlines():
            lis = lines.split('\t')
            lineArr = []
            for i in lis[:-1]:
                lineArr.append(float(i))
            # print(lineArr)
            # print(len(lineArr))
            dataSet.append(lineArr)
            labelMat.append(float(lis[-1]))
    print(np.shape(dataSet), type(dataSet[0][0]))  # (299, 21) <class 'float'>
    print(np.shape(labelMat), type(dataSet[0][0]))  # (299, ) <class 'float'>
    return dataSet, labelMat

def main():
    filename = 'horseColicTraining2.txt'
    dataSet, labelMat = loadDataSet(filename)

    strongDtree, aggClassEst = adaBoostTrainDT(dataSet, labelMat, maxCycle=10)
    print('strongDtree', strongDtree)
    print('aggClassEst', aggClassEst)
    plotROC(aggClassEst.T, labelMat)
    filename = 'horseColicTest2.txt'
    testSet, testlabel = loadDataSet(filename)
    predictList = adaClassify(testSet, strongDtree)

    # 测试:计算总样本数,错误样本数,错误率
    m = np.shape(testSet)[0]
    error = np.mat(np.ones((m, 1)))

    print('测试样本个数%s 错误个数%s 错误率%.2f%%' % (m, error[predictList != np.mat(testlabel).T].sum(), error[predictList != np.mat(testlabel).T].sum()/m *100))

参考文献
《统计学习方法》,李航著
《机器学习实战》

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值