美文网首页
(十 七)boosting\adaBoosting--迭代算法

(十 七)boosting\adaBoosting--迭代算法

作者: 羽天驿 | 来源:发表于2020-04-07 08:35 被阅读0次

    一、原理的描述

    Adaboost是一种迭代算法,其核心思想是针对同一个训练集训练不同的分类器(弱分类器),然后把这些弱分类器集合起来,构成一个更强的最终分类器(强分类器)。其算法本身是通过改变数据分布来实现的,它根据每次训练集之中每个样本的分类是否正确,以及上次的总体分类的准确率,来确定每个样本的权值。将修改过权值的新数据集送给下层分类器进行训练,最后将每次训练得到的分类器最后融合起来,作为最后的决策分类器。使用adaboost分类器可以排除一些不必要的训练数据特徵,并将关键放在关键的训练数据上面。


    • 三个臭皮匠,赛过诸葛亮
    • 参考文章一
    • 参考文章二
    • 1.用大量的<font color =red>病例 == X == 样本</font>让这些<font color = red>新手 == model</font>依次学习,每个<font color = red>大夫 == model == 算法</font>自己琢磨怎样诊断,学习结束后统计一下每个人在这些病例上的诊断准确率
      2.训练时,前面的大夫<font color = red>误诊</font>的病例,后面的大夫要<font color = red>重点学习研究 == 样本权重加大 == w</font>,所谓查缺补漏
      3.训练结束之后,给每个大夫打分,如果一个大夫对病例学习的误诊率越低,也就是说在这些学习的病例集上诊断的准确率越高,这名大夫在后面诊断病人时的<font color = green>话语权就越大 == 权重大 == \alpha偏大</font>
    • 诊断过程
      • 一个病人之后,8个大夫一起诊断,然后投票。如果一个大夫之前在学习时的诊断准确率为p,误差率e = 1-p,他在投票时的话语权是:
      • \alpha = \frac{1}{2}ln\frac{p}{1-p}
      • \alpha = \frac{1}{2}ln\frac{1-e}{e} = \frac{1}{2}ln\frac{p}{1-p}
      • [图片上传失败...(image-81730-1586219732552)]
      • 赵大夫的结果 == 模型预测值
    • Adabooting概述
      • AdaBoost算法是一种集成学习(ensemble learning)方法。集成学习是机器学习中的一类方法,它对多个机器学习模型进行组合形成一个<font color = red>精度更高的模型就是强学习器</font>,参与组合的模型称为<font color = red>弱学习器(weak learner)</font>。在预测时使用这些弱学习器模型联合起来进行预测;训练时需要用训练样本集依次训练出这些弱学习器。典型的集成学习算法是随机森林和boosting算法,而AdaBoost算法是boosting算法的一种实现版本。
      • F(x) = \sum\limits_{t = 1}^N\alpha_tf_t(x),其中\alpha_t是第t个模型的权重,f_t(x)第t个弱学习器的预测
      • 分类是判定规则:
      • sgn(F(x))表示F(x) 大于0结果正的,如果F(x)小于0,结果就是负的(算法原理基于二分类)
      • sgn(F(x)) = \left\{\begin{aligned}+1,x>0\\-1,x<=0\end{aligned}\right.
    • 算法梳理:
      • w^0 = \frac{1}{m},1,2,3,……,m
      • 训练弱学习器,计算误差率e,可以计算准确率p ,p + e = 1
      • 弱学习器的权重\alpha_t = \frac{1}{2}ln\frac{1-e_t}{e_t} = \frac{1}{2}ln\frac{p_t}{1-p_t}
      • w^t = [w^{t-1}*exp(-yf_t(x)\alpha_t)] 没有进行归一化
      • Z_t是归一化因子
      • Z_t = \sum\limits_{i=1}^mw_i^t
      • w^t = w^t/Z_t 归一化
    • Adaboosting中的A是adaptive的意思,所以AdaBoosting表示自适应增强算法

    二、主要解决的问题

    (1) 二分类,多类单标签问题、多类多标签问题、大类单标签问题
    (2)回归问题

    三、整体的流程:

    1. 先通过对N个训练样本的学习得到第一个弱分类器 ;
    2. 将 分错的样本和其他的新数据一起构成一个新的N个的训练样本,通过对这个样本的学习得到第二个弱分类器 ;
    3. 将 和 都分错了的样本加上其他的新样本构成另一个新的N个的训练样本,通过对这个样本的学习得到第三个弱分类器 ;
    4. 最终经过提升的强分类器 。即某个数据被分为哪一类要通过 , ……的多数表决。

    注意:每一次都会更新样本的权重(数据的划分正确,降低该样本的权重,数据划分错误就增大它的权重)---》计算该弱分类器的误差率--》更新公式---》再根据公式更新下一轮的样本的权重。


    通过以上的操作----经过T次的循环。就得到了最终想要的强分类器。


    具体的公式及详细说明如下:


    adaboosting算法.png
    adaboosting中的Zt是什么.png

    每次迭代都是选择相同的模型,上面的ht(x)表示的是弱学习器,前面的αt表示的是该弱学习器的权重。


    强学习器.png

    多个弱学习器经过多次的迭代,最终得到的就是强学习器H(x)。
    其中:sign代表的是符号函数
    其最终返回的是那种分类


    数学符号函数.png

    四、adaboosting简单的算法案例


    ```python
    from sklearn.ensemble import AdaBoostClassifier
    import numpy as np
    from sklearn import tree
    

    生成数据

    X = np.arange(10).reshape(-1,1)
    y = np.array([1,1,1,-1,-1,-1,1,1,1,-1])
    y
    
    array([ 1,  1,  1, -1, -1, -1,  1,  1,  1, -1])
    

    声明算法,进行训练

    # {'SAMME', 'SAMME.R'}
    ada = AdaBoostClassifier(algorithm='SAMME',n_estimators=3)
    ada.fit(X,y)
    
    AdaBoostClassifier(algorithm='SAMME', base_estimator=None, learning_rate=1.0,
                       n_estimators=3, random_state=None)
    

    第一棵树划分

    y# 4个1 ----> 比例0.4,6个-1 ----> 比例 0.6 gini = 0.4*(1-0.4) + 0.6*(1-0.6) = 0.48
    
    array([ 1,  1,  1, -1, -1, -1,  1,  1,  1, -1])
    
    _ = tree.plot_tree(ada[0])
    ada[0].predict(X)#第一棵树的预测值,怎么预测呢?
    
    array([ 1,  1,  1, -1, -1, -1, -1, -1, -1, -1])
    
    output_7_1.png

    第一棵树,手动计算,划分

    # 样本的初始权重,还没有开始进行训练,所以,所有样本权重一样?
    w1 = np.full(shape = 10,fill_value=0.1)
    w1
    
    array([0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1])
    
    X # 样本中10个数据,划分,0到1之间(threshold阈值0.5)划分;1到2之间(1.5)划分……
    # X <= threshold 类别1 阳性 说明不好
    # X > threshold 类别-1 阴性 说明健康
    
    array([[0],
           [1],
           [2],
           [3],
           [4],
           [5],
           [6],
           [7],
           [8],
           [9]])
    
    # numpy中的最基本逻辑运算
    # 数据分析的三剑客:numpy、pandas、matplotlib
    c = y != y1#算数计算的时候,False = 0,True = 1
    print(c)
    print(c.astype(np.int8))
    # 之前讲分类算法,模型评估,使用准确率
    # accuracy = (y == y_).mean()
    
    [False  True  True False False False  True  True  True False]
    [0 1 1 0 0 0 1 1 1 0]
    
    # 如果阈值0.5,构建树,结果:
    y1 = np.array([1,-1,-1,-1,-1,-1,-1,-1,-1,-1]) #预测结果
    e1 = ((y != y1)*d1).sum()#误差
    print('方式一',e1)
    e1 = (y != y1).mean()
    print('方式二',e1)
    # 如果阈值1.5,构建树,结果:
    y2 = np.array([1,1,-1,-1,-1,-1,-1,-1,-1,-1])
    e2 = ((y != y2)*d1).sum()
    print('方式一',e2)
    e2 = (y != y2).mean()
    print('方式二',e2)
    
    方式一 0.5
    方式二 0.5
    方式一 0.4
    方式二 0.4
    
    # 第一颗树划分时,阈值选择了2.5?
    # 决策树的裂分,有一个标准!
    # for 循环目的:找到分类条件:2.5或者8.5
    thresholds = np.arange(0.5,10)
    for i,t in enumerate(thresholds,start = 1):#enumerate,获取索引,默认从0开始, 
    #     y_是弱分类器,预测值
        y_ = np.array([1]*i + [-1]*(10-i))
    #     y_ = np.zeros(shape = 10)
    #     y_[(X <=t).reshape(-1)] = 1
    #     y_[(X > t).ravel()] = -1
        print(t,((y !=y_)*w1).sum())
    
    0.5 0.5
    1.5 0.4
    2.5 0.30000000000000004
    3.5 0.4
    4.5 0.5
    5.5 0.6
    6.5 0.5
    7.5 0.4
    8.5 0.30000000000000004
    9.5 0.4
    

    根据输出的结果,结论,阈值是2.5或者8.5,误差最小的:0.3

    选择2.5或者8.5作为裂分条件,代码中一般选择,前面的索引

    # 计算第一个弱学习器的权重,相当于大夫的话语权
    e1 = 0.3
    a1 = 1/2*np.log((1 -e1)/e1 )
    print('计算第一个弱学习器的权重:',a1)
    
    计算第一个弱学习器的权重: 0.42364893019360184
    

    更新样本的权重

    # 在w1的基础上,进行更新 w1 = [0.1,0.1,0.1……]
    y_ = np.array([1]*3 + [-1]*(10-3))
    w2 = w1*np.exp(-y*y_*a1)
    w2 = w2/w2.sum()
    print(w2)
    
    [0.07142857 0.07142857 0.07142857 0.07142857 0.07142857 0.07142857
     0.16666667 0.16666667 0.16666667 0.07142857]
    

    第二棵树划分

    _ = tree.plot_tree(ada[1])#样本权重,发生变化了
    
    output_19_0.png

    手动计算,第二棵树的划分

    第二棵树,根据第一棵树的返回结果,进行,学习

    第一棵树,更新了样本的权重!w2

    thresholds = np.arange(0.5,10)
    for i,t in enumerate(thresholds,start = 1):#enumerate,获取索引,默认从0开始, 
    #     y_是弱分类器,预测值
        y_ = np.array([1]*i + [-1]*(10-i))
    #     y_ = np.zeros(shape = 10)
    #     y_[(X <=t).reshape(-1)] = 1
    #     y_[(X > t).ravel()] = -1
        print(t,((y !=y_)*w2).sum())
    
    0.5 0.6428571428571428
    1.5 0.5714285714285714
    2.5 0.5
    3.5 0.5714285714285714
    4.5 0.6428571428571428
    5.5 0.7142857142857142
    6.5 0.5476190476190476
    7.5 0.38095238095238093
    8.5 0.21428571428571425
    9.5 0.28571428571428564
    
    # 阈值,如果是8.5,那么左边9个数,右边是1个数,计算误差率
    y_ = np.array([1]*9 + [-1]*(10-9))#预测值
    display(y,y_)
    e2 = ((y != y_)*w2).sum()
    print('第二棵树的误差率:',e2)
    print('样本的权重是:',w2.round(4))
    #计算第二棵树的权重
    a2 =np.round( 1/2*np.log((1 - e2)/e2),4)
    print('第二棵树,权重是:',a2)
    
    array([ 1,  1,  1, -1, -1, -1,  1,  1,  1, -1])
    
    
    
    array([ 1,  1,  1,  1,  1,  1,  1,  1,  1, -1])
    
    
    第二棵树的误差率: 0.21428571428571425
    样本的权重是: [0.0714 0.0714 0.0714 0.0714 0.0714 0.0714 0.1667 0.1667 0.1667 0.0714]
    第二棵树,权重是: 0.6496
    

    更新第二棵树的样本的权值分布,根据第一棵树的结果w2进行更新

    y_ = np.array([1]*9 + [-1]*(10-9))#预测值
    w3 = w2*np.exp(-y*y_*a2)
    w3 = w3/w3.sum()
    print('第二棵树,更新样本权重,更新样本分布:',w3)
    
    第二棵树,更新样本权重,更新样本分布: [0.04545643 0.04545643 0.04545643 0.16665975 0.16665975 0.16665975
     0.10606501 0.10606501 0.10606501 0.04545643]
    

    第三棵树划分

    _ = tree.plot_tree(ada[2])
    
    output_26_0.png
    thresholds = np.arange(0.5,10)
    for i,t in enumerate(thresholds,start = 1):#enumerate,获取索引,默认从0开始, 
    #     y_是弱分类器,预测值
        y_ = np.array([1]*i + [-1]*(10-i))
    #     y_ = np.zeros(shape = 10)
    #     y_[(X <=t).reshape(-1)] = 1
    #     y_[(X > t).ravel()] = -1
        print(t,((y !=y_)*w3).sum())#误差率 + 准确率 = 1
    
    0.5 0.40910788311754365
    1.5 0.36365145166003876
    2.5 0.318195020202534
    3.5 0.4848547715250161
    4.5 0.6515145228474983
    5.5 0.8181742741699806
    6.5 0.7121092674358026
    7.5 0.6060442607016245
    8.5 0.4999792539674466
    9.5 0.5454356854249515
    
    e3 = 0.1820
    # 计算第三棵树的权重
    y_ = np.array([-1]*6 + [1]*(10-6))
    a3 = 1/2*np.log((1 - e3)/e3)
    print('第三棵树的权重是:',a3)
    # 更新第三棵树的,样本权值分布,权重
    w4 = w3*np.exp(-y*y_*a3)
    w4 = w4/w4.sum()
    print('第三棵树,更新样本权重:',w4.round(3))
    
    第三棵树的权重是: 0.7514278247629759
    第三棵树,更新样本权重: [0.125 0.125 0.125 0.102 0.102 0.102 0.065 0.065 0.065 0.125]
    

    集成算法

    F(x) = \sum\limits_{t = 1}^N\alpha_tf_t(x)

    print(a1,a2,a3)
    
    0.42364893019360184 0.6496 0.7514278247629759
    
    # 第一棵树ft(x)
    y1 = np.array([1]*3 + [-1]*(10-3))
    # 第二棵树的预测值
    y2 = np.array([1]*9 + [-1]*(10-9))#预测值
    # 第三棵树,预测值
    y3 = np.array([-1]*6 + [1]*(10-6))
    F =  a1*y1 + a2*y2 + a3*y3
    # 将多个弱分类器,整合,变成了强分类器F(X)
    F
    
    array([ 0.32182111,  0.32182111,  0.32182111, -0.52547675, -0.52547675,
           -0.52547675,  0.97737889,  0.97737889,  0.97737889, -0.32182111])
    
    # 上面的result使我们手动计算的。
    result = [-1 if i <0 else 1  for i in F]
    result
    
    [1, 1, 1, -1, -1, -1, 1, 1, 1, -1]
    
    # 这个模型预测的返回值
    ada.predict(X)
    
    array([ 1,  1,  1, -1, -1, -1,  1,  1,  1, -1])
    
    # 类别 0,1,2目标值有3个类别
    y = np.array([1,1,2,0])
    # 二进制编码,3个数的二进制,刚好可以表示,3个类别,one-hot:独热编码
    y_ = np.array([[0,1,0],
                   [0,1,0],
                   [0,0,1],
                   [1,0,0]])
    
    
    
    ********
    **以上部分内容参考自博客**[https://blog.csdn.net/ben_ben_niao/article/details/47277035](https://blog.csdn.net/ben_ben_niao/article/details/47277035)
    

    相关文章

      网友评论

          本文标题:(十 七)boosting\adaBoosting--迭代算法

          本文链接:https://www.haomeiwen.com/subject/bvuruhtx.html