精华内容
下载资源
问答
  • 逻辑回归算法

    2019-10-28 12:47:54
    逻辑回归是一个分类算法,但是利用的是回归的思想,首先对样本特征线性组合,然后利用logistic函数将值映射到0-1之间,通过给定的阈值,来预测样本属于哪一类。 为什么选择logistic函数: 连续、可导; 取值是0-1...

    逻辑回归和线性回归都是广义线性模型,以线性回归为理论支持,通过sigmoid函数引入非线性因素,用于处理分类问题。
    逻辑回归的基本假设是服从伯努利分布,构造极大似然函数,通过梯度下降法,求解二分类问题。

    为什么选择logistic函数:

    优点:
    连续、可导;
    取值是0-1之间;

    为什么用极大似然估计

    如果是用最小二乘或者是均方误差来求解参数的话,关于参数是非凸的,不容易求解很容易陷入局部最优解。
    将极大似然函数取对数以后等价与对数似然函数,参数的更新只和样本有关,比较稳定,和sigomid函数本身的梯度是无关的,不然的话sigmoid的梯度不大于0.25,更新的十分缓慢。

    参数更新过程

    通过极大似然函数来估计模型参数
    i=1myiyi^.(1yi)(1yi^)\displaystyle\prod_{i=1}^{m} y_i^{\widehat{y_i}}.(1-y_i)^{(1-\widehat{y_i})}
    转换成对数似然函数
    i=1myi.log(yi^)+(1yi).log(1yi^)\sum_{i=1}^m y_i.log({\widehat{y_i}})+(1-y_i).log(1-{\widehat{y_i}})
    为了利用经常使用的梯度下降来求解,也就是对负的对数似然函数来求解。
    1mi=1myi.log(yi^)+(1yi).log(1yi^)-\frac{1}{m}\sum_{i=1}^m y_i.log({\widehat{y_i}})+(1-y_i).log(1-{\widehat{y_i}})
    对参数求偏导,进行迭代,直到损失函数的值小于给定的阈值可以停止迭代。

    梯度下降的方法

    BGD批量梯度下降,每次迭代都是用全部的样本,虽然可以得到全局最优解,但是在样本量特别多的情况下,迭代速度特别慢,而且没有办法进行实时在线计算
    SGD随机梯度下降:每次都是用一个样本来更新参数,计算速度比较快,但是如果样本之间差距较大,就会造成参数来回的震荡
    MBGD小批量梯度下降,是结合了BGD和SGD优点的一种方法,既考虑了计算速度的问题,也考虑了避免参数震荡的问题,不是取所有的样本,也不是取一个样本,而是从样本中取n个样本,然后利用这n个样本来进行参数的求解,这种方法就产生了一个超参数n,n的取值如何定也是一个需要考虑的问题,可以进行线上实时计算。

    步长的更新

    实际情况下,将步长固定为一个常数会产生很多问题,比如震荡,而且不同特征的学习率也是不同的,因此应该迭代的修改学习率。 比如采用adam方法等

    逻辑回归的优缺点

    优点: 形式简单,模型的可解释性比较好,从特征的权重可以看出不同的特征对最后结果的影响,如果特征的权重比较大,那么这个特征对结果的影响也比较大。
    方便输出结果调整:因为输出的是每个样本的概率值或者叫做可能性,我们可以根据实际的项目和要求确定合适的阈值,然后将大于阈值的分为一类,小于阈值的分为一类。
    计算量比较小,速度快,存储资源低;
    缺点:准确率不是很高,因为形式比较简单,难以拟合数据的真实分布;
    处理非线性数据比较麻烦,在不引入其他方法的情况下,只能处理线性可分的数据
    本身无法选择特征,只能对数据做好特征工程之后,再进行模型训练。

    展开全文
  • 而在名称上类似的逻辑回归虽然也有“回归”两个字,但是逻辑回归属于分类算法逻辑回归也称为对数几率回归。那为什么逻辑回归也叫回归呢?原因是逻辑回归的形式与线性回归的形式有部分相同的。下面我们具体来学习...

    分类和回归任务的区别

    分类
    输出变量为有限个离散变量的预测问题是分类问题。
    回归
    输入变量与输出变量均为连续变量的预测问题是回归问题。

    例如:预测明天多少度,是一个回归任务;预测明天阴、晴、雨,就是一个分类任务。

    逻辑回归与线性回归的区别和联系

    区别
    线性回归回归算法,可以得到实值。而在名称上类似的逻辑回归虽然也有“回归”两个字,但实际上却是一种分类算法,逻辑回归也称为 对数几率回归
    联系
    逻辑回归的形式与线性回归的形式有部分是相同的,如果说 线性回归是对于特征的线性组合来拟合真实标记的话(y=wx+by=wx+b),那么 逻辑回归 是对于特征的线性组合来拟合真实标记为正例的概率的对数几率lny1y=wx+bln\frac{y}{1−y}=wx+b)。可以认为 逻辑回归就是用回归的办法来做分类

    逻辑回归(logistics regression)的判别函数

    逻辑回归由于存在易于实现、解释性好以及容易扩展等优点,被广泛应用于点击率预估(CTR)、计算广告(CA)以及推荐系统(RS)等任务中。下面我们具体来学习逻辑回归的判别函数(基于sigmod函数构造)。
    逻辑回归的判别函数
    g(z)=11+ezz=wTx \begin{aligned} &g(z)=\frac{1}{1+e^{-z}} ,z=\mathbf{w}^T\mathbf{x} \end{aligned}

    在这里插入图片描述
    sigmod函数的优点
    (1)具有很强的鲁棒性(鲁棒是Robust的音译,也就是健壮和强壮的意思);
    (2)并且将函数的输入范围(,+)(-∞,+∞)映射到了输出的(0,1)(0,1)之间且具有概率意义具有概率意义的理解:将一个样本输入到我们学习到的函数中,输出0.7,意思就是这个样本有70%的概率是正例,30%的概率为负例)。

    逻辑回归输出的预测函数的数学表达式为
    hθ(x)=g(θTx)=11+eθTxh_θ(x)=g({θ^Tx})=\cfrac{1}{1+e^{−θ^Tx}}
    其中θθ是参数向量。对于hθ(x)h_θ(x)的直观解释是:对于给定的输入xxhθ(x)h_θ(x)表示其对应类标 y=1y=1(即:属于正例)的概率,hθ(x)h_θ(x)的计算公式为hθ(x)=p(xi;w)h_θ(x)=p(x_i ; w)

    逻辑回归(logistics regression)的损失函数

    逻辑回归的 损失函数 J(θ)J(\mathbf{θ}),又叫 交叉熵损失函数,它是通过 极大似然估计 推导得到的。
    J(θ)=1mi=1myiloghθ(xi)+(1yi)log(1hθ(xi)) \begin{aligned} J(\mathbf{θ})=-\frac{1}{m}∑_{i=1}^{m}y_ilogh_θ(x_i)+(1−y_i)log(1−h_θ(x_i)) \end{aligned}

    损失函数J(θ)J(\mathbf{θ})的推导过程
    由于yy只能取0或1,服从二项分布,则后验概率
    p(yx;θ)=(hθ(x))y(1hθ(x))1yp(y|x;θ)=(h_θ(x))^y(1−h_θ(x))^{1−y}
    对于mm个独立同分布的训练样本xx,其似然函数写作
    L(θ)=i=1mp(yx;θ)=i=1mhθ(xi)yi(1hθ(xi))1yiL(θ)=∏_{i=1}^{m}p(y|x;θ)=∏_{i=1}^{m}h_θ(x_i)^{y_i}(1−h_θ(x_i))^{1−y_i}
    为了方便操作,取对数,则对数似然函数
    l(θ)=logL(θ)=i=1myiloghθ(xi)+(1yi)log(1hθ(xi))l(θ)=logL(θ)=∑_{i=1}^{m}y_i ·logh_θ(x_i)+(1−y_i)·log(1−h_θ(x_i))
    根据“最大似然估计”,求l(θ)l(θ)取最大值时的θθ,定义 损失函数J(θ)J(θ)为:
    J(θ)=1ml(θ)=1mi=1myiloghθ(xi)+(1yi)log(1hθ(xi))J(θ)=−\frac{1}{m}l(θ)=-\frac{1}{m}∑_{i=1}^{m}y_i·logh_θ(x_i)+(1−y_i)·log(1−h_θ(x_i))
    所以最后目标变成取J(θ)J(θ)最小值时的θθ为最佳参数。
    利用梯度下降法得到最优θθ参数更新) :
    θj:=θjαθjJ(θ)=θjα1mi=1m(hθ(xi)yi)xijθ_j:=θ_j−α\frac{∂}{∂θ_j}J(θ)=θ_j−α\frac{1}{m}∑_{i=1}^m\Big(h_θ(x_i)−y_i\Big)x_i^j
    图片名称

    交叉熵损失Cost函数
    Cost(hθ(x),y)={log(hθ(x)),if y=1log(1hθ(x)),if y=0Cost(h_θ(x),y)= \begin{cases} −log(h_θ(x)),& \text{if y=1}\\ −log(1−hθ(x)),& \text{if y=0} \end{cases}
    数据集全部损失J(θ)J(\mathbf{θ})函数
    J(θ)=1mi=1mCost(hθ(x(i)),y(i))=1mi=1m[y(i)loghθ(x(i))+(1y(i))log(1hθ(x(i)))] \begin{aligned} J(\mathbf{θ})&=\frac{1}{m}\sum_{i=1}^mCost(h_θ(x^{(i)}),y^{(i)}) \\&=-\frac{1}{m}\sum_{i=1}^{m}\big[y^{(i)}logh_θ(x^{(i)})+(1−y^{(i)})log(1−h_θ(x^{(i)}))\big] \end{aligned}

    交叉熵损失函数的求解

    与线性回归类似,利用梯度下降法求解交叉熵损失函数,求解步骤概况如下:
    (1)随机选择一组W;
    (2)将W带入交叉熵损失函数,让得到的点沿着负梯度的方向移动;
    (3)循环第二步;
    求解梯度部分同样是对损失函数求偏导,过程如下:

    对损失函数求偏导
    θjJ(θ)=1mi=1m(yi1hθ(xi)θjhθ(xi)(1yi)11hθ(xi)θjhθ(xi))=1mi=1m(yi1g(θTxi)(1yi)11g(θTxi))θjg(θTxi)=1mi=1m(yi1g(θTxi)(1yi)11g(θTxi))g(θTxi)(1g(θTxi))θjθTxi=1mi=1m(yi(1g(θTxi))(1yi)g(θTxi))xij=1mi=1m(yig(θTxi))xij=1mi=1m(yihθ(xi))xij=1mi=1m(hθ(xi)yi)xij \begin{aligned} \frac{\partial}{\partialθ_j}J(\mathbf{θ})&=-\frac{1}{m}∑_{i=1}^{m} \bigg(y_i\frac{1}{h_θ(x_i)}\frac{\partial}{\partialθ_j}{h_θ(x_i)}-(1−y_i)\frac{1}{1−h_θ(x_i)}\frac{\partial}{\partialθ_j}{h_θ(x_i)}\bigg) \\&=-\frac{1}{m}∑_{i=1}^{m} \bigg(y_i\frac{1}{g(θ^Tx_i)}-(1−y_i)\frac{1}{1−g(θ^Tx_i)}\bigg)\frac{\partial}{\partialθ_j}{g(θ^Tx_i)} \\&=-\frac{1}{m}∑_{i=1}^{m} \bigg(y_i\frac{1}{g(θ^Tx_i)}-(1−y_i)\frac{1}{1−g(θ^Tx_i)}\bigg){g(θ^Tx_i)}\Big(1-{g(θ^Tx_i)}\Big)\frac{\partial}{\partialθ_j}θ^Tx_i \\&=-\frac{1}{m}∑_{i=1}^{m} \bigg(y_i\Big(1-{g(θ^Tx_i)}\Big)-(1−y_i){g(θ^Tx_i)}\bigg)x_i^j \\&=-\frac{1}{m}∑_{i=1}^{m} \bigg(y_i-{g(θ^Tx_i)}\bigg)x_i^j \\&=-\frac{1}{m}∑_{i=1}^{m} \bigg(y_i-{h_θ(x_i)}\bigg)x_i^j \\&=\frac{1}{m}∑_{i=1}^{m} \bigg({h_θ(x_i)}-y_i\bigg)x_i^j \end{aligned}
    交叉熵损失函数的梯度和最小二乘法的梯度形式上完全相同,区别在于,交叉熵损失函数的hθ(x)=g(z)h_{θ}(x) = g(z),而最小二乘法的hθ(x)=wTxh_{θ}(x) =\mathbf{w}^T\mathbf{x}

    展开全文
  • 本文将从理论介绍开始,搞清楚什么是逻辑回归、回归系数、算法思想、工作原理及其优缺点等。进一步通过两个实际案例深化理解逻辑回归,以及在工程应用进行实现。(本文原创,转载必须注明出处:决...

    逻辑回归模型算法研究与案例分析
    (白宁超 2018年9月6日15: 21:20)

    导读:逻辑回归(Logistic regression)即逻辑模型,属于常见的一种分类算法。本文将从理论介绍开始,搞清楚什么是逻辑回归、回归系数、算法思想、工作原理及其优缺点等。进一步通过两个实际案例深化理解逻辑回归,以及在工程应用进行实现。(本文原创,转载必须注明出处: 决策树模型算法研究与案例分析

    理论介绍

    逻辑回归和Sigmoid 函数

    逻辑回归

    回归:假设现在有一些数据点,我们用一条直线对这些点进行拟合(这条直线称为最佳拟合直线),这个拟合的过程就叫做回归。

    逻辑回归(Logistic Regression)是一种用于解决二分类(0 or 1)问题的机器学习方法,用于估计某种事物的可能性。比如某用户购买某商品的可能性,某病人患有某种疾病的可能性,以及某广告被用户点击的可能性等。 注意,这里用的是“可能性”,而非数学上的“概率”,logisitc回归的结果并非数学定义中的概率值,不可以直接当做概率值来用。该结果往往用于和其他特征值加权求和,而非直接相乘。

    Sigmoid 函数

    Sigmoid函数是一个常见的S型数学函数,在信息科学中,由于其单增以及反函数单增等性质,Sigmoid函数常被用作神经网络的阈值函数,将变量映射到0,1之间。在逻辑回归、人工神经网络中有着广泛的应用。Sigmoid函数的数学形式是:

    gif.latex?f(z)=\frac{1}{1+e^{-z}}

    对x求导可以推出如下结论:

    gif.latex?f^{%27}(z)=\frac{e^{-z}}{(1+e^

    下图给出了 Sigmoid 函数在不同坐标尺度下的两条曲线图。当 x 为 0 时,Sigmoid 函数值为 0.5 。随着 x 的增大,对应的 Sigmoid 值将逼近于 1 ; 而随着 x 的减小, Sigmoid 值将逼近于 0 。如果横坐标刻度足够大, Sigmoid 函数看起来很像一个阶跃函数。



    因此,为了实现 Logistic 回归分类器,我们可以在每个特征上都乘以一个回归系数,然后把所有结果值相加,将这个总和代入 Sigmoid 函数中,进而得到一个范围在 0~1 之间的数值。任何大于 0.5 的数据被分入 1 类,小于 0.5 即被归入 0 类。所以,Logistic 回归也是一种概率估计,比如这里Sigmoid 函数得出的值为0.5,可以理解为给定数据和参数,数据被分入 1 类的概率为0.5。(注意:针对二分类问题,0.5不是唯一确定分类的值,你可以根据需求调整这个概率值。)

    逻辑回归与线性回归的关系

    逻辑回归(Logistic Regression)与线性回归(Linear Regression)都是一种广义线性模型(generalized linear model)。逻辑回归假设因变量 y 服从伯努利分布,而线性回归假设因变量 y 服从高斯分布。 因此与线性回归有很多相同之处,去除Sigmoid映射函数的话,逻辑回归算法就是一个线性回归。可以说,逻辑回归是以线性回归为理论支持的,但是逻辑回归通过Sigmoid函数引入了非线性因素,因此可以轻松处理0/1分类问题。

    最优化方法的回归系数

    Sigmoid 函数的输入记为 z ,由下面公式得到:

    gif.latex?z=w_0x_0&space;+&space;w_1x_1+

    如果采用向量的写法,上述公式可以写成 Sigmoid 函数计算公式向量形式 gif.latex?\dpi{100}&space;z=w^Tx,它表示将这两个数值向量对应元素相乘然后全部加起来即得到 z 值。其中的向量 x 是分类器的输入数据,向量 w 也就是我们要找到的最佳参数(系数),从而使得分类器尽可能地精确。为了寻找该最佳参数,需要用到最优化理论的一些知识。我们这里使用的是——梯度上升法(Gradient Ascent)。

    梯度上升与梯度下降

    梯度

    对于梯度这个词一些人比较陌生,我们先看看维基百科的解释:在向量微积分中,标量场(向量场)中某一点的梯度指向在这点标量场增长最快的方向(当然要比较的话必须固定方向的长度),梯度的绝对值是长度为1的方向中函数最大的增加率,也就是说gif.latex?\dpi{80}&space;|\nabla&space;f,其中 gif.latex?\dpi{80}&space;\nabla_v 代表方向导数。

    • 在单变量的实值函数的情况,梯度只是导数,或者,对于一个线性函数,也就是线的斜率。
    • 梯度一词有时用于斜度,也就是一个曲面沿着给定方向的倾斜程度。可以通过取向量梯度和所研究的方向的内积来得到斜度。梯度的数值有时也被称为梯度。(更多梯度相关知识参照维基百科词条

    梯度形式化描述

    考虑一座高度在 (x, y)点是 H(x, y)的山。H这一点的梯度是在该点坡度(或者说斜度)最陡的方向。梯度的大小告诉我们坡度到底有多陡。这个现象可以如下数学的表示。山的高度函数 H的梯度点积一个单位向量给出了表面在该向量的方向上的斜率。这称为方向导数。

    理解梯度

    为了大家更容易理解什么是梯度,我们介意向量的概念,向量是一个矢量具有大小和方向的。同样,梯度也可以类比为具备大小和方向的这么一个概念。其两者比较如下:(这里严格意义上讲是不成立的,便于大家理解。)

    向量 = 值 + 方向  
    梯度 = 向量
    梯度 = 梯度值 + 梯度方向
    

    梯度上升

    要找到某函数的最大值,最好的方法是沿着该函数的梯度方向探寻。如果梯度记为 ▽ ,则函数 f(x, y) 的梯度由下式表示:

    gif.latex?\dpi{120}&space;\nabla&space;f

    这个梯度意味着要沿 x 的方向移动gif.latex?\dpi{90}&space;{\frac{\partial ,沿 y 的方向移动gif.latex?\dpi{90}&space;{\frac{\partial。其中,函数f(x, y) 必须要在待计算的点上有定义并且可微。下图是一个具体的例子。



    上图展示的,梯度上升算法到达每个点后都会重新估计移动的方向。从 P0 开始,计算完该点的梯度,函数就根据梯度移动到下一点 P1。在 P1 点,梯度再次被重新计算,并沿着新的梯度方向移动到 P2 。如此循环迭代,直到满足停止条件。迭代过程中,梯度算子总是保证我们能选取到最佳的移动方向。

    上图中的梯度上升算法沿梯度方向移动了一步。可以看到,梯度算子总是指向函数值增长最快的方向。这里所说的是移动方向,而未提到移动量的大小。该量值称为步长,记作 α 。用向量来表示的话,梯度上升算法的迭代公式如下:

    gif.latex?\dpi{100}&space;w&space;:=w&sp

    例如:y = w0 + w1x1 + w2x2 + ... + wnxn
    梯度:参考上图的例子,二维图像,x方向代表第一个系数,也就是 w1,y方向代表第二个系数也就是 w2,这样的向量就是梯度。
    α:上面的梯度算法的迭代公式中的阿尔法,这个代表的是移动步长(step length)。移动步长会影响最终结果的拟合程度,最好的方法就是随着迭代次数更改移动步长。步长通俗的理解,100米,如果我一步走10米,我需要走10步;如果一步走20米,我只需要走5步。这里的一步走多少米就是步长的意思。
    ▽f(w):代表沿着梯度变化的方向,也可以理解该方向求导。
    

    该公式将一直被迭代执行,直至达到某个停止条件为止,比如迭代次数达到某个指定值或者算法达到某个可以允许的误差范围。

    梯度上升与梯度下降的区别

    梯度下降是大家听的最多的,本质上梯度下降与梯度上升算法是一样的,只是公司中加法变减法,梯度下降的公式如下:

    gif.latex?\dpi{100}&space;w&space;:=w&sp

    在求极值的问题中,有梯度上升和梯度下降两个最优化方法。梯度上升用于求最大值,梯度下降用于求最小值。如logistic回归的目标函数:代表的是概率,我们想求概率最大值,即对数似然函数的最大值,所以使用梯度上升算法。而线性回归的代价函数:代表的则是误差,我们想求误差最小值,所以用梯度下降算法。

    逻辑回归分类核心思想

    根据现有数据对分类边界建立回归公司,以此进行分类。回归即最佳拟合。

    逻辑回归工作原理

    每个回归系数初始化为 1
    重复 R 次:
        计算整个数据集的梯度
        使用 步长 x 梯度 更新回归系数的向量
    返回回归系数
    

    逻辑回归算法流程

    收集数据: 采用任意方法收集数据
    准备数据: 由于需要进行距离计算,因此要求数据类型为数值型。另外,结构化数据格式则最佳。
    分析数据: 采用任意方法对数据进行分析。
    训练算法: 大部分时间将用于训练,训练的目的是为了找到最佳的分类回归系数。
    测试算法: 一旦训练步骤完成,分类将会很快。
    使用算法: 首先,我们需要输入一些数据,并将其转换成对应的结构化数值;接着,基于训练好的回归系数就可以对这些数值进行简单的回归计算,判定它们属于哪个类别;
    

    逻辑回归优缺点

    优点: 计算代价不高,易于理解和实现。
    缺点: 容易欠拟合,分类精度可能不高。
    适用数据类型: 数值型和标称型数据。  
    

    案例分析1:Logistic回归在简单数据集上的分类

    案例描述

    在一个简单的数据集上,采用梯度上升法找到 Logistic 回归分类器在此数据集上的最佳回归系数

    开发流程

    收集数据: 可以使用任何方法
    准备数据: 由于需要进行距离计算,因此要求数据类型为数值型。另外,结构化数据格式则最佳
    分析数据: 画出决策边界
    训练算法: 使用梯度上升找到最佳参数
    测试算法: 使用 Logistic 回归进行分类
    使用算法: 对简单数据集中数据进行分类
    

    数据采集

    本文采用100行的测试集文本。其中前两列是特征1,和特征2,第三类是对应的标签。(这里特征1,特征2作为测试使用没有实际意义,你可以理解为特征1 是水里游的,特征2是有鱼鳞。类别判断是否为鱼类。)



    读取文本文件,加载数据集和类标签,这里将特征集第一列加1,便于后续回归系数的计算:

    '''加载数据集和类标签'''
    def loadDataSet(file_name):
        # dataMat为原始数据, labelMat为原始数据的标签
        dataMat,labelMat = [],[]
        fr = open(file_name)
        for line in fr.readlines():
            lineArr = line.strip().split(',')
            if len(lineArr) == 1:
                continue    # 这里如果就一个空的元素,则跳过本次循环
            # 为了方便计算,我们将每一行的开头添加一个 1.0 作为 X0
            dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])
            labelMat.append(int(lineArr[2]))
        return dataMat, labelMat
    

    梯度上升训练算法模型

    梯度上升算法

    使用梯度上升训练算法模型,其代码实现如下:

    ''' 正常的梯度上升法,得到的最佳回归系数 '''
    def gradAscent(dataMatIn, classLabels):
        dataMatrix = mat(dataMatIn)  # 转换为 NumPy 矩阵
        # 转化为矩阵[[0,1,0,1,0,1.....]],并转制[[0],[1],[0].....]
        # transpose() 行列转置函数
        # 将行向量转化为列向量   =>  矩阵的转置
        labelMat = mat(classLabels).transpose()  # 首先将数组转换为 NumPy 矩阵,然后再将行向量转置为列向量
        # m->数据量,样本数 n->特征数
        m, n = shape(dataMatrix) # 矩阵的行数和列数
        # print(m,n)
        alpha = 0.001  # alpha代表向目标移动的步长
        maxCycles = 500 # 迭代次数
        weights = ones((n, 1)) # 代表回归系数,ones((n,1)) 长度和特征数相同矩阵全是1
        for k in range(maxCycles):
            h = sigmoid(dataMatrix * weights)  # 矩阵乘法
            # labelMat是实际值
            error = (labelMat - h)  # 向量相减
            # 0.001* (3*m)*(m*1) 表示在每一个列上的一个误差情况,最后得出 x1,x2,xn的系数的偏移量
            weights = weights + alpha * dataMatrix.transpose() * error  # 矩阵乘法,最后得到回归系数
        return array(weights)
    

    其中sigmoid函数实现如下:

    ''' sigmoid跳跃函数 '''
    def sigmoid(ZVar):
        return 1.0 / (1 + exp(-ZVar))
    

    代码分析:函数的两个参数是数据加载返回的特征集和标签类集合。对数据集进行mat矩阵话转化,而类标签集进行矩阵之后转置,便于行列式的计算。然后设定步长,和迭代次数。整个特征矩阵与回归系数乘积求sigmoid值,最后返回回归系数的值。运行结果如下:

    [[ 4.12414349]
     [ 0.48007329]
     [-0.6168482 ]]
    

    思考?步长和迭代次数的初始值如何设定?

    随机梯度上升算法

    梯度上升算法在每次更新回归系数时都需要遍历整个数据集,该方法在处理 100 个左右的数据集时尚可,但如果有数十亿样本和成千上万的特征,那么该方法的计算复杂度就太高了。一种改进方法是一次仅用一个样本点来更新回归系数,该方法称为 随机梯度上升算法。由于可以在新样本到来时对分类器进行增量式更新,因而随机梯度上升算法是一个在线学习(online learning)算法。与 “在线学习” 相对应,一次处理所有数据被称作是 “批处理” (batch) 。其伪代码是:

    所有回归系数初始化为 1
    对数据集中每个样本
        计算该样本的梯度
        使用 alpha x gradient 更新回归系数值
    返回回归系数值
    

    随机梯度上升算法的代码实现如下:

    ''' 随机梯度上升'''
    # 梯度上升与随机梯度上升的区别?梯度下降在每次更新数据集时都需要遍历整个数据集,计算复杂都较高;随机梯度下降一次只用一个样本点来更新回归系数
    def stocGradAscent0(dataMatrix, classLabels):
        m, n = shape(dataMatrix)
        alpha = 0.01
        weights = ones(n)  # 初始化长度为n的数组,元素全部为 1
        for i in range(m):
            # sum(dataMatrix[i]*weights)为了求 f(x)的值,f(x)=a1*x1+b2*x2+..+nn*xn
            h = sigmoid(sum(dataMatrix[i] * weights))
            # 计算真实类别与预测类别之间的差值,然后按照该差值调整回归系数
            error = classLabels[i] - h
            # 0.01*(1*1)*(1*n)
            weights = array(weights) + alpha * error * array(mat(dataMatrix[i]))
        return array(weights.transpose())
    

    可以看到,随机梯度上升算法与梯度上升算法在代码上很相似,但也有一些区别: 第一,后者的变量 h 和误差 error 都是向量,而前者则全是数值;第二,前者没有矩阵的转换过程,所有变量的数据类型都是 NumPy 数组。

    判断优化算法优劣的可靠方法是看它是否收敛,也就是说参数是否达到了稳定值,是否还会不断地变化?下图展示了随机梯度上升算法在 200 次迭代过程中回归系数的变化情况。其中的系数2,也就是 X2 只经过了 50 次迭代就达到了稳定值,但系数 1 和 0 则需要更多次的迭代。如下图所示:



    针对波动问题,我们改进了之前的随机梯度上升算法,具体代码实现如下:

    ''' 改进版的随机梯度上升,使用随机的一个样本来更新回归系数'''
    def stocGradAscent1(dataMatrix, classLabels, numIter=150):
        m, n = shape(dataMatrix)
        weights = ones(n)  # 创建与列数相同的矩阵的系数矩阵
        # 随机梯度, 循环150,观察是否收敛
        for j in range(numIter):
            dataIndex = list(range(m)) # [0, 1, 2 .. m-1]
            for i in range(m):
                # i和j的不断增大,导致alpha的值不断减少,但是不为0
                alpha = 4 / (1.0 + j + i) + 0.0001 # alpha随着迭代不断减小非0
                # random.uniform(x, y) 随机生成下一个实数,它在[x,y]范围内
                Index = int(random.uniform(0, len(dataIndex)))
                # sum(dataMatrix[i]*weights)为了求 f(x)的值, f(x)=a1*x1+b2*x2+..+nn*xn
                h = sigmoid(sum(dataMatrix[dataIndex[Index]] * weights))
                error = classLabels[dataIndex[Index]] - h
                weights = weights + alpha * error *array(mat(dataMatrix[dataIndex[Index]]))
                del (dataIndex[Index])
        # print(weights.transpose())
        return weights.transpose()
    

    上面的改进版随机梯度上升算法改了两处代码。

    • 改进为 alpha 的值。alpha 在每次迭代的时候都会调整,这回缓解上面波动图的数据波动或者高频波动。另外,虽然 alpha 会随着迭代次数不断减少,但永远不会减小到 0,因为我们在计算公式中添加了一个常数项。
    • 修改为 randIndex 更新,这里通过随机选取样本拉来更新回归系数。这种方法将减少周期性的波动。这种方法每次随机从列表中选出一个值,然后从列表中删掉该值(再进行下一次迭代)。

    分析数据:画出决策边界

    边界可视化的代码实现如下:

    ''' 数据可视化展示 '''
    def plotBestFit(dataArr, labelMat, weights):
        n = shape(dataArr)[0]
        xcord1,xcord2,ycord1,ycord2 = [],[],[],[]
        for i in range(n):
            if int(labelMat[i]) == 1:
                xcord1.append(dataArr[i, 1])
                ycord1.append(dataArr[i, 2])
            else:
                xcord2.append(dataArr[i, 1])
                ycord2.append(dataArr[i, 2])
    
        fig = plt.figure()
        ax = fig.add_subplot(111)
        ax.scatter(xcord1, ycord1, s=30, c='red', marker='s')
        ax.scatter(xcord2, ycord2, s=30, c='green')
        x = arange(-3.0, 3.0, 0.1)
        """
        dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])
        w0*x0+w1*x1+w2*x2=f(x)
        x0最开始就设置为1, x2就是我们画图的y值,而f(x)被我们磨合误差给算到w0,w1,w2身上去了
        所以: w0+w1*x+w2*y=0 => y = (-w0-w1*x)/w2
        """
        y = (-weights[0] - weights[1] * x) / weights[2]
        ax.plot(x, y)
        plt.xlabel('X')
        plt.ylabel('Y')
        plt.show()
    

    运行结果分别是:

    梯度上升算法可视化结果图1-1:





    图1-1 梯度上升算法分类

    随机梯度上升算法可视化结果:


    图1-2 随机梯度上升算法分类

    优化随机梯度上升算法可视化结果:


    图1-3 优化随机梯度上升算法分类

    结果分析:

    图1-1的梯度上升算法在每次更新回归系数时都需要遍历整个数据集,虽然分类结果还不错该方法的计算复杂度就太高了。图1-2的随机梯度上升算法虽然分类效果不是很好(分类1/3左右),但是其迭代次数远远小于图1-1迭代次数(500次)。整体性能有所改进,但是其存在局部波动现象。基于此改进后的图1-3效果显示好很多。

    测试算法: 使用Logistic回归进行分类

    代码实现如下:

    '''数据集决策可视化'''
    def simpleTest(file_name):
        # 1.收集并准备数据
        dataMat, labelMat = loadDataSet(file_name)
        # 2.训练模型,  f(x)=a1*x1+b2*x2+..+nn*xn中 (a1,b2, .., nn).T的矩阵值
        dataArr = array(dataMat)
        weights = stocGradAscent1(dataArr, labelMat)
        # 数据可视化
        plotBestFit(dataArr, labelMat, weights)
    

    案例分析2:从病毒性流感预测病人的死亡情况

    案例描述

    使用 Logistic 回归来预测病毒性流感预测病人的死亡问题。这个数据集中包含了医院检测病毒性流感的一些指标,有的指标比较主观,有的指标难以测量,例如人的疼痛级别。

    开发流程
    收集数据: 给定数据文件
    准备数据: 用 Python 解析文本文件并填充缺失值
    分析数据: 可视化并观察数据
    训练算法: 使用优化算法,找到最佳的系数
    测试算法: 为了量化回归的效果,需要观察错误率。根据错误率决定是否回退到训练阶段,
    通过改变迭代的次数和步长的参数来得到更好的回归系数
    使用算法: 实现一个简单的命令行程序来收集马的症状并输出预测结果并非难事,
    这可以作为留给大家的一道习题

    收集数据: 给定数据文件

    训练数据已经给出,这里对文件处理即可,代码如下:

    '''加载数据集和类标签2'''
    def loadDataSet2(file_name):
        frTrain = open(file_name)
        trainingSet,trainingLabels = [],[]
        for line in frTrain.readlines():
            currLine = line.strip().split(',')
            # print(len(currLine))
            lineArr = []
            for i in range(len(currLine)-1):
                lineArr.append(float(currLine[i]))
            trainingSet.append(lineArr)
            trainingLabels.append(float(currLine[len(currLine)-1]))
        return trainingSet,trainingLabels
    

    准备数据: 用 Python 解析文本文件并填充缺失值

    处理数据中的缺失值

    假设有100个样本和20个特征,这些数据都是机器收集回来的。若机器上的某个传感器损坏导致一个特征无效时该怎么办?此时是否要扔掉整个数据?这种情况下,另外19个特征怎么办? 它们是否还可以用?答案是肯定的。因为有时候数据相当昂贵,扔掉和重新获取都是不可取的,所以必须采用一些方法来解决这个问题。下面给出了一些可选的做法:

    • 使用可用特征的均值来填补缺失值;
    • 使用特殊值来填补缺失值,如 -1;
    • 忽略有缺失值的样本;
    • 使用有相似样本的均值添补缺失值;
    • 使用另外的机器学习算法预测缺失值。

    现在,我们对下一节要用的数据集进行预处理,使其可以顺利地使用分类算法。在预处理需要做两件事:所有的缺失值必须用一个实数值来替换,因为我们使用的 NumPy 数据类型不允许包含缺失值。我们这里选择实数 0 来替换所有缺失值,恰好能适用于 Logistic 回归。这样做的直觉在于,我们需要的是一个在更新时不会影响系数的值。回归系数的更新公式如下:
    weights = weights + alpha * error * dataMatrix[dataIndex[randIndex]]
    如果 dataMatrix 的某个特征对应值为 0,那么该特征的系数将不做更新,即:weights = weights
    另外,由于 Sigmoid(0) = 0.5 ,即它对结果的预测不具有任何倾向性,因此我们上述做法也不会对误差造成任何影响。基于上述原因,将缺失值用 0 代替既可以保留现有数据,也不需要对优化算法进行修改。此外,该数据集中的特征取值一般不为 0,因此在某种意义上说它也满足 “特殊值” 这个要求。
    如果在测试数据集中发现了一条数据的类别标签已经缺失,那么我们的简单做法是将该条数据丢弃。这是因为类别标签与特征不同,很难确定采用某个合适的值来替换。采用 Logistic 回归进行分类时这种做法是合理的,而如果采用类似 kNN 的方法,则保留该条数据显得更加合理。

    训练算法: 使用优化算法,找到最佳的系数

    训练算法模型代码如下:

    '''测试Logistic算法分类'''
    def testClassier():
        # 使用改进后的随机梯度上升算法 求得在此数据集上的最佳回归系数 trainWeights
        file_name = './HorseColicTraining.txt'
        trainingSet,trainingLabels = loadDataSet2(file_name)
        trainWeights = stocGradAscent1(array(trainingSet), trainingLabels, 500)
        # 根据特征向量预测结果
        teststr = '2.000000,1.000000,38.300000,40.000000,24.000000,1.000000,1.000000,3.000000,1.000000,3.000000,3.000000,1.000000,0.000000,0.000000,0.000000,1.000000,1.000000,33.000000,6.700000,0.000000,0.000000'
        currLine = teststr.strip().split(',')
        lineArr = []
        for i in range(len(currLine)):
            lineArr.append(float(currLine[i]))
        res = classifyVector(array(lineArr), trainWeights)
        # 打印预测结果
        reslut = ['死亡','存活']
        print('预测结果是:',int(res))
    

    分类函数代码如下:

    '''分类函数,根据回归系数和特征向量来计算 Sigmoid的值,大于0.5函数返回1,否则返回0'''
    def classifyVector(featuresV, weights):
        prob = sigmoid(sum(featuresV * weights))
        print(prob)
        if prob > 0.9: return 1.0
        else: return 0.0
    

    测试算法:使用决策树执行分类

    为了量化回归的效果,需要观察错误率。根据错误率决定是否回退到训练阶段,通过改变迭代的次数和步长的参数来得到更好的回归系数

    '''打开测试集和训练集,并对数据进行格式化处理'''
    def colicTest():
        file_name = './HorseColicTraining.txt'
        trainingSet,trainingLabels = loadDataSet2(file_name)
        # 使用改进后的随机梯度上升算法 求得在此数据集上的最佳回归系数 trainWeights
        trainWeights = stocGradAscent1(array(trainingSet), trainingLabels, 500)
        frTest = open('./HorseColicTest.txt')
        errorCount = 0 ; numTestVec = 0.0
        # 读取 测试数据集 进行测试,计算分类错误的样本条数和最终的错误率
        for line in frTest.readlines():
            numTestVec += 1.0
            currLine = line.strip().split(',')
            lineArr = []
            for i in range(21):
                lineArr.append(float(currLine[i]))
            if int(classifyVector(array(lineArr), trainWeights)) != int(
                    currLine[21]):
                errorCount += 1
        errorRate = (float(errorCount) / numTestVec)
        print("逻辑回归算法测试集的错误率为: %f" % errorRate)
        return errorRate
    
    
    # 调用 colicTest() 10次并求结果的平均值
    def multiTest():
        numTests = 10;errorSum = 0.0
        for k in range(numTests):
            errorSum += colicTest()
        print("迭代 %d 次后的平均错误率是: %f" % (numTests, errorSum / float(numTests)))
    

    其运行结果如下:

    逻辑回归算法测试集的错误率为: 0.298507
    

    参考文献

    1. scikit中文社区:http://sklearn.apachecn.org/cn/0.19.0/
    2. 中文维基百科:https://zh.wikipedia.org/wiki/%E9%82%8F%E8%BC%AF%E8%BF%B4%E6%AD%B8
    3. GitHub:https://github.com/BaiNingchao/MachineLearning-1
    4. 图书:《机器学习实战》
    5. 图书:《自然语言处理理论与实战》

    完整代码下载

    源码请进【机器学习和自然语言QQ群:436303759】文件下载:



    作者声明

    本文版权归作者白宁超所有,本文原创,旨在学术和科研使用。文章同步如下:

    展开全文
  • 本文将从理论介绍开始,搞清楚什么是逻辑回归、回归系数、算法思想、工作原理及其优缺点等。进一步通过两个实际案例深化理解逻辑回归,以及在工程应用进行实现。(本文原创,转载必须注明出处: 一步步教你轻松学...
    一步步教你轻松学逻辑回归模型算法
    (白宁超2018年9月6日15: 01:20)

    导读:逻辑回归(Logistic regression)即逻辑模型,属于常见的一种分类算法。本文将从理论介绍开始,搞清楚什么是逻辑回归、回归系数、算法思想、工作原理及其优缺点等。进一步通过两个实际案例深化理解逻辑回归,以及在工程应用进行实现。(本文原创,转载必须注明出处: 一步步教你轻松学逻辑回归模型算法

    目录

    机器学习:一步步教你轻松学KNN模型算法

    机器学习:一步步教你轻松学决策树算法

    机器学习:一步步教你轻松学朴素贝叶斯模型算法理论篇1 

    机器学习:一步步教你轻松学朴素贝叶斯模型实现篇2 

    机器学习:一步步教你轻松学朴素贝叶斯模型算法Sklearn深度篇3

    机器学习:一步步教你轻松学逻辑回归模型算法

    机器学习:一步步教你轻松学K-means聚类算法

    机器学习:一步步教你轻松学关联规则Apriori算法

    机器学习: 一步步教你轻松学支持向量机SVM算法之理论篇1

    10 机器学习: 一步步教你轻松学支持向量机SVM算法之案例篇2

    11 机器学习: 一步步教你轻松学主成分分析PCA降维算法

    12 机器学习: 一步步教你轻松学支持向量机SVM降维算法

    更多文章请点击这里>>

    理论介绍

    逻辑回归和Sigmoid 函数

    逻辑回归

    回归:假设现在有一些数据点,我们用一条直线对这些点进行拟合(这条直线称为最佳拟合直线),这个拟合的过程就叫做回归。

    逻辑回归(Logistic Regression)是一种用于解决二分类(0 or 1)问题的机器学习方法,用于估计某种事物的可能性。比如某用户购买某商品的可能性,某病人患有某种疾病的可能性,以及某广告被用户点击的可能性等。 注意,这里用的是“可能性”,而非数学上的“概率”,logisitc回归的结果并非数学定义中的概率值,不可以直接当做概率值来用。该结果往往用于和其他特征值加权求和,而非直接相乘。

    Sigmoid 函数

    Sigmoid函数是一个常见的S型数学函数,在信息科学中,由于其单增以及反函数单增等性质,Sigmoid函数常被用作神经网络的阈值函数,将变量映射到0,1之间。在逻辑回归、人工神经网络中有着广泛的应用。Sigmoid函数的数学形式是:

    对x求导可以推出如下结论:

    下图给出了 Sigmoid 函数在不同坐标尺度下的两条曲线图。当 x 为 0 时,Sigmoid 函数值为 0.5 。随着 x 的增大,对应的 Sigmoid 值将逼近于 1 ; 而随着 x 的减小, Sigmoid 值将逼近于 0 。如果横坐标刻度足够大, Sigmoid 函数看起来很像一个阶跃函数。


    因此,为了实现 Logistic 回归分类器,我们可以在每个特征上都乘以一个回归系数,然后把所有结果值相加,将这个总和代入 Sigmoid 函数中,进而得到一个范围在 0~1 之间的数值。任何大于 0.5 的数据被分入 1 类,小于 0.5 即被归入 0 类。所以,Logistic 回归也是一种概率估计,比如这里Sigmoid 函数得出的值为0.5,可以理解为给定数据和参数,数据被分入 1 类的概率为0.5。(注意:针对二分类问题,0.5不是唯一确定分类的值,你可以根据需求调整这个概率值。)

    逻辑回归与线性回归的关系

    逻辑回归(Logistic Regression)与线性回归(Linear Regression)都是一种广义线性模型(generalized linear model)。逻辑回归假设因变量 y 服从伯努利分布,而线性回归假设因变量 y 服从高斯分布。 因此与线性回归有很多相同之处,去除Sigmoid映射函数的话,逻辑回归算法就是一个线性回归。可以说,逻辑回归是以线性回归为理论支持的,但是逻辑回归通过Sigmoid函数引入了非线性因素,因此可以轻松处理0/1分类问题。

    最优化方法的回归系数

    Sigmoid 函数的输入记为 z ,由下面公式得到:

    如果采用向量的写法,上述公式可以写成 Sigmoid 函数计算公式向量形式 ,它表示将这两个数值向量对应元素相乘然后全部加起来即得到 z 值。其中的向量 x 是分类器的输入数据,向量 w 也就是我们要找到的最佳参数(系数),从而使得分类器尽可能地精确。为了寻找该最佳参数,需要用到最优化理论的一些知识。我们这里使用的是——梯度上升法(Gradient Ascent)。

    梯度上升与梯度下降

    梯度

    对于梯度这个词一些人比较陌生,我们先看看维基百科的解释:在向量微积分中,标量场(向量场)中某一点的梯度指向在这点标量场增长最快的方向(当然要比较的话必须固定方向的长度),梯度的绝对值是长度为1的方向中函数最大的增加率,也就是说,其中 代表方向导数。

    • 在单变量的实值函数的情况,梯度只是导数,或者,对于一个线性函数,也就是线的斜率。
    • 梯度一词有时用于斜度,也就是一个曲面沿着给定方向的倾斜程度。可以通过取向量梯度和所研究的方向的内积来得到斜度。梯度的数值有时也被称为梯度。(更多梯度相关知识参照维基百科词条

    梯度形式化描述

    考虑一座高度在 (x, y)点是 H(x, y)的山。H这一点的梯度是在该点坡度(或者说斜度)最陡的方向。梯度的大小告诉我们坡度到底有多陡。这个现象可以如下数学的表示。山的高度函数 H的梯度点积一个单位向量给出了表面在该向量的方向上的斜率。这称为方向导数。

    理解梯度

    为了大家更容易理解什么是梯度,我们介意向量的概念,向量是一个矢量具有大小和方向的。同样,梯度也可以类比为具备大小和方向的这么一个概念。其两者比较如下:(这里严格意义上讲是不成立的,便于大家理解。)

    向量 = 值 + 方向  
    梯度 = 向量
    梯度 = 梯度值 + 梯度方向
    

    梯度上升

    要找到某函数的最大值,最好的方法是沿着该函数的梯度方向探寻。如果梯度记为 ▽ ,则函数 f(x, y) 的梯度由下式表示:

    这个梯度意味着要沿 x 的方向移动 ,沿 y 的方向移动。其中,函数f(x, y) 必须要在待计算的点上有定义并且可微。下图是一个具体的例子。


    上图展示的,梯度上升算法到达每个点后都会重新估计移动的方向。从 P0 开始,计算完该点的梯度,函数就根据梯度移动到下一点 P1。在 P1 点,梯度再次被重新计算,并沿着新的梯度方向移动到 P2 。如此循环迭代,直到满足停止条件。迭代过程中,梯度算子总是保证我们能选取到最佳的移动方向。

    上图中的梯度上升算法沿梯度方向移动了一步。可以看到,梯度算子总是指向函数值增长最快的方向。这里所说的是移动方向,而未提到移动量的大小。该量值称为步长,记作 α 。用向量来表示的话,梯度上升算法的迭代公式如下:

    例如:y = w0 + w1x1 + w2x2 + ... + wnxn
    梯度:参考上图的例子,二维图像,x方向代表第一个系数,也就是 w1,y方向代表第二个系数也就是 w2,这样的向量就是梯度。
    α:上面的梯度算法的迭代公式中的阿尔法,这个代表的是移动步长(step length)。移动步长会影响最终结果的拟合程度,最好的方法就是随着迭代次数更改移动步长。步长通俗的理解,100米,如果我一步走10米,我需要走10步;如果一步走20米,我只需要走5步。这里的一步走多少米就是步长的意思。
    ▽f(w):代表沿着梯度变化的方向,也可以理解该方向求导。
    

    该公式将一直被迭代执行,直至达到某个停止条件为止,比如迭代次数达到某个指定值或者算法达到某个可以允许的误差范围。

    梯度上升与梯度下降的区别

    梯度下降是大家听的最多的,本质上梯度下降与梯度上升算法是一样的,只是公司中加法变减法,梯度下降的公式如下:

    在求极值的问题中,有梯度上升和梯度下降两个最优化方法。梯度上升用于求最大值,梯度下降用于求最小值。如logistic回归的目标函数:代表的是概率,我们想求概率最大值,即对数似然函数的最大值,所以使用梯度上升算法。而线性回归的代价函数:代表的则是误差,我们想求误差最小值,所以用梯度下降算法。

    逻辑回归分类核心思想

    根据现有数据对分类边界建立回归公司,以此进行分类。回归即最佳拟合。

    逻辑回归工作原理

    每个回归系数初始化为 1
    重复 R 次:
        计算整个数据集的梯度
        使用 步长 x 梯度 更新回归系数的向量
    返回回归系数
    

    逻辑回归算法流程

    收集数据: 采用任意方法收集数据
    准备数据: 由于需要进行距离计算,因此要求数据类型为数值型。另外,结构化数据格式则最佳。
    分析数据: 采用任意方法对数据进行分析。
    训练算法: 大部分时间将用于训练,训练的目的是为了找到最佳的分类回归系数。
    测试算法: 一旦训练步骤完成,分类将会很快。
    使用算法: 首先,我们需要输入一些数据,并将其转换成对应的结构化数值;接着,基于训练好的回归系数就可以对这些数值进行简单的回归计算,判定它们属于哪个类别;
    

    逻辑回归优缺点

    优点: 计算代价不高,易于理解和实现。
    缺点: 容易欠拟合,分类精度可能不高。
    适用数据类型: 数值型和标称型数据。  
    

    案例分析1:Logistic回归在简单数据集上的分类

    案例描述

    在一个简单的数据集上,采用梯度上升法找到 Logistic 回归分类器在此数据集上的最佳回归系数

    开发流程

    收集数据: 可以使用任何方法
    准备数据: 由于需要进行距离计算,因此要求数据类型为数值型。另外,结构化数据格式则最佳
    分析数据: 画出决策边界
    训练算法: 使用梯度上升找到最佳参数
    测试算法: 使用 Logistic 回归进行分类
    使用算法: 对简单数据集中数据进行分类
    

    数据采集

    本文采用100行的测试集文本。其中前两列是特征1,和特征2,第三类是对应的标签。(这里特征1,特征2作为测试使用没有实际意义,你可以理解为特征1 是水里游的,特征2是有鱼鳞。类别判断是否为鱼类。)


    读取文本文件,加载数据集和类标签,这里将特征集第一列加1,便于后续回归系数的计算:

    '''加载数据集和类标签'''
    def loadDataSet(file_name):
        # dataMat为原始数据, labelMat为原始数据的标签
        dataMat,labelMat = [],[]
        fr = open(file_name)
        for line in fr.readlines():
            lineArr = line.strip().split(',')
            if len(lineArr) == 1:
                continue    # 这里如果就一个空的元素,则跳过本次循环
            # 为了方便计算,我们将每一行的开头添加一个 1.0 作为 X0
            dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])
            labelMat.append(int(lineArr[2]))
        return dataMat, labelMat
    

    梯度上升训练算法模型

    梯度上升算法

    使用梯度上升训练算法模型,其代码实现如下:

    ''' 正常的梯度上升法,得到的最佳回归系数 '''
    def gradAscent(dataMatIn, classLabels):
        dataMatrix = mat(dataMatIn)  # 转换为 NumPy 矩阵
        # 转化为矩阵[[0,1,0,1,0,1.....]],并转制[[0],[1],[0].....]
        # transpose() 行列转置函数
        # 将行向量转化为列向量   =>  矩阵的转置
        labelMat = mat(classLabels).transpose()  # 首先将数组转换为 NumPy 矩阵,然后再将行向量转置为列向量
        # m->数据量,样本数 n->特征数
        m, n = shape(dataMatrix) # 矩阵的行数和列数
        # print(m,n)
        alpha = 0.001  # alpha代表向目标移动的步长
        maxCycles = 500 # 迭代次数
        weights = ones((n, 1)) # 代表回归系数,ones((n,1)) 长度和特征数相同矩阵全是1
        for k in range(maxCycles):
            h = sigmoid(dataMatrix * weights)  # 矩阵乘法
            # labelMat是实际值
            error = (labelMat - h)  # 向量相减
            # 0.001* (3*m)*(m*1) 表示在每一个列上的一个误差情况,最后得出 x1,x2,xn的系数的偏移量
            weights = weights + alpha * dataMatrix.transpose() * error  # 矩阵乘法,最后得到回归系数
        return array(weights)
    

    其中sigmoid函数实现如下:

    ''' sigmoid跳跃函数 '''
    def sigmoid(ZVar):
        return 1.0 / (1 + exp(-ZVar))
    

    代码分析:函数的两个参数是数据加载返回的特征集和标签类集合。对数据集进行mat矩阵话转化,而类标签集进行矩阵之后转置,便于行列式的计算。然后设定步长,和迭代次数。整个特征矩阵与回归系数乘积求sigmoid值,最后返回回归系数的值。运行结果如下:

    [[ 4.12414349]
     [ 0.48007329]
     [-0.6168482 ]]
    

    思考?步长和迭代次数的初始值如何设定?

    随机梯度上升算法

    梯度上升算法在每次更新回归系数时都需要遍历整个数据集,该方法在处理 100 个左右的数据集时尚可,但如果有数十亿样本和成千上万的特征,那么该方法的计算复杂度就太高了。一种改进方法是一次仅用一个样本点来更新回归系数,该方法称为 随机梯度上升算法。由于可以在新样本到来时对分类器进行增量式更新,因而随机梯度上升算法是一个在线学习(online learning)算法。与 “在线学习” 相对应,一次处理所有数据被称作是 “批处理” (batch) 。其伪代码是:

    所有回归系数初始化为 1
    对数据集中每个样本
        计算该样本的梯度
        使用 alpha x gradient 更新回归系数值
    返回回归系数值
    

    随机梯度上升算法的代码实现如下:

    ''' 随机梯度上升'''
    # 梯度上升与随机梯度上升的区别?梯度下降在每次更新数据集时都需要遍历整个数据集,计算复杂都较高;随机梯度下降一次只用一个样本点来更新回归系数
    def stocGradAscent0(dataMatrix, classLabels):
        m, n = shape(dataMatrix)
        alpha = 0.01
        weights = ones(n)  # 初始化长度为n的数组,元素全部为 1
        for i in range(m):
            # sum(dataMatrix[i]*weights)为了求 f(x)的值,f(x)=a1*x1+b2*x2+..+nn*xn
            h = sigmoid(sum(dataMatrix[i] * weights))
            # 计算真实类别与预测类别之间的差值,然后按照该差值调整回归系数
            error = classLabels[i] - h
            # 0.01*(1*1)*(1*n)
            weights = array(weights) + alpha * error * array(mat(dataMatrix[i]))
        return array(weights.transpose())
    

    可以看到,随机梯度上升算法与梯度上升算法在代码上很相似,但也有一些区别: 第一,后者的变量 h 和误差 error 都是向量,而前者则全是数值;第二,前者没有矩阵的转换过程,所有变量的数据类型都是 NumPy 数组。

    判断优化算法优劣的可靠方法是看它是否收敛,也就是说参数是否达到了稳定值,是否还会不断地变化?下图展示了随机梯度上升算法在 200 次迭代过程中回归系数的变化情况。其中的系数2,也就是 X2 只经过了 50 次迭代就达到了稳定值,但系数 1 和 0 则需要更多次的迭代。如下图所示:


    针对波动问题,我们改进了之前的随机梯度上升算法,具体代码实现如下:

    ''' 改进版的随机梯度上升,使用随机的一个样本来更新回归系数'''
    def stocGradAscent1(dataMatrix, classLabels, numIter=150):
        m, n = shape(dataMatrix)
        weights = ones(n)  # 创建与列数相同的矩阵的系数矩阵
        # 随机梯度, 循环150,观察是否收敛
        for j in range(numIter):
            dataIndex = list(range(m)) # [0, 1, 2 .. m-1]
            for i in range(m):
                # i和j的不断增大,导致alpha的值不断减少,但是不为0
                alpha = 4 / (1.0 + j + i) + 0.0001 # alpha随着迭代不断减小非0
                # random.uniform(x, y) 随机生成下一个实数,它在[x,y]范围内
                Index = int(random.uniform(0, len(dataIndex)))
                # sum(dataMatrix[i]*weights)为了求 f(x)的值, f(x)=a1*x1+b2*x2+..+nn*xn
                h = sigmoid(sum(dataMatrix[dataIndex[Index]] * weights))
                error = classLabels[dataIndex[Index]] - h
                weights = weights + alpha * error *array(mat(dataMatrix[dataIndex[Index]]))
                del (dataIndex[Index])
        # print(weights.transpose())
        return weights.transpose()
    

    上面的改进版随机梯度上升算法改了两处代码。

    • 改进为 alpha 的值。alpha 在每次迭代的时候都会调整,这回缓解上面波动图的数据波动或者高频波动。另外,虽然 alpha 会随着迭代次数不断减少,但永远不会减小到 0,因为我们在计算公式中添加了一个常数项。
    • 修改为 randIndex 更新,这里通过随机选取样本拉来更新回归系数。这种方法将减少周期性的波动。这种方法每次随机从列表中选出一个值,然后从列表中删掉该值(再进行下一次迭代)。

    分析数据:画出决策边界

    边界可视化的代码实现如下:

    ''' 数据可视化展示 '''
    def plotBestFit(dataArr, labelMat, weights):
        n = shape(dataArr)[0]
        xcord1,xcord2,ycord1,ycord2 = [],[],[],[]
        for i in range(n):
            if int(labelMat[i]) == 1:
                xcord1.append(dataArr[i, 1])
                ycord1.append(dataArr[i, 2])
            else:
                xcord2.append(dataArr[i, 1])
                ycord2.append(dataArr[i, 2])
    
        fig = plt.figure()
        ax = fig.add_subplot(111)
        ax.scatter(xcord1, ycord1, s=30, c='red', marker='s')
        ax.scatter(xcord2, ycord2, s=30, c='green')
        x = arange(-3.0, 3.0, 0.1)
        """
        dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])
        w0*x0+w1*x1+w2*x2=f(x)
        x0最开始就设置为1, x2就是我们画图的y值,而f(x)被我们磨合误差给算到w0,w1,w2身上去了
        所以: w0+w1*x+w2*y=0 => y = (-w0-w1*x)/w2
        """
        y = (-weights[0] - weights[1] * x) / weights[2]
        ax.plot(x, y)
        plt.xlabel('X')
        plt.ylabel('Y')
        plt.show()
    

    运行结果分别是:

    梯度上升算法可视化结果图1-1:





    图1-1 梯度上升算法分类

    随机梯度上升算法可视化结果:


    图1-2 随机梯度上升算法分类

    优化随机梯度上升算法可视化结果:


    图1-3 优化随机梯度上升算法分类

    结果分析:

    图1-1的梯度上升算法在每次更新回归系数时都需要遍历整个数据集,虽然分类结果还不错该方法的计算复杂度就太高了。图1-2的随机梯度上升算法虽然分类效果不是很好(分类1/3左右),但是其迭代次数远远小于图1-1迭代次数(500次)。整体性能有所改进,但是其存在局部波动现象。基于此改进后的图1-3效果显示好很多。

    测试算法: 使用Logistic回归进行分类

    代码实现如下:

    '''数据集决策可视化'''
    def simpleTest(file_name):
        # 1.收集并准备数据
        dataMat, labelMat = loadDataSet(file_name)
        # 2.训练模型,  f(x)=a1*x1+b2*x2+..+nn*xn中 (a1,b2, .., nn).T的矩阵值
        dataArr = array(dataMat)
        weights = stocGradAscent1(dataArr, labelMat)
        # 数据可视化
        plotBestFit(dataArr, labelMat, weights)
    

    案例分析2:从病毒性流感预测病人的死亡情况

    案例描述

    使用 Logistic 回归来预测病毒性流感预测病人的死亡问题。这个数据集中包含了医院检测病毒性流感的一些指标,有的指标比较主观,有的指标难以测量,例如人的疼痛级别。

    开发流程
    收集数据: 给定数据文件
    准备数据: 用 Python 解析文本文件并填充缺失值
    分析数据: 可视化并观察数据
    训练算法: 使用优化算法,找到最佳的系数
    测试算法: 为了量化回归的效果,需要观察错误率。根据错误率决定是否回退到训练阶段,
    通过改变迭代的次数和步长的参数来得到更好的回归系数
    使用算法: 实现一个简单的命令行程序来收集马的症状并输出预测结果并非难事,
    这可以作为留给大家的一道习题

    收集数据: 给定数据文件

    训练数据已经给出,这里对文件处理即可,代码如下:

    '''加载数据集和类标签2'''
    def loadDataSet2(file_name):
        frTrain = open(file_name)
        trainingSet,trainingLabels = [],[]
        for line in frTrain.readlines():
            currLine = line.strip().split(',')
            # print(len(currLine))
            lineArr = []
            for i in range(len(currLine)-1):
                lineArr.append(float(currLine[i]))
            trainingSet.append(lineArr)
            trainingLabels.append(float(currLine[len(currLine)-1]))
        return trainingSet,trainingLabels
    

    准备数据: 用 Python 解析文本文件并填充缺失值

    处理数据中的缺失值

    假设有100个样本和20个特征,这些数据都是机器收集回来的。若机器上的某个传感器损坏导致一个特征无效时该怎么办?此时是否要扔掉整个数据?这种情况下,另外19个特征怎么办? 它们是否还可以用?答案是肯定的。因为有时候数据相当昂贵,扔掉和重新获取都是不可取的,所以必须采用一些方法来解决这个问题。下面给出了一些可选的做法:

    • 使用可用特征的均值来填补缺失值;
    • 使用特殊值来填补缺失值,如 -1;
    • 忽略有缺失值的样本;
    • 使用有相似样本的均值添补缺失值;
    • 使用另外的机器学习算法预测缺失值。

    现在,我们对下一节要用的数据集进行预处理,使其可以顺利地使用分类算法。在预处理需要做两件事:所有的缺失值必须用一个实数值来替换,因为我们使用的 NumPy 数据类型不允许包含缺失值。我们这里选择实数 0 来替换所有缺失值,恰好能适用于 Logistic 回归。这样做的直觉在于,我们需要的是一个在更新时不会影响系数的值。回归系数的更新公式如下:
    weights = weights + alpha * error * dataMatrix[dataIndex[randIndex]]
    如果 dataMatrix 的某个特征对应值为 0,那么该特征的系数将不做更新,即:weights = weights
    另外,由于 Sigmoid(0) = 0.5 ,即它对结果的预测不具有任何倾向性,因此我们上述做法也不会对误差造成任何影响。基于上述原因,将缺失值用 0 代替既可以保留现有数据,也不需要对优化算法进行修改。此外,该数据集中的特征取值一般不为 0,因此在某种意义上说它也满足 “特殊值” 这个要求。
    如果在测试数据集中发现了一条数据的类别标签已经缺失,那么我们的简单做法是将该条数据丢弃。这是因为类别标签与特征不同,很难确定采用某个合适的值来替换。采用 Logistic 回归进行分类时这种做法是合理的,而如果采用类似 kNN 的方法,则保留该条数据显得更加合理。

    训练算法: 使用优化算法,找到最佳的系数

    训练算法模型代码如下:

    '''测试Logistic算法分类'''
    def testClassier():
        # 使用改进后的随机梯度上升算法 求得在此数据集上的最佳回归系数 trainWeights
        file_name = './HorseColicTraining.txt'
        trainingSet,trainingLabels = loadDataSet2(file_name)
        trainWeights = stocGradAscent1(array(trainingSet), trainingLabels, 500)
        # 根据特征向量预测结果
        teststr = '2.000000,1.000000,38.300000,40.000000,24.000000,1.000000,1.000000,3.000000,1.000000,3.000000,3.000000,1.000000,0.000000,0.000000,0.000000,1.000000,1.000000,33.000000,6.700000,0.000000,0.000000'
        currLine = teststr.strip().split(',')
        lineArr = []
        for i in range(len(currLine)):
            lineArr.append(float(currLine[i]))
        res = classifyVector(array(lineArr), trainWeights)
        # 打印预测结果
        reslut = ['死亡','存活']
        print('预测结果是:',int(res))
    

    分类函数代码如下:

    '''分类函数,根据回归系数和特征向量来计算 Sigmoid的值,大于0.5函数返回1,否则返回0'''
    def classifyVector(featuresV, weights):
        prob = sigmoid(sum(featuresV * weights))
        print(prob)
        if prob > 0.9: return 1.0
        else: return 0.0
    

    测试算法:使用决策树执行分类

    为了量化回归的效果,需要观察错误率。根据错误率决定是否回退到训练阶段,通过改变迭代的次数和步长的参数来得到更好的回归系数

    '''打开测试集和训练集,并对数据进行格式化处理'''
    def colicTest():
        file_name = './HorseColicTraining.txt'
        trainingSet,trainingLabels = loadDataSet2(file_name)
        # 使用改进后的随机梯度上升算法 求得在此数据集上的最佳回归系数 trainWeights
        trainWeights = stocGradAscent1(array(trainingSet), trainingLabels, 500)
        frTest = open('./HorseColicTest.txt')
        errorCount = 0 ; numTestVec = 0.0
        # 读取 测试数据集 进行测试,计算分类错误的样本条数和最终的错误率
        for line in frTest.readlines():
            numTestVec += 1.0
            currLine = line.strip().split(',')
            lineArr = []
            for i in range(21):
                lineArr.append(float(currLine[i]))
            if int(classifyVector(array(lineArr), trainWeights)) != int(
                    currLine[21]):
                errorCount += 1
        errorRate = (float(errorCount) / numTestVec)
        print("逻辑回归算法测试集的错误率为: %f" % errorRate)
        return errorRate
    
    
    # 调用 colicTest() 10次并求结果的平均值
    def multiTest():
        numTests = 10;errorSum = 0.0
        for k in range(numTests):
            errorSum += colicTest()
        print("迭代 %d 次后的平均错误率是: %f" % (numTests, errorSum / float(numTests)))
    

    其运行结果如下:

    逻辑回归算法测试集的错误率为: 0.298507
    

    参考文献

    1. scikit中文社区:http://sklearn.apachecn.org/cn/0.19.0/
    2. 中文维基百科:https://zh.wikipedia.org/wiki/%E9%82%8F%E8%BC%AF%E8%BF%B4%E6%AD%B8
    3. GitHub:https://github.com/BaiNingchao/MachineLearning-1
    4. 图书:《机器学习实战》
    5. 图书:《自然语言处理理论与实战》

    完整代码下载

    源码请进【机器学习和自然语言QQ群:436303759】文件下载:


    作者声明

    本文版权归作者所有,旨在技术交流使用。未经作者同意禁止转载,转载后需在文章页面明显位置给出原文连接,否则相关责任自行承担。

     

     

     

     

     

     

     

     

    展开全文
  • 什么是逻辑回归

    千次阅读 2018-04-11 00:00:00
    逻辑回归(Logistic Regression,也译作“对数几率回归”)离散选择法模型之一,属于多重变量分析范畴,社会学、生物统计学、临床、数量心理学、计量经济学、市场营销等统计实证分析的常用方法。1符号约定逻辑...
  • 机器学习之分类算法逻辑回归

    千次阅读 2020-04-16 12:55:54
    什么是逻辑回归? 将线性回归的式子作为的输入,进行二分类。 应用场景: 广告点击率 判断用户的性别 预测用户是否会购买给定的商品类 判断一条评论正面的还是负面的 二分类问题等 逻辑回归公式 z=回归的...
  • 逻辑回归

    2020-12-09 00:40:59
    逻辑回归是一种分类算法,虽然名字中带有回归 由于算法的简单和高效,在实际中应用非常广泛 1.2 特点 解决的是一个二分类问题 逻辑回归的输入是线性回归的输出 1.3 应用场景 广告点击率 是否为垃圾邮件 是否患病...
  • 逻辑回归介绍

    2021-04-18 21:34:15
    逻辑回归(Logistic Regression)是机器学习中的一种分类模型,逻辑回归是一种分类算法,虽然名字中带有回归,但是它与回归之间有一定的联系。由于算法的简单和高效,在实际中应用非常广泛。 1 逻辑回归的应用...
  • 机器学习-逻辑回归

    2018-10-27 20:17:14
    逻辑回归算法是分类算法,可能它的名字里出现了“回归”让我们以为它属于回归问题,但逻辑回归算法实际上一种分类算法,它主要处理当 yyy 取值离散的情况,如:1 0 。 为什么不使用线性回归算法处理分类问题 ...
  • 1 什么是逻辑回归 Logistic属于概率型非线性回归,分为二分类和多分类的回归模型。对于二分类的逻辑回归只有和否两个取值,记为1和0,在自变量xi(i从1到n),y取的概率为P,y取否的概率为1-P,研究的当y取...
  • 逻辑回归(Logistic Regression)是机器学习中的一种分类模型,逻辑回归是一种分类算法,虽然名字中带有回归,但是它与回归之间有一定的联系。由于算法的简单和高效,在实际中应用非常广泛。 广告点击率 是否为垃圾...
  • 逻辑回归+Python3实现

    2020-09-07 10:14:59
    什么是逻辑回归2. 逻辑回归的判定边界3.代价函数4.Python3实现逻辑回归5.总结 1.什么是逻辑回归 logistic回归又称logistic回归分析,一种广义的线性回归分析模型。常用于数据挖掘,疾病自动诊断,经济预测等领域。...
  • 逻辑回归问题被扩展到多线性分类问题时,第一步要解决的还是计算概率的问题,即该点属于每个类别的概率多少,选择概率最大的类为该点所在的类。然后根据概率计算公式构建目标函数,然后用梯...
  • 什么是逻辑回归逻辑回归算法应用非常广泛,他用来解决...所以,逻辑回归就是根据事物的特征值,最后能够输出判别这个事物属于什么类别的一种方法。 如何更加特征值获得分类结果? 首先看下面2个公式: p^\...
  • 本次从概率统计角度来记录一下关于逻辑回归算法的理解。首先通俗的介绍一下极大似然估计概念。 极大似然估计 上面给出的文章中已经通俗的介绍了什么是极大似然估计,总结一下就是: 事先已经知道了此样本属于何种...
  • 逻辑斯蒂回归(logistic distribution)适用于多类分类问题,它对数线性模型,属于判别模型。 优点:计算代价不高,易于理解和实现。 缺点:容易欠拟合,分类精度可能不高。 模型 在讲逻辑斯蒂回归模型之前,我们先...
  • 在学习了基本的Theano的概念之后,我们可以将这些知识用来进行...我们可以通过一个简单的例子来说明什么是逻辑回归算法,假设在三维空间中,有一组待分类的点,同时有一系平面,代表这些点应该属于的类别,我们将通过
  • 逻辑回归本质分类问题,而且二分类问题,不属于回归,但是为什么又叫回归呢。我们可以这样理解,逻辑回归就是用回归的办法来做分类。它在线性回归的基础上,通过Sigmoid函数进行了非线性转换,从而具有更强的...
  • 支持向量机,逻辑回归,决策树等经典的机器学习算法主要用于分类问题,即根据一些已经给定的类别的样本,训练某种分类器,使得他能够对类别未知的样本进行分类。 与分类问题不同,聚类事先并不知道任何样本标签的...
  • 就如同线性回归、逻辑回归一样。那么BB了这么久,它到底谁了?没错,就是K-Means算法。没错,K-Means非常常见的聚类算法,所以它数以非监督学习的算法。这个算法最大的特点简单,好理解,运算速度快,但是只能...
  • )Logistic回归是一种涉及线性判别的分类算法。那是什么意思?1.与实测回归法不同,逻辑回归不会尝试在给定一组输入的情况下预测数值变量的值。相反,输出是给定输入点属于某个类的概率。为简单起见,假设我们只有两...
  • 支撑向量机(SVM)   我们将开始学习一种新的机器学习算法...下面一个二维的特征平面,所有的样本点分成了两类,逻辑回归就是在该平面中找到了一个决策边界,如果在决策边界的一侧,我们的算法就认为这些数据属于
  • 决策树一种逻辑简单的机器学习算法,可用作分类,也可用作回归属于监督学习(Supervised learning)。 决策树的模型表达式f(x)很难被写出,却很容易被画出 决策树一种树形结构: 树形结构: ①结点+有向边 ...

空空如也

空空如也

1 2 3 4
收藏数 64
精华内容 25
关键字:

逻辑回归是属于什么算法