python实现AdaBoost算法

★  AdaBoost的理解:

      对于二分类而言,我们通过一个阈值threshVal将数据集划分为两种分类(正类和负类),而这个阈值就是我们所说的分割线,只不过它总是平行于坐标轴(因为我们取的基分类器是单层决策树):

python实现AdaBoost算法_第1张图片  python实现AdaBoost算法_第2张图片

       对于上述数据集,一个基分类器即可将其分类,但是对于大多数训练集而言,一个基分类器是不足够的,比如:

python实现AdaBoost算法_第3张图片  python实现AdaBoost算法_第4张图片

         在图3中,我们找不到一条平行于坐标轴的直线将数据集正确的划分,因此我们使用了3个基分类器将其分开,由图4看出,3个分类器把数据集分成6个部分,每一部分我们公式sign(\pm \alpha _{1}\pm \alpha _{2}\pm ...\pm \alpha _{m})计算出来它是正类还是负类,比如对第①部分:sign(-0.69+0.8-0.97)=-1,所以第①部分是负类(蓝色点就是负类),再比如第⑥部分:sign(0.69-0.8+0.97)=1,所以第⑥部分是正类(红色点就是正类)。依次计算这6个部分,画出图来就是:

python实现AdaBoost算法_第5张图片

         由图我们可以看出,橘红色部分(②,③,⑥)是正类,绿色部分(①,④,⑤)是负类。

★ AdaBoost 分类器简介:

       adaboost 就是把几个弱分类器,通过线性组合,组合成强分类器,它在训练集上有很高的准确率,但是在测试集上效果却没有那么好,因为它是逐步优化分错的样本,所以最终分类误差率会降到很低,这个组合分类器的数学描述是:

                                 f(x)=\alpha _{1}G_{1}(x)+...+\alpha _{m}G_{m}(x)                                              ①

       其中m是分类器个数,也就是当组合m个弱分类器后,误差率能满足我们的要求。

        \alpha _{i}\; \; \; i=1,...,m 代表着该分类器的重要程度。

★ AdaBoost 算法流程:

      (1) 初始化权值,每一个训练样本最开始时都被赋予相同的权值:1/N (N是样本个数),它代表着开始时每个样本的重要性都是相等的。

               D_{1}=(w_{1,1},w_{1,2},...,w_{1,N})\; \; \; \; w_{1,i}=\frac{1}{N},\; \; i=1,2,...,N                           ②

       我们经过每一次的迭代,上述权值会不断变化,但初始时各权值是相等的。

     (2) 使用具有权值分布D_{m}的训练数据集学习,得到基本分类器(分类器可以选择SVM,决策树等,后面我们选择最简单的单层决策树作为基分类器):

                      G_{m}(x):\; \; \; \; \; \chi \rightarrow\begin{Bmatrix} -1,+1 \end{Bmatrix}

          这里G_{m}就是第m个基分类器,它的取值只有-1或者+1。

     (3) 计算G_{m} 在训练集上的分类误差率:

                e_{m}=P(G_{m}(x_{i})\neq y_i)=\frac{\sum _{G_{m}(x_{i})\neq y_{i}}w_{m,i}}{\sum _{i=1}^{N}w_{m,i}}=\sum_{i=1}^{N}w_{m,i}\cdot I(G_{m}(x_{i})\neq y_{i})                       ③

        其中:e_{m}是第m个分类器G_{m}的分类误差率,就是分类器G_{m}分错的概率。

                    w_{m,i} 是第m个分类器G_{m}在数据集x上使用的每个样本的权值,跟公式②的 w_{1,i} 一个意思

                    G_{m}(x_{i})是第m个分类器对第i个样本的预测分类。它的取值是-1或+1

                    y_{i} 是第i个样本真实的分类。对于二分类来说,它的取值也是-1或+1

                    I(G_{m}(x_{i})=y_{i})当括号里面条件为true的时候取值为1,反之,为false的时候取值为0,这里I 可不是单位矩阵哈

     (4) 计算G_{m}(x)的系数\alpha _{m}\alpha _{m}代表着该分类器的重要程度,当这个分类器的分类误差率越低的时候,\alpha _{m}就越大。

                               \alpha _{m}=\frac{1}{2}\cdot ln\frac{1-e_{m}}{e_{m}}                                ④

            从上式④可以看出,分类误差率e_{m}越小,\alpha _{m}就越大,对应的分类器就越重要。

     (5) 更新每个样本的权值:

                     D_{m+1}=(w_{m+1,1},w_{m+1,2},...,w_{m+1,N})

                     w_{m+1,i}=\frac{w_{m,i}\cdot e^{-\alpha _{m}y_{i}G_{m}(x_{i})}}{Z_m}\; \;\;\; \; \; \; \; \; \; i=1,...,N                 ⑤

         其中: D_{m+1} 是第m+1个分类器的各样本点权值分布

                      w_{m+1,i} 是第m+1个分类器的样本点权值的更新规则。

                      Z_{m}是归一化因子,他其实就是分子的和。

                            Z_{m}=\sum_{i=1}^{N}(w_{m,i}\cdot e^{-\alpha _{m}y_{i}G_{m}(x_{i})})=(\sum _{G_{m}(x_{i})=y_{i}}w_{m.i}\cdot e^{-\alpha _{m}})+(\sum _{G_{m}(x_{i})\neq y_{i}}w_{m.i}\cdot e^{\alpha _{m}})

                                   =(1-e_{m})\cdot e^{-\alpha _{m}}+e_{m}\cdot e^{\alpha _{m}}=(1-e_{m}\cdot e^{-\frac{1}{2}ln\frac{1-e_{m}}{e_{m}}})+e_{m}\cdot e^{\frac{1}{2}ln\frac{1-e_{m}}{e_{m}}}

                                   =2\sqrt{(1-e_{m})\cdot e_{m}}                                 ⑥

           上式的公式⑥是有公式③、④代入得到的。

   (6) 线性组合各弱分类器:

                     f(x)=\alpha _{1}G_{1}(x)+...+\alpha _{m}G_{m}(x)=\sum _{m=1}^{M}\alpha _{m}\cdot G_{m}(x)            ⑦

        得到最终的分类器:

                    G(x)=sign(f(x))=sign(\sum _{m=1}^{M}\alpha _{m}\cdot G_{m}(x))                            ⑧

★ AdaBoost 算法的解释:

      证明 AdaBoost 的损失函数是指数函数:(可通过前向分布算法来推adaboost,只要证明前向分布算法与adaboost都是加法模型,并当前向分布算法取指数损失函数时就是adaboost,那么就证明了adaboost使用的是指数损失函数)

      ✿ 首先我们先来看一下前向分布算法:

        前向分布算法的加法模型是:

                                                    f(x)=\sum _{m=1}^{M}\beta _{m}\cdot b(x;\gamma _{m})                          ⑨

        其中,b(x;\gamma _{m})为基函数,\gamma _{m} 为基函数的参数,\beta _{m}为基函数的系数,M是基分类器个数由公式⑦可以看出,adaboost也是一个加法模型。

        假设前向分布算法的损失函数是L(y,f(x)),那么算法的目标函数就是极小化损失函数:

                     \begin{matrix}min\; \sum_{i=1}^{N}L(y_{i},f(x))= min\; \sum_{i=1}^{N}L(y_{i},\sum _{m=1}^{M}\beta _{m}\cdot b(x_{i};\gamma _{m}))\\ \beta _{m} ,\gamma _{m}\; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \beta _{m} ,\gamma _{m}\; \; \; \; \; \; \; \; \; \; \; \;\; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \end{matrix}                   ⑩

        上式中的N是样本个数。

        前向分布算法求解这一优化问题的思想是:因为该学习是加法模型,如果能够从前向后,每一步只学习一个基函数及其系数,逐步逼近优化目标函数式⑩,那么就可以简化该优化问题的复杂度,因此每一步只需优化如下损失函数(即优化每一个基分类器的损失函数):

                           \begin{matrix} min\; \sum_{i=1}^{N}L(y_{i},\beta \cdot b(x_{i};\gamma))\\ \beta ,\gamma \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \end{matrix}                                      ⑪

        当前向分布算法的损失函数L(y,f(x))是指数损失函数时,即:

                               L(y,f(x))=e^{-y\cdot f(x)}                                                ⑫

        只需证明该学习的具体操作等价于AdaBoost的具体操作,就可证明AdaBoost也使用的是指数损失函数。假设我们经过m-1次迭代前向分布算法得到f_{m-1}(x)

                   f_{m-1}(x)=f_{m-2}(x)+\alpha _{m-1}G_{m-1}(x)=\alpha _{1}G_{1}(x)+...+\alpha _{m-1}G_{m-1}(x)               ⑬

        在第m轮迭代得到\alpha _{m}G_{m}(x)f_{m}(x):

                         f_{m}(x)=f_{m-1}(x)+\alpha _{m}G_{m}(x)                           ⑭

        目标是使前向分布算法得到的\alpha _{m}G_{m}(x) 使得f_{m}(x)在训练集上的指数损失函数最小,即:

                 \begin{matrix} (\alpha _{m},G_{m}(x))=arg\; min\sum _{i=1}^{N}e^{-y_{i}(f_{m-1}(x_{i})+\alpha G(x_{i}))}\\\alpha,G\; \; \; \; \; \; \; \end{matrix}                    ⑮

        公式⑮可以表示为:

                          \begin{matrix} (\alpha _{m},G_{m}(x))=arg\; min\sum _{i=1}^{N}\varpi _{mi}\cdot e^{-y_{i}\alpha G(x_{i})}\\\alpha,G \; \end{matrix}                    ⑯

        其中:\varpi _{mi}=e^{-y_{i}\cdot f_{m-1}(x_{i})} 。 因为\varpi _{mi} 既不依赖\alpha也不依赖于G,所以与最小化无关。但\varpi _{mi}依赖于f_{m-1}(x),随着每一轮迭代而发生改变。

        现证使公式⑯达到最小时,\alpha _{m}^{*}e_{m}^{*}w_{m+1,i}^{*}的取值就是AdaBoost算法得到的\alpha _{m}e_{m}w_{m+1,i}

        对于任意\alpha >0,使公式最小的G(x)由下式得到:

       \begin{matrix} min\sum _{i=1}^{N}\varpi _{mi}\cdot e^{-y_{i}\alpha G(x_{i})}=min\; (\sum_{y_{i}=G_{m}(x_i)}\varpi_{mi} \cdot e^{-\alpha }+\sum_{y_{i}\neq G_{m}(x_i)}\varpi_{mi} \cdot e^{\alpha })\\\alpha,G \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \;\; \; \; \; \; \; \; \; \; \; \; \;\alpha,G \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \;\; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \end{matrix}

                                                         \begin{matrix} =min\; (e^{-\alpha }\cdot (\sum_{i=1}^{N}\varpi _{mi}-\sum _{y_{i}\neq G_{m}(x_{i})}\varpi _{mi})+e^{\alpha }\cdot \sum _{y_{i}\neq G_{m}(x_{i})}\varpi _{mi})\\ \alpha ,G\; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \;\; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \end{matrix}

                                                         \begin{matrix} =min\; ((e^{\alpha }-e^{-\alpha })\cdot \sum _{y_{i}\neq G_{m}(x_{i})}\varpi _{mi}+e^{-\alpha }\cdot \sum_{i=1}^{N}\varpi _{mi})\\ \alpha ,G\; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \end{matrix}         ⑰

         我们要求极小值,所以将上式对\alpha求偏导并令其为0:

                       (e^{\alpha }+e^{-\alpha })\cdot \sum _{y_{i}\neq G_{m}(x_{i})}\varpi _{mi}-e^{-\alpha }\cdot \sum _{i=1}^{N}\varpi _{mi}=0                        ⑱

          上式的两边同时除以 \sum _{i=1}^{N}\varpi _{mi},且令:

                                              e_{m}^{*}=\frac{\sum _{y_{i}\neq G_{m}(x_{i})}\varpi _{mi}}{\sum _{i=1}^{N}\varpi _{mi}}                         ⑲

           而AdaBoost的e_{m}为:

          e_{m}=P(G_{m}(x_{i})\neq y_i)=\frac{\sum _{G_{m}(x_{i})\neq y_{i}}w_{m,i}}{\sum _{i=1}^{N}w_{m,i}}=\sum_{i=1}^{N}w_{m,i}\cdot I(G_{m}(x_{i})\neq y_{i})         ③

          对比公式③、⑲可以看出,AdaBoost的e_{m}和前向分布算法的e_{m}^{*}是一致的。

           故求导的原式为:

                                           (e^{\alpha }+e^{-\alpha })\cdot e_{m}^{*}-e^{-\alpha }=0

           解上式得:

                                           a_{m}^{*}=\frac{1}{2}\cdot ln\frac{1-e_{m}^{*}}{e_{m}^{*}}                                  ⑳

          而AdaBoost的 \alpha _{m}

                                          \alpha _{m}=\frac{1}{2}\cdot ln\frac{1-e_{m}}{e_{m}}                                  ④

          对比公式④、⑳可以看出,AdaBoost的\alpha _{m}和前向分布算法的\alpha _{m}^{*}是一致的。

          我们再来推算前向分布算法的每个样本的权值更新,由公式:

                                        \left\{\begin{matrix} f_{m}(x)=f_{m-1}(x)+\alpha _{m}G_{m}(x)\\ \varpi _{mi}=e^{-y_{i}\cdot f_{m-1}(x_{i})}\; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \end{matrix}\right.             ㉑

           将公式㉑的第一个式子,等式两边同时乘以 -y 再取以e为底数:

                                  e^{-y_{i}\cdot f_{m}(x_{i})}=e^{-y_{i}\cdot f_{m-1}(x_{i})-y_{i}\cdot \alpha _{m}G_{m}(x_{i})}

                                       \varpi _{m+1,i}=\varpi _{mi}\cdot e^{-y_{i}\alpha _{m}G_{m}(x_{i})}                                     ㉒

           对比公式⑤、㉒,可以看出AdaBoost的w_{m+1,i}和前向分布算法的\varpi _{m+1,i}只差一个归一化因子,因而等价。

           因此,AdaBoost算法使用的是指数损失函数。

★  代码实践:

from numpy import *
import matplotlib.pyplot as plt
import matplotlib
from matplotlib.font_manager import *

def loadDataSet():                # 加载测试数据
    dataMat = mat([[1.,2.1],
                   [1.5,1.6],
                   [1.3,1.],
                   [1.,1.],
                   [2.,1.],
                   [1.1,1.2]])

    labelList = [1.0,1.0,-1.0,-1.0,1.0]
    return dataMat, labelList      # 数据集返回的是矩阵类型,标签返回的是列表类型

def stumpClassify(dataMat,dimen,threshVal,threshIneq): # dimen:第dimen列,也就是第几个特征, threshVal:是阈值  threshIneq:标志
    retArray = ones((shape(dataMat)[0],1))   # 创造一个 样本数×1 维的array数组
    if threshIneq == 'lt':        # lt表示less than,表示分类方式,对于小于等于阈值的样本点赋值为-1
        retArray[dataMat[:,dimen] <= threshVal] = -1.0
    else:  # 我们确定一个阈值后,有两种分法,一种是小于这个阈值的是正类,大于这个值的是负类,
           #第二种分法是小于这个值的是负类,大于这个值的是正类,所以才会有这里的if 和else
        retArray[dataMat[:,dimen] > threshVal] = -1.0
    return  retArray            # 返回的是一个基分类器的分类好的array数组

def buildStump(dataArr,classLabels,D):
    dataMat = mat(dataArr)
    labelMat = mat(classLabels).T
    m,n = shape(dataMat)
    numStemp = 10
    bestStump = {}
    bestClassEst = mat(zeros((m,1)))
    minError = inf                      # 无穷
    for i in range(n):                  # 遍历特征
        rangeMin = dataMat[:,i].min()    # 检查到该特征的最小值
        rangeMax = dataMat[:,i].max()
        stepSize = (rangeMax - rangeMin)/numStemp  # 寻找阈值的步长是最大减最小除以10,你也可以按自己的意愿设置步长公式
        for j in range(-1, int(numStemp)+1):
            for inequal in ['lt', 'gt']:   # 因为确定一个阈值后,可以有两种分类方式
                threshVal = (rangeMin+float(j) * stepSize)
                predictedVals = stumpClassify(dataMat,i,threshVal,inequal)  # 确定一个阈值后,计算它的分类结果,predictedVals就是基分类器的预测结果,是一个m×1的array数组
                errArr = mat(ones((m,1)))
                errArr[predictedVals==labelMat] =0   # 预测值与实际值相同,误差置为0
                weightedEroor = D.T*errArr     # D就是每个样本点的权值,随着迭代,它会变化,这段代码是误差率的公式
                if weightedEroor

★ 运行结果:

python实现AdaBoost算法_第6张图片

★ 推算上述填充颜色的规律(以至于写出填充颜色的代码):

        不失一般性,我们随便举一个例子如上图7,共有3条纵向阈值,2条横向阈值,将信息绘制成表格:

纵向阈值 0.4 0.6 0.8
分类方式 gt lt lt
横向阈值 1.2 1.0
分类方式 gt lt

         注意:纵向阈值(竖线)按从小达到排序,横向阈值(横线)按从大到小排序,至于原因,可以看图7就知道了。

         gt和lt对应上文的两种分类方式,gt箭头就朝左,lt箭头就朝右。可以看出,这3条竖线和2条横线把该区域分成了12个部分,这里分成的区域数就是:  (横线条数+1)×(竖线条数+1)。

         现在我们判别每一部分是正类还是负类,可以写出每一部分的计算公式,比如我先写出①②③④这个四个部分的计算公式:

                                     \left\{\begin{matrix} sign(+0.4-0.6-0.8-1.2+1.0)=-1\; \; \; \; \;\; \; \; (1.)\\ sign(-0.4-0.6-0.8-1.2+1.0)=-1 \; \; \; \; \; \; \; \; (2.)\\ sign(-0.4+0.6-0.8-1.2+1.0)=-1 \; \; \; \; \;\; \; \; (3.)\\ sign(-0.4+0.6+0.8-1.2+1.0)=+1 \; \; \; \; \;\; \; \; (4.)\\...\end{matrix}\right.         ①

          当然了,上述式子是通过观察图7,根据箭头指向来判断出加减号,然后写出来的计算式子。那么如何通过代码来代替人的观察以此来写出加减号呢?

          其实加号或减号在代码中的体现就是+1或-1。我们把(1.),(2.),(3.),(4.)的符号提出来观察一下:

                       \begin{matrix} + & - & -& -&+ \\ - & -& -& - &+ \\ - & + & - &- & +\\ - &+ &+ & - & + \end{matrix}           ②     == ==>           \begin{matrix} \; \: \: 1 & -1 & -1&\; \; \; |\; \; -1&1 \\ - 1& -1& -1&\; \; \; |\; \; - 1& 1\\ - 1& \; \; \: 1& - 1&\; \; \;| \; \; - 1& 1\\ - 1&\; \; \: 1&\; \; \: 1&\; \; \;| \; \; -1 & 1 \end{matrix}        ③

        我把式子③分成左右两部分了(因为左边是竖线阈值提出来的符号,右部分是横线阈值提出来的符号)。gt和lt是字母表示的是分类方式,字母我们不能用于计算,所以我们规定:lt为+1,而gt为-1。(当然这是我自己规定的,你也可以反过来)。因此3条竖线阈值可以写为[-1,1,1],而2条横线阈值可以写为[-1,1]。

        我们再来看图7,每一部分都跟这3条竖线和2条横线有关系,比如第①部分:它在竖线阈值0.4的左边,在竖线阈值0.6的左边,在竖线阈值0.8的左边,在横线阈值1.2的上边,在横线阈值1.0的上边。现在我们再次规定:在直线右边或上边的部分为+1,在直线左边或下边的部分为-1。因此由刚才叙述的第①部分与各直线的关系,我们可以写出来第①部分和3条竖线阈值的关系是[-1,-1,-1],与2条横线阈值的关系是:[1,1]。我们把阈值与区域和阈值的关系进行点乘(竖线和横线要分开,然后再合起来),比如还是第①部分:

        [-1,-1,-1]*[-1,1,1]+[1,1]*[-1,1]=[1,-1,-1]+[-1,1]=[1,-1,-1,-1,1]       ④

       上式④的+号是合并列表的意思,不是加减乘除的+号。对比式子③,可以看出与式子③的第一个式子一致,因此这样考虑是可行的,不信的话,可以根据上述规则写出第②部分的计算式子:

      [1,-1,-1]*[-1,1,1]+[1,1]*[-1,1]=[-1,-1,-1]+[-1,1]=[-1,-1,-1,-1,1]      ⑤

        再把⑤和式子③的第二个式子对比,发现还是一致,现在小伙伴们可以相信这个做法是正确的。

       可是还有一个问题:上述区域与竖线阈值(或横线阈值)的关系而写出的表达式使我们用肉眼看出来的,比如你看到第①部分在竖线阈值0.4的左边,你才根据规则写出的-1,可是程序不会肉眼看啊,现在我们再来发现一个规律:先把这些位置关系的表达式写出来,看看有没有规律可循,比如我先把①②③④这个四个区域与竖线阈值的关系写出来,你可以看出端倪:

                                                \begin{matrix} [-1,-1,-1]\\ [\; \; \: 1,-1,-1] \\ [\; \; \: 1,\; \; \: 1,-1] \\ [\; \; \: 1,\; \; \: 1,\; \; \: 1] \end{matrix}

       我们可以看出第一行0个1,3个-1,而第二行1个1,2个-1,第三行2个1,1个-1,第四行3个1,0个-1。而在写代码时,我们遍历行的时候,就是遍历①②③④这四个部分来填充颜色,不正是第①部分j=0;第②部分j=1;第③部分j=2;第④部分j=3。那么上面矩阵的每一行就可以这么来制造,伪代码就是:

       for j in range(竖线阈值的条数+1):                # 因为看图7,第一行不正好4部分,对应区域①②③④

            row_list = [1]*j + [-1]*(竖线阈值的条数)

        同样的方法,我们也可以写出①⑤⑨这个3个区域与横线阈值的关系(为啥不继续写①②③④与横线的关系,因为①②③④与横线的关系是一样的,①⑤⑨在图7中是不同列的,他们的关系才是不同的):

                                               \begin{matrix} [\; \; \: 1,\; \; \: 1]\\ [-1,\; \; \: 1] \\ [-1,-1] \end{matrix}

        我们同样看出了端倪:第一行0个-1,2个1;第二行1个-1,1个1;第三行2个-1,0个1。这正是我们写代码时遍历列,第一列 i = 0,第二列 i=1,第三列 i=2,因此伪代码是:

        for i in range(横线阈值的条数+1):

             column_list = [-1]*i + [1]*(横线阈值的条数)

         因此我们把遍历行和遍历列的伪代码拼在一起,成为遍历3×4个区域,依次填充颜色。

✿ 我们写成伪代码(代码里的+号都是合并列表的意思,不是加减乘除的+号):

              for  i in range(横线阈值的条数+1):

                    for j in range(竖线阈值的条数+1):

                          symbol_list = row_list = [1]*j + [-1]*(竖线阈值的条数) + column_list = [-1]*i + [1]*(横线阈值的条数)

                          result = sign([alpha值的列表]*symbol_list):

                                    if  reslut == 1:

                                            正类(红点)

                                     else:

                                            负类(蓝点)

★ 参考链接:

         1.   http://www.cnblogs.com/Tang-tangt/p/9557089.html

         2.   https://zhuanlan.zhihu.com/p/30035094

         3.   统计学习与方法, 李航 P138-P146

你可能感兴趣的:(大数据)