AdaBoost算法的理论--(1)

历史上,Kearns和Valiant首先提出了“强可学习(strongly learnable)”和(弱可学习(weakly learnable)”的概念。指出:在概率近似正确(probably approximately
correct,PAC)学习的框架中,一个概念(一个类),如果存在一个多项式的学习
算法能够学习它,并且正确率很高,那么就称这个概念是强可学习的;一个概念,
如果存在一个多项式的学习算法能够学习它,学习的正确率仅比随机猜测略好,那么就称这个概念是弱可学习的。非常有趣的是Schapire后来证明强可学习与弱可学习是等价的,也就是说,在PAC学习的框架下,一个概念是强可学习的充分
必要条件是这个概念是弱可学习的。

当做重要决定时,大家可能都会考虑吸取多个专家而不只是一个人的意见。这就元算法(meta-algorithm)背后的思路。元算法对其他算法进行组合的一种方式。接下来我们将集中关注一个称AdaBoost的最流行的元算法。由于某些人认为AdaBoost是最好的监督学习的方法,所以该方法是机器学习工具箱中最强有力的工具之一。

我们自然可以将不同的分类器组合起来,而这种组合结果则被称为集成方法(ensemble method)或者元算法(meta-algorithm)。使用集成方法时会有多种形式:

  • 不同算法集成
  • 同一算法在不同设置下的集成
  • 数据集不同部分分配给不同分器之后的集成

对于集成方法有两个问题:
(1)在每一轮如何改变训练数据的权重或概率分布;
(2)如何将弱分类器组合成一个强分类器。

1.bagging:基于数据随机重抽样的分类器构建方法

自举汇聚法(bootstrap aggregating),也称为bagging方法,是在从原始数据集选择S次后得到S个新数据集的一种技术。新数据集和原数据集的大小相等。每个数据集都是通过在原始数据集中随机选择一个样本来进行替换而得到的。这里的替换就意味着可以多次地选择同一样本。这一性质就允许新数据集中可以有重复值,而原始数据集的某些值在新集合出现。

在S个数据集建好之后,将某个学习算法分别作用于每个数据集就得到了S个分 器。当我们要对新数据进行分类时,就可以应用这S个分类器进行分类。此同时,选择分类器投票结果中最多的类别作为最后的分类结果。
当然,还有一些更先进bagging方法,比如随机森林(random forest)有关这些方法的一个很讨论材参见网页:
http://www.stat.berkeley.edu/~breiman/RandomForests/cc_home.htm。

2.boosting

提升方法是一种常用的统计学习方法,应用十分广泛且有效。在分类问题中,它通过改变训练样本的权重,学习多个分类器,并将这些分类器进行线性组合,提高分类的性能。提升算法基于这样一种思路:对于一个复杂任务来说,将多个专家的判断进行适当的综合所得出的判断,要比其中任何一个专家独断的判断好。实际上,就是“三个臭皮匠顶个诸葛亮”的道理。

历史上,Kearns和Valiant首先提出了“强可学习(Strongly learnable)”和“弱可学习(Weekly learnable)”的概念。支出:在概率近似正确(probably approximately correct,PAC)学习框架中,
(1)一个概念(一个分类),如果存在一个多项式的学习算法能够学习它,并且正确率很好,那么就称这个概念是强可学习的;
(2)一个概念(一个分类),如果存在一个多项式的学习算法能够学习它,但学习的正确率仅比随机猜测略好,那么就称这个概念是弱可学习的。
非常有趣的是Schapire后来证明强可学习与弱可学习是等价的,也就是说,在PAC学习框架下,一个概念是强可学习的充要条件是这个概念是弱可学习的。

这样一来,问题便成为,在学习中,如果已经发现了“弱学习算法”,那么能否将它提升(boost)为“强学习算法”。大家知道,发现弱学习算法通常要比发现强学习算法容易得多。那么如何具体实施提升,便成为开发提升方法时所要解决的问题。关于提升方法的研究很多,有很多算法被提出,最具代表性的是AdaBoost算法(Adaboost algorithm)。

对与分类问题而言,给定一个训练样本集,求比较粗糙的分类规则(弱分类器)要比求精确的分类规则(强分类器)容易得多。提升方法就是从弱学习算法出发,反复学习,得到一系列分类器,然后组合这些分类器,构成一个强分类器。

这样,对于提升算法来说,有两个问题需要回答:一是在每一轮如何改变训练数据的权值分布;二是如何将弱分类器组合成一个强分类器。

Boosting算法要涉及到两个部分,加法模型和前向分步算法。
(1) 加法模型就是说强分类器由一系列弱分类器线性相加而成。一般组合形式如下:
在这里插入图片描述
其中h(x,θm)h(x,\theta_m)是一个个的弱分类器,θm\theta_m是弱分类器学习到的最优参数;αm\alpha_m就是弱分类在强分类器中所占的比重;P是所有θm\theta_mαm\alpha_m的组合。这些弱分类器线性相加组成强分类器。

(2) 前向分布就是说在训练过程中,下一轮迭代产生的分类器是在上一轮的基础上训练得来的。也就是可以协成这样的形式:
在这里插入图片描述

由于采用的损失函数不同,Boosting算法也因此有了不同的类型,AdaBoost就是损失函数为指数损失的Boosting算法。

boosting是一种与bagging很类似的技术。不论是在boosting还是bagging当中,所使用的多个分类器的类型都是一致的。但是在前者当中,不同的分类器是通过串行训练而获得的,每个新分器都根据已训练出的分类器的性能来进行训练。boosting是通过集中关注被已有分类器错分的那些数据来获得新的分类器。
由于boosting分类的结果是基于所有分类器的加权求和结果的,因此boosting与bagging不太一样。bagging中的分类器权重是相等的,而boosting中的分类器权重并不相等,每个权重代表的是其对应分类器在上一轮迭代中的成功度。
boosting方法拥有多个版本,本章将只关注其中一个最流行的版本AdaBoost。

3.AdaBoost算法

AdaBoost是adaptive boosting(自适应boosting)的缩写,其运行过程如下:
(1)训练数据中的每个样本,并赋予其一个权重,这些权重构成了向量D。一开始,这些权重都初始化成相等值。
(2)在训练数据上训练出一个弱分类器并计算该分类器的错误率,然后在同一数据集上再次训练弱分类器。在分类器的第二次训练当中,将会重新调整每个样本的权重,其中第一次分对的样本的权重将会降低,而第一次分错的样本的权重将会提高。
(3)为了从所有弱分类器中得到最终的分类结果,AdaBoost为每个分类器都分配了一个权重值alpha,这些alpha值是基于每个弱分类器的错误率进行计算的。其中,错误 定义为:
ϵ=\epsilon=\frac{未正确分类的样本数}{所有样本数目}

alpha的计算公式如下:
α=12ln(1ϵϵ)\alpha=\frac12ln(\frac{1-\epsilon}{\epsilon})

Adaboost算法本身是通过改变数据分布来实现的,它根据每次训练集之中每个样本的分类是否正确,以及上次的总体分类的准确率,来确定每个样本的权值。将修改过权值的新数据集送给下层分类器进行训练,最后将每次得到的分类器最后融合起来,作为最后的决策分类器。

AdaBoost的算法流程:
左边是数据集,其中直方图的不同宽度表示每个样例上的不同权重。在经过一个分类器之后,加权的预测结果会通过三角形中的alpha值进行加权。每个三角形 输出的加权结果在圆形中求和,从而得到最终的输出结果。
在这里插入图片描述

计算出alpha值之后,可以对权重向量D进行更新,以使得那些正确分类的样本的权重降低而错分样本的权重升高。D的计算方法如下。
如果某个样本被正确分类,那么该样本的权重更改为
在这里插入图片描述
而如果某个样本被错分,那么该样本的权重更改为:
在这里插入图片描述
在计算出D之后,AdaBoost又开始进入下一轮迭代。AdaBoost算法会不断地重复训练和调整权重的过程,直到训练错误率为0或者弱分类器的数目达到用户的指定值为止。

Adaboost算法思想

  1. 提高那些被前一轮弱分类器错误分类的样本的权值,降低那些被正确分类的样本的权值;
  2. 采用加权多数表决的方法。具体的,加大分类误差率小的弱分类器的权值,使其在表决中起较大的作用;减小分类误差率大的弱分类器的权值,使其在表决中起较小的作用。

Adaboost算法流程
(1)输入:训练数据集T={(x1,y1),(x2,y2),(x3,y3),...,(xn,yn)}T=\{(x_1,y_1),(x_2,y_2),(x_3,y_3),...,(x_n,y_n) \},其中,xiRnorXx_i \in R^n orXyiY={1,+1}y_i \in Y=\{-1,+1\}

(2)输出:最终分类器Gm(x)G_m(x)
(3)初始化:假定第一次训练时,样本均匀分布权值一样。
在这里插入图片描述

其中,w1i=1/n,i=1,2,...,nw_{1i}=1/n,i=1,2,...,n

(4)循环:m=1,2,3…M,

(a)使用具有权值分布DmD_m的训练数据集学习,得到基本分类器GmG_m(选取让误差率最低的阈值来设计基本分类器):
Gm(x):{1,+1}G_m(x):\rightarrow \{-1,+1\}

(b)计算Gm(x)G_m(x)在训练集上的分类误差率eme_m,即分类错误的概率。
在这里插入图片描述
I(Gm(xi))yiI(G_m(x_i) )\neq y_i:当Gm(xi)G_m(x_i)yiy_i相等时,函数取值为0;当与不相等时,取值为1。
由上述式子可知,Gm(x)G_m(x)在训练数据集上的误差率eme_m就是被Gm(x)G_m(x)误分类样本的权值之和。

( c ) 计算Gm(x)G_m(x)的系数αm\alpha_mαm\alpha_m表示Gm(x)G_m(x)在最终分类器中的重要程度:
在这里插入图片描述

【注】显然em1/2e_m \leq1/2时,αm0\alpha_m \geq 0,且αm\alpha_m随着eme_m的减小而增大,意味着分类误差率越小的基本分类器在最终分类器中的作用越大
此时分类器为:
fm(x)=αmGm(x)f_m(x)=\alpha_mG_m(x)

(d)更新训练数据集的权值分布,用于下一轮迭代。
在这里插入图片描述
在这里插入图片描述
其中ZmZ_m是规范化因子,使得Dm+1D_{m+1}成为一个概率分布。

在这里插入图片描述

(5)循环结束条件:

eme_m小于某个阈值(一般是0.5),或是达到最大迭代次数。

AdaBoost 方法中使用的分类器可能很弱(比如出现很大错误率),但只要它的分类效果比随机好一点(比如两类问题分类错误率略小于0.5),就能够改善最终得到的模型。

(6)组合分类器:
在这里插入图片描述

(7)最终分类器:
在这里插入图片描述

4.AdaBoost例子

假定给出下列训练样本。
序号 i 1 2 3 4 5 6 7 8 9 10
数据 x 0 1 2 3 4 5 6 7 8 9
类别标签 y 1 1 1 -1 -1 -1 1 1 1 -1

4.1.初始化

初始化:w1i=1/n=0.1w_{1i}=1/n=0.1,n=10(样本个数)
序号 i 1 2 3 4 5 6 7 8 9 10
数据 x 0 1 2 3 4 5 6 7 8 9
类别标签 y 1 1 1 -1 -1 -1 1 1 1 -1
初始权值 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
阈值猜测:观察数据,可以发现数据分为两类:-1和1,其中数据“0,1,2”对应“1”类,数据“3,4,5”对应“-1”类,数据“6,7,8”对应“1”类,数据“9”对应“"1”类。抛开单个的数据“9”,可以找到对应的数据分界点(即可能的阈值),比如:2.5、5.5、8.5(一般0.5的往上加,也可以是其他数)。然后计算每个点的误差率,选最小的那个作为阈值。

但在实际操作中,可以每个数据点都可以作为阈值,然后计算误差率,保留误差率最小的那个值。若误差率有大于0.5的就取反(分类换一下,若大于取1,取反后就小于取1),再计算误差率。

4.2.迭代过程1:m=1

阈值:变量的取值范围。阈值的确定标准:误差率小的阈值。

(1)确定阈值的取值及误差率

  • 当阈值取2.5时,误差率为0.3。即x<2.5 时取1,x>2.5 时取 -1,则数据6、7、8分错,误差率为0.3(简单理解:10个里面3个错的,真正误差率计算看下面的表格 )
    当阈值取5.5时,误差率最低为0.4。即 x<5.5 时取1,x>5.5 时取 -1,则数据3、4、5、6、7、8分错,错误率为0.6>0.5,故反过来,令x>5.5 取1,x<5.5 时取 -1,则数据0、1、2、9分错,误差率为0.4。
  • 当阈值取8.5时,误差率为0.3。即 x<8.5 时取1,x>8.5 时取 -1,则数据3、4、5分错,错误率为0.3

由上面可知,阈值取2.5 或8.5时,误差率一样,所以可以任选一个作为基本分类器。这里选2.5为例。
在这里插入图片描述

计算误差率:
序号 i 1 2 3 4 5 6 7 8 9 10
数据 x 0 1 2 3 4 5 6 7 8 9
类别标签 y 1 1 1 -1 -1 -1 1 1 1 -1
分类器结果 1 1 1 -1 -1 -1 -1 -1 -1 -1
分类结果 对 对 对 对 对 对 错 错 错 对

从上可得G1(x)G_1(x)在训练数据集上的误差率(被分错类的样本的权值之和):
在这里插入图片描述
(2)计算的系数:
在这里插入图片描述
这个代表G1(x)G_1(x)在最终的分类函数中所占的比重约为0.42365

(3)分类函数
在这里插入图片描述

(4)更新权值分布:
3个G1(x)G_1(x)为1,其他为-1,
在这里插入图片描述
序号 i 1 2 3 4 5 6 7 8 9 10
数据 x 0 1 2 3 4 5 6 7 8 9
类别标签 y 1 1 1 -1 -1 -1 1 1 1 -1
初始权值1 w1i 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
更新权值2 w2i 0.07143 0.07143 0.07143 0.07143 0.07143 0.07143 0.16666 0.16666 0.16666 0.07143

由上面可以看出,因为数据“6,7,8”被分错了,所以它们的权值由初始的0.1增大到了0.16666;其他的数据由于被分对了,所以权值由0.1减小到0.07143。

4.1.3.迭代过程2:m=2

(1)确定阈值的取值及误差率

  • 当阈值取2.5时,误差率为0.49998。即 x<2.5 时取 1,x>2.5 时取 -1,则数据6、7、8分错,误差率为0.16666*3(取过,不列入考虑范围)
  • 当阈值取5.5时,误差率最低为0.28572。即 x<5.5 时取1,x>5.5 时取 -1,则数据3、4、5、6、7、8分错,错误率为0.071433+0.166663=0.71427>0.5,故反过来,令 x>5.5 取 1,x<5.5 时取 -1,则数据0、1、2、9分错,误差率为0.07143*4=0.28572
  • 当阈值取8.5时,误差率为0.21429。即 x<8.5 时取1,x>8.5 时取 -1,则数据3、4、5分错,错误率为0.07143*3=0.21429
    由上面可知,阈值取8.5时,误差率最小,所以:
    在这里插入图片描述

计算误差率:

序号 i 1 2 3 4 5 6 7 8 9 10
数据 x 0 1 2 3 4 5 6 7 8 9
类别标签 y 1 1 1 -1 -1 -1 1 1 1 -1
权值分布  w2i 0.07143 0.07143 0.07143 0.07143 0.07143 0.07143 0.16666 0.16666 0.16666 0.07143
分类器结果 G2(x) 1 1 1 1 1 1 1 1 1 -1
分类结果 对 对 对 错 错 错 对 对 对 对

从上可得G2(x)G_2(x)在训练数据集上的误差率(被分错类的样本的权值之和):
在这里插入图片描述
(2)计算G2(x)G_2(x)的系数:
在这里插入图片描述
这个α2\alpha_2代表G2(x)G_2(x)在最终的分类函数中所占的比重约为0.649263

(3)分类函数
在这里插入图片描述

(4)更新权值分布:

在这里插入图片描述

序号 i 1 2 3 4 5 6 7 8 9 10
数据 x 0 1 2 3 4 5 6 7 8 9
类别标签 y 1 1 1 -1 -1 -1 1 1 1 -1
初始权值1 w1i 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
权值2 w
2i 0.07143 0.07143 0.07143 0.07143 0.07143 0.07143 0.16666 0.16666 0.16666 0.07143
更新权值3 w3i 0.04546 0.04546 0.04546 0.16667 0.16667 0.16667 0.10606 0.10606 0.10606 0.04546

4.1.4.迭代过程3:m=3

(1)确定阈值的取值及误差率

  • 当阈值取2.5时,误差率为0.31818。即 x<2.5 时取 1,x>2.5 时取 -1,则数据6、7、8分错,误差率为0.10606*3=0.31818(取过,不列入考虑范围)
  • 当阈值取5.5时,误差率最低为0.18184。即 x<5.5 时取1,x>5.5 时取 -1,则数据3、4、5、6、7、8分错,错误率为0.166673+0.106063=0.81819>0.5,故反过来,令x>5.5 取 1,x<5.5 时取 -1,则数据0、1、2、9分错,误差率为0.04546*4=0.18184
  • 当阈值取8.5时,误差率为0.13638。即 x<8.5 时取1,x>8.5 时取 -1,则数据3、4、5分错,错误率为0.04546*3=0.13638(取过,不列入考虑范围)
    由上面可知,阈值取8.5时,误差率最小,但8.5取过了,所以取5.5:
    在这里插入图片描述

计算误差率:

序号 i 1 2 3 4 5 6 7 8 9 10
数据 x 0 1 2 3 4 5 6 7 8 9
类别标签 y 1 1 1 -1 -1 -1 1 1 1 -1
权值分布  w3i 0.04546 0.04546 0.04546 0.16667 0.16667 0.16667 0.10606 0.10606 0.10606 0.04546
分类器结果 G3(x) -1 -1 -1 -1 -1 -1 1 1 1 1
分类结果 错 错 错 对 对 对 对 对 对 错

从上可得G3(x)G_3(x)在训练数据集上的误差率(被分错类的样本的权值之和):
在这里插入图片描述

(2)计算G3(x)G_3(x)的系数:
在这里插入图片描述
这个α3\alpha_3代表G3(x)G_3(x)在最终的分类函数中所占的比重约为0.75197。

(3)分类函数
在这里插入图片描述

(4)更新权值分布:

在这里插入图片描述

序号 i 1 2 3 4 5 6 7 8 9 10
数据 x 0 1 2 3 4 5 6 7 8 9
类别标签 y 1 1 1 -1 -1 -1 1 1 1 -1
初始权值1 w1i 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
权值2 w2i 0.07143 0.07143 0.07143 0.07143 0.07143 0.07143 0.16666 0.16666 0.16666 0.07143
权值3 w3i 0.04546 0.04546 0.04546 0.16667 0.16667 0.16667 0.10606 0.10606 0.10606 0.04546
更新权值4 w4i 0.12500 0.12500 0.12500 0.10185 0.10185 0.10185 0.06481 0.06481 0.06481 0.12500

4.1.5.迭代过程4:m=4

此时观察数据,每次迭代被分错的数据都已经重新分配过权值,按其他参考资料来说,此时的误差率为0,所以迭代可以到此结束。

最终分类器:
在这里插入图片描述

6.代码

单层决策树(decision stump , 也称决策树桩)是一种简单的决策树。前面我们已经介绍决策树的工作原理,接下来将构建一个单层决策树,而它仅基於单个特征来做决策。由于这棵树只有一次分裂过程,因此它实际上就是一个树桩。

完整AdaBoost算法的实现

6.1.简单数据

# coding: utf-8
# Author: shelley
# 2020/5/1311:42
# -*- coding: utf-8 -*-

import numpy as np
import matplotlib.pyplot as plt


def loadsimpData():
    """
    创建单层决策树的数据集
    :return:
    dataMat - 数据矩阵
    classLabels - 数据标签
    """
    datMat = np.matrix([[1., 2.1],
                        [1.5, 1.6],
                        [1.3, 1.],
                        [1., 1.],
                        [2., 1.]])
    classLabels = [1.0, 1.0, -1.0, -1.0, 1.0]
    return datMat, classLabels


def stumpClassify(dataMatrix, dimen, threshVal, threshIneq):
    """
    单层决策树分类函数
    :param dataMatrix: 数据矩阵
    :param dimen: 第dimen列,也就是第几个特征
    :param threshVal: 阈值
    :param threshIneq: 标志
    :return: 分类结果
    """
    # 初始化retArray为全1列向量
    retArray = np.ones((np.shape(dataMatrix)[0], 1))
    if threshIneq == 'lt':
        # 如果小于阈值则赋值为-1
        retArray[dataMatrix[:, dimen] <= threshVal] = -1.0
    else:
        # 如果大于阈值则赋值为-1
        retArray[dataMatrix[:, dimen] > threshVal] = -1.0
    return retArray


def buildStump(dataArr, classLabels, D):
    """
    找到数据集上最佳的单层决策树
    :param dataArr: 数据矩阵
    :param classLabels: 数据标签
    :param D: 样本权重,每个样本权重相等 1/n
    :return:
    bestStump - 最佳单层决策树信息
    minError - 最小误差
    bestClassEst - 最佳的分类结果
    """
    # 输入数据转为矩阵(5, 2)
    dataMatrix = np.mat(dataArr)
    # 将标签矩阵进行转置(5, 1)
    labelMat = np.mat(classLabels).T
    # m=5, n=2
    m, n = np.shape(dataMatrix)
    numSteps = 10.0
    bestStump = {}
    # (5, 1)全零列矩阵
    bestClasEst = np.mat(np.zeros((m, 1)))
    # 最小误差初始化为正无穷大inf
    minError = float('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):
            # 大于和小于的情况均遍历,lt:Less than  gt:greater than
            for inequal in ['lt', 'gt']:
                # 计算特征的阈值
                threshVal = (rangeMin + float(j) * stepSize)
                # 计算分类结果
                predictedVals = stumpClassify(dataMatrix, i, threshVal, inequal)
                # 初始化误差矩阵
                errArr = np.mat(np.ones((m, 1)))
                # 分类正确的,赋值为0
                errArr[predictedVals == labelMat] = 0
                # 计算误差
                weightedError = D.T * errArr
                print("分裂: 维度:%d, 阈值:%.2f, 阈值不等类别: %s, 权重错误是:%.3f" % (
                i, threshVal, inequal, weightedError))
                # 找到误差最小的分类方式
                if weightedError < minError:
                    minError = weightedError
                    bestClasEst = predictedVals.copy()
                    bestStump['dim'] = i
                    bestStump['thresh'] = threshVal
                    bestStump['ineq'] = inequal
    return bestStump, minError, bestClasEst


def adaBoostTrainDS(dataArr, classLabels, numIt=40):
    """
    使用AdaBoost进行优化
    :param dataArr: 数据矩阵
    :param classLabels: 数据标签
    :param numIt: 最大迭代次数
    :return:
    weakClassArr - 存储单层决策树的list
    aggClassEsc - 训练的label
    """
    weakClassArr = []
    # 获取数据集的行数
    m = np.shape(dataArr)[0]
    # 样本权重,每个样本权重相等,即1/m
    D = np.mat(np.ones((m, 1)) / m)
    # 初始化为全零列
    aggClassEst = np.mat(np.zeros((m, 1)))
    # 迭代
    for i in range(numIt):
        # 构建单层决策树
        bestStump, error, classEst = buildStump(dataArr, classLabels, D)
        # print("D:", D.T)
        # 计算弱学习算法权重alpha,使error不等于0,因为分母不能为0
        alpha = float(0.5 * np.log((1.0 - error) / max(error, 1e-16)))
        # 存储弱学习算法权重
        bestStump['alpha'] = alpha
        # 存储单层决策树
        weakClassArr.append(bestStump)
        # 打印最佳分类结果
        # print("classEst: ", classEst.T)
        # 计算e的指数项
        expon = np.multiply(-1 * alpha * np.mat(classLabels).T, classEst)
        # 计算递推公式的分子
        D = np.multiply(D, np.exp(expon))
        # 根据样本权重公式,更新样本权重
        D = D / D.sum()
        # 计算AdaBoost误差,当误差为0的时候,退出循环
        # 以下为错误率累计计算
        aggClassEst += alpha * classEst
        # print("aggClassEst: ", aggClassEst.T)
        # 计算误差
        aggErrors = np.multiply(np.sign(aggClassEst) != np.mat(classLabels).T, np.ones((m, 1)))
        errorRate = aggErrors.sum() / m
        # print("total error:", errorRate)
        if errorRate == 0.0:
            # 误差为0退出循环
            break
    return weakClassArr, aggClassEst

def adaClassify(datToClass, classifierArr):
    """
    AdaBoost分类函数
    :param datToClass: 待分类样例
    :param classifierArr: 训练好的分类器
    :return: 分类结果
    """
    dataMatrix = np.mat(datToClass)
    m = np.shape(dataMatrix)[0]
    aggClassEst = np.mat(np.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 np.sign(aggClassEst)


def showDataSet(dataMat, labelMat):
    """
    数据可视化
    :param dataMat: 数据矩阵
    :param labelMat: 数据标签
    :return:
    """
    # 正样本
    data_plus = []
    # 负样本
    data_minus = []
    for i in range(len(dataMat)):
        if labelMat[i] > 0:
            data_plus.append(dataMat[i])
        else:
            data_minus.append(dataMat[i])
    # 转换为numpy矩阵
    data_plus_np = np.array(data_plus)
    # 转换为numpy矩阵
    data_minus_np = np.array(data_minus)
    # 正样本散点图(scatter)
    # transpose转置
    plt.scatter(np.transpose(data_plus_np)[0], np.transpose(data_plus_np)[1])
    # 负样本散点图(scatter)
    plt.scatter(np.transpose(data_minus_np)[0], np.transpose(data_minus_np)[1])
    # 显示
    plt.show()


if __name__ == '__main__':
    dataArr, classLabels = loadsimpData()
    weakClassArr, aggClassEst = adaBoostTrainDS(dataArr, classLabels)
    print(adaClassify([[0, 0], [5, 5]], weakClassArr))
    # print('weakClassArr:\n', weakClassArr)
    # print('aggClassEst:\n', aggClassEst)
    # showDataSet(dataArr, classLabels)

6.2.sklearn

# coding: utf-8
# Author: shelley
# 2020/5/1311:43
# -*- coding: utf-8 -*-


import numpy as np
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier


def loadDataSet(fileName):
    """
    加载文件
    :param fileName: 文件名
    :return:
    dataMat - 数据矩阵
    labelMat - 数据标签
    """
    # 特征个数
    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


from sklearn.svm import SVC

if __name__ == '__main__':
    dataArr, classLabels = loadDataSet('horseColicTraining2.txt')
    testArr, testLabelArr = loadDataSet('horseColicTest2.txt')
    # bdt = AdaBoostClassifier(DecisionTreeClassifier(max_depth=2), algorithm="SAMME", n_estimators=10)
    bdt = AdaBoostClassifier(SVC(C=200.0, kernel='rbf'), algorithm="SAMME", n_estimators=10)
    bdt.fit(dataArr, classLabels)
    predictions = bdt.predict(dataArr)
    errArr = np.mat(np.zeros((len(dataArr), 1)))
    for i in range(len(classLabels)):
        if classLabels[i] != predictions[i]:
            errArr[i] = 1
    print('训练集的错误率:%.3f%%' % float(errArr.sum() / len(dataArr) * 100))
    predictions = bdt.predict(testArr)
    errArr = np.mat(np.zeros((len(testArr), 1)))
    for i in range(len(testLabelArr)):
        if testLabelArr[i] != predictions[i]:
            errArr[i] = 1
    print('测试集的错误率:%.3f%%' % float(errArr.sum() / len(testArr) * 100))

# 训练集的错误率:0.334%
# 测试集的错误率:28.358%

7.代码和数据

链接:https://pan.baidu.com/s/1QbeG8g_9JhVwJRhERViTMg
提取码:80su

github:
https://github.com/shelleyHLX/machine-learning

8.参考

机器学习实战
一些博客,如有侵权,请联系。
https://www.cnblogs.com/liuq/p/9927580.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章