逻辑回归函数为什么用sigmoid函数

机器学习之逻辑回归(Logistic Regression) - 推酷
机器学习之逻辑回归(Logistic Regression)
1. Classification
这篇文章我们来讨论分类问题(classification problems),也就是说你想预测的变量 y 是一个离散的值。我们会使用逻辑回归算法来解决分类问题。
之前的文章中,我们讨论的垃圾邮件分类实际上就是一个分类问题。类似的例子还有很多,例如一个在线交易网站判断一次交易是否带有欺诈性(有些人可以使用偷来的信用卡,你懂的)。再如,之前判断一个肿瘤是良性的还是恶性的,也是一个分类问题。
在以上的这些例子中,我们想预测的是一个二值的变量,或者为0,或者为1;或者是一封垃圾邮件,或者不是;或者是带有欺诈性的交易,或者不是;或者是一个恶性肿瘤,或者不是。
我们可以将因变量(dependant variable)可能属于的两个类分别称为负向类(negative class)和正向类(positive class)。可以使用0来代表负向类,1来代表正向类。
现在,我们的分类问题仅仅局限在两类上:0或者1。之后我们会讨论多分类问题,也就是说,变量 y 可以取多个值,例如0,1,2,3。
那么,我们如何来解决一个分类问题呢?来看以下例子:
现在有这样一个分类任务,需要根据肿瘤大小来判断肿瘤的良性与否。训练集如上图所示,横轴代表肿瘤大小,纵轴表示肿瘤的良性与否,注意,纵轴只有两个取值,1(代表恶性肿瘤)和0(代表良性肿瘤)。
通过之前的博文,我们已经知道对于以上数据集使用线性回归来处理,实际上就是用一条直线去拟合这些数据。因此,你得到的 Hypothesis 可能如下:
那么,如果你想做出预测,一种可行的方式是如下:
从以上这个例子来看,似乎线性回归也能很好的解决分类问题。现在,我们对以上问题稍作一些改动。
将横轴向右扩展,并且增加一个训练样本,如下:
此时,我们使用线性回归,会得到一条新的直线:
此时,我们再用0.5作为阈值来预测肿瘤的良性与否,就不合适了。
2. Hypothesis Representation
3. Decision boundary
强调一下,决策边界不是训练集的属性,而是假设本身及其参数的属性。只要我们给定了参数向量θ,决策边界就确定了。我们不是用训练集来定义的决策边界,我们用训练集来拟合参数θ,以后我们将谈论如何做到这一点。但是,一旦你有参数θ它就确定了决策边界。
4. Cost function
现在我们来讨论如何拟合逻辑回归中模型的参数θ。
具体来说,
我们需要定义optimization objective 或者 cost function 来拟合参数θ
,这便是监督学习问题中的逻辑回归模型的拟合问题。
如上图所示,我们有一个训练集,里面有m个训练样本,同之前一样,我们的每个样本使用n+1维的特征向量表示(x 0 = 1)。并且由于是分类问题,我们训练集中的所有y,取值不是0就是1。假设函数的参数即为θ。那么,对于这个给定的训练集,我们如何拟合参数θ(或者说是选择参数θ)?
之前,我们使用线性回归模型来拟合假说参数θ时,使用了如下的代价函数,我们稍作改变,将原先的1/2m中的原先的1/2放到了求和符号里面去了。
现在我们使用另一种方式,来书写代价函数:
现在,我们能更清楚的看到代价函数是这个Cost函数(代价项)在训练集范围上的求和,再求均值(乘以1/m)。
我们稍微简化一下这个式子,去掉这些上标会显得方便一些,所以Cost函数直接定义为:
对这个代价项(Cost函数)的理解是这样的:y我所期望的值,通过学习算法如果想要达到这个值,那么假设h(x)所需要付出的代价即为这个代价项。这个希望的预测值是h(x),而实际值则是y,干脆,全部去掉那些上标好了。
显然,在线性回归中,代价项(Cost函数)会被定义为:1/2乘以预测值h和实际值观测的结果y的差的平方。这个代价值可以很好地用在线性回归里,但是对于逻辑回归却是不合适的。
如果我们可以最小化代价函数J(θ)中的代价项(Cost函数),那么我们的确可以使用该代价项。但实际上,如果我们使用该代价项,那么代价函数J(θ)会变成关于参数θ的非凸函数。Why?
对于逻辑回归来说,这里的h函数是非线性的:
是一个很复杂的非线性函数,因此如果用h函数来构造我们在线性回归中所使用的代价项(Cost函数),接着再用该代价项来构造代价函数J(θ)。
那么J(θ)可能是一个这样的函数,有很多局部最优值:
实际上,这就是一个非凸函数。
不难发现,如果你把梯度下降法用在一个这样的函数上的话,我们并不能保证它会收敛到全局最小值。
显然,我们希望我们的代价函数J(θ)是一个凸函数,也就是一个单弓形函数,如下图所示:
如果对它使用梯度下降法,那么我们可以保证梯度下降法会收敛到该函数的全局最小值。
因此我们在逻辑回归中使用这个代价项(Cost函数)的问题在于非线性的sigmoid函数的出现导致J(θ)成为一个非凸函数。
我们需要做的是,另外找一个本身是凸函数的代价项(Cost函数),可以让我们使用类似于梯度下降的算法来找到一个全局最小值。以下就是一个我们将要在逻辑回归中使用的代价项(Cost函数):
5. Simplified cost function and gradient descent
注意,此时θ是变量。我们的目标就是找出使J(θ)最小的θ值。
已发表评论数()
已收藏到推刊!
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
没有分页内容
图片无法显示
视频无法显示
与原文不一致逻辑回归(Logistic&Regression)与梯度上升算法
第一眼看到逻辑回归(Logistic
Regression)这个词时,脑海中没有任何概念,读了几页后,发现这非常类似于神经网络中单个神经元的分类方法。
书中逻辑回归的思想是用一个超平面将数据集分为两部分,这两部分分别位于超平面的两边,且属于两个不同类别(和SVM的想法有些相似),如下图:
<img STYLE="BorDer-BoTToM: BorDer-LeFT: MAx-WiDTH: 100%; BorDer-Top: BorDer-riGHT: medium none" ALT="" src="/blog7style/images/common/sg_trans.gif" real_src ="http://img.blog.csdn.net/26562"
TITLE="逻辑回归(Logistic&Regression)与梯度上升算法" />
因此,一般的逻辑回归只能处理两分类问题,同时两个类别必须是线性可分的。对于线性不可分问题,在SVM中,可以使用核函数升维的方式解决,不过那都是后话了。还是先看看逻辑回归吧。
一、Sigmoid函数
了解神经网络的朋友想必不会对这个东西陌生,在神经网络中它就是所谓的激励函数,其最常用的一种表现形式如下:
<img STYLE="BorDer-BoTToM: BorDer-LeFT: MAx-WiDTH: 100%; BorDer-Top: BorDer-riGHT: medium none" ALT=""
TITLE="逻辑回归(Logistic&Regression)与梯度上升算法" />
函数曲线如下:
<img STYLE="BorDer-BoTToM: BorDer-LeFT: MAx-WiDTH: 100%; BorDer-Top: BorDer-riGHT: medium none" ALT="" src="/blog7style/images/common/sg_trans.gif" real_src ="http://img.blog.csdn.net/20906"
TITLE="逻辑回归(Logistic&Regression)与梯度上升算法" />
很显然它是对阶跃函数的一个很好的近似,当输入大于零时,输出趋近于1,输入小于零时,输出趋近于0,输入为0时,输出刚好为0.5。
在逻辑回归中,训练和分类所用数据的取值范围是任意的,因此我认为,Sigmoid在逻辑回归中除了有分类作用外,最主要作用是将数据映射到0和1之间,之后我会说明具体原因。
二、超平面与梯度上升(下降)
作为分界面的超平面定义如下:
<img STYLE="BorDer-BoTToM: BorDer-LeFT: MAx-WiDTH: 100%; BorDer-Top: BorDer-riGHT: medium none" ALT=""
TITLE="逻辑回归(Logistic&Regression)与梯度上升算法" />
其中可取x0 = 1,即将w0作为一个常量偏移。
通过该式可以计算得到一个z值,这个z值将作为Sigmoid函数的输入,其输出大于0.5和小于0.5分别表示两个不同的类别,也即实现了两分类。现在的问题是,给定一组训练数据,如何求出超平面中的系数,即w。
我们使用梯度上升算法进行优化求解。了解神经网络的朋友对梯度上升或梯度下降应该也很熟悉吧。一个函数的梯度定义为:
<img STYLE="BorDer-BoTToM: BorDer-LeFT: MAx-WiDTH: 100%; BorDer-Top: BorDer-riGHT: medium none" ALT=""
TITLE="逻辑回归(Logistic&Regression)与梯度上升算法" />
注意,这里并不是f(w)的导数,其中的w是一个向量,因此上式代表对w中每一个元素求偏导。
梯度是有方向的,总是指向函数值上升最快的方向,因此当我们沿着梯度方向或反方向行进时,就能达到一个函数的最大值或最小值处。因此,梯度上升算法就是根据下式不断更新w,直到梯度没有变化或变化很小,即函数达到了最大值:
<img STYLE="BorDer-BoTToM: BorDer-LeFT: MAx-WiDTH: 100%; BorDer-Top: BorDer-riGHT: medium none" ALT="" src="/blog7style/images/common/sg_trans.gif" real_src ="/gif.latex?/large&w=w&/alpha&/triangledown&f(w)"
TITLE="逻辑回归(Logistic&Regression)与梯度上升算法" />
其中alpha为沿着梯度行进的步长。
也许有人会问,如何用代码求函数的梯度,在Machine Learning In
Action一书中,作者没有解释,直接写出了以下几行代码:
从代码可以看出,作者用误差值error乘以输入数据矩阵的转置代表梯度,这里我就来尝试推导一下这个等式吧。
首先说明,我们的这个分类问题,可以等效为一个最小二乘问题,设:
<img STYLE="BorDer-BoTToM: BorDer-LeFT: MAx-WiDTH: 100%; BorDer-Top: BorDer-riGHT: medium none" ALT="" src="/blog7style/images/common/sg_trans.gif" real_src ="/gif.latex?/large&Aw=b"
TITLE="逻辑回归(Logistic&Regression)与梯度上升算法" />
其中A是包含训练数据的矩阵,也就是上面代码中的dataMatrix,w是我们要求的系数,而b是我们期望的每个训练样本乘以w后应该有的值,比如我们希望输入这个样本后,Sigmoid函数输出1,那么就应该期望这个样本乘以w后的值大于零,比如说20
要达到最好的分类,必然希望Aw中的每一项都接近b中的对应项,即要使下式达到最小:
<img STYLE="BorDer-BoTToM: BorDer-LeFT: MAx-WiDTH: 100%; BorDer-Top: BorDer-riGHT: medium none" ALT=""
TITLE="逻辑回归(Logistic&Regression)与梯度上升算法" />
这就是我们要优化的函数,于是对其求梯度,有:
<img STYLE="BorDer-BoTToM: BorDer-LeFT: MAx-WiDTH: 100%; BorDer-Top: BorDer-riGHT: medium none" ALT=""
TITLE="逻辑回归(Logistic&Regression)与梯度上升算法" />
<img STYLE="BorDer-BoTToM: BorDer-LeFT: MAx-WiDTH: 100%; BorDer-Top: BorDer-riGHT: medium none" ALT=""
TITLE="逻辑回归(Logistic&Regression)与梯度上升算法" />
由梯度的定义知:
<img STYLE="BorDer-BoTToM: BorDer-LeFT: MAx-WiDTH: 100%; BorDer-Top: BorDer-riGHT: medium none" ALT=""
TITLE="逻辑回归(Logistic&Regression)与梯度上升算法" />
由矩阵的微分方法可知(具体过程略):
<img STYLE="BorDer-BoTToM: BorDer-LeFT: MAx-WiDTH: 100%; BorDer-Top: BorDer-riGHT: medium none" ALT=""
TITLE="逻辑回归(Logistic&Regression)与梯度上升算法" />
<img STYLE="BorDer-BoTToM: BorDer-LeFT: MAx-WiDTH: 100%; BorDer-Top: BorDer-riGHT: medium none" ALT=""
TITLE="逻辑回归(Logistic&Regression)与梯度上升算法" />
<img STYLE="BorDer-BoTToM: BorDer-LeFT: MAx-WiDTH: 100%; BorDer-Top: BorDer-riGHT: medium none" ALT=""
TITLE="逻辑回归(Logistic&Regression)与梯度上升算法" />
最后合在一起可得:
<img STYLE="BorDer-BoTToM: BorDer-LeFT: MAx-WiDTH: 100%; BorDer-Top: BorDer-riGHT: medium none" ALT=""
TITLE="逻辑回归(Logistic&Regression)与梯度上升算法" />
其中(Aw - b)正好就是实际输出值与期望值的误差,前面的系数2和步长alpha合并,就得到了上面代码中所用的公式。
现在也可以解释用Sigmoid函数映射数据的作用了,如果不用Sigmoid函数,训练样本中的取值可能较大,因此误差值error也会较大,将这样的error值带入上式后,就会造成w的剧烈变化,最后甚至难以收敛,因此在代码中,作者将dataMatrix*weights的结果送入Sigmoid后才得到用于计算误差的输出结果,同时由于Sigmoid的使用,期望值b就和Label的值一样了(0和1),对代码的编写还起到简化作用。
以上是我的个人理解,如有错误或不严密的地方,还请指出!
三、代码实现
到具体实现代码时,以上算法就有一些问题了,首先,以上算法的步长值alpha是固定的,太小会使算法收敛很慢,太大又有不能收敛的可能。其次,以上算法的结果往往在一个最佳值附件来回震荡。为此我们使用随机梯度上升算法,在神经网络中也被称为LMS(最小均方)算法。
随机梯度上升算法与普通梯度上升算法不同在于,更新w时不使用全部训练样本,而只是从中随机选择一个样本来计算误差并更新w,这样通过多次迭代,每次都随机选择不同的样本,最终w趋于收敛,且结果与普通梯度上升算法没有差别,这种方式可以抑制结果的来回震荡。同时,使用可变的步长,使步长alpha随着迭代次数的增加而减小,这样可使算法在刚开始时,快速沿着梯度前进,当接近最佳值时,alpha减小,保证算法能正确收敛到最佳值上,从而在总体上加快算法的收敛速度。
由于随机梯度上升算法每次只取一个样本,和样本总体无关,所以它还是一种支持在线学习的算法。所谓在线就是指能实时处理新加入的训练数据,而不必从新将所有数据又处理一遍。
下面给出C#版本的实现:
最后总结一下逻辑回归的优缺点。
1、实现简单;
2、分类时计算量非常小,速度很快;
3、所需存储资源极低;
1、容易过拟合;
2、准确度可能不高;
3、只能处理两分类问题,且必须线性可分
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。From Ufldl
我们想用批量梯度上升法对logistic回归分析模型进行训练,其模型如下:
让我们遵从公开课程视频与CS229教学讲义的符号规范,设 ,于是 ,,
为截距。假设我们有m个训练样本{(, ) ,...,( , )},而批量梯度上升法的更新法则是: ,这里的
是对数似然函数, 是其导函数。
[注:下文的符号规范与&公开课程视频&或&教学讲义CS229:机器学习&中的相同,详细内容可以参见公开课程视频或教学讲义#1 ]
于是,我们需要如下计算梯度:
我们用Matlab/Octave风格变量x表示输入数据构成的样本矩阵,x(:,i)代表第 i个训练样本,x(j,i)就代表(译者注:第i个训练样本向量的第j个元素)。同样,用Matlab/Octave风格变量y表示由训练样本集合的全体类别标号所构成的行向量,则该向量的第i个元素y(i)就代表上式中的。(注意这里跟公开课程视频及CS229的符号规范不同,矩阵x按列而不是按行存放输入训练样本,同样,是行向量而不是列向量。)
以下是梯度运算代码的一种实现,非常恐怖,速度极慢:
grad = zeros&#40;n+1,1&#41;;
for i=1:m,
h = sigmoid&#40;theta'*x&#40;:,i&#41;&#41;;
temp = y&#40;i&#41; -
for j=1:n+1,
grad&#40;j&#41; = grad&#40;j&#41; + temp * x&#40;j,i&#41;;
嵌套的for循环语句使这段代码的运行非常缓慢。以下是更典型的实现方式,它对算法进行部分向量化,带来更优的执行效率:
grad = zeros&#40;n+1,1&#41;;
for i=1:m,
grad = grad + &#40;y&#40;i&#41; - sigmoid&#40;theta'*x&#40;:,i&#41;&#41;&#41;* x&#40;:,i&#41;;
但是,或许可以向量化得更彻底些。如果去除for循环,我们就可以显著地改善代码执行效率。特别的,假定b是一个列向量,A是一个矩阵,我们用以下两种方式来计算A*b:
% 矩阵-向量乘法运算的低效代码
grad = zeros&#40;n+1,1&#41;;
for i=1:m,
grad = grad + b&#40;i&#41; * A&#40;:,i&#41;;
% 通常写法为A(:,i)*b(i)
% 矩阵-向量乘法运算的高效代码
grad = A*b;
我们看到,代码2是用了低效的for循环语句执行梯度上升(译者注:原文是下降)运算,将b(i)看成(y(i) - sigmoid(theta'*x(:,i))),A看成x,我们就可以使用以下高效率的代码:
grad = x * &#40;y- sigmoid&#40;theta'*x&#41;&#41;;
这里我们假定Matlab/Octave的sigmoid(z)函数接受一个向量形式的输入z,依次对输入向量的每个元素施行sigmoid函数,最后返回运算结果,因此sigmoid(z)的输出结果是一个与z有相同维度的向量。
当训练数据集很大时,最终的实现(译者注:代码3)充分发挥了Matlab/Octave高度优化的数值线性代数库的优势来进行矩阵-向量操作,因此,比起之前代码要高效得多。
想采用向量化实现并非易事,通常需要周密的思考。但当你熟练掌握向量化操作后,你会发现,这里面有固定的设计模式(对应少量的向量化技巧),可以灵活运用到很多不同的代码片段中。
逻辑回归 Logistic Regression
批量梯度上升法 batch gradient ascent
截距 intercept term
对数似然函数 the log likelihood
导函数 derivative
梯度 gradient
林锋(),谭晓阳(x.tan@),邓亚峰()
| 逻辑回归的向量化实现样例 |
Language&:
Personal tools
This page was last modified on 8 April 2013, at 08:31.
This page has been accessed 27,828 times.[转]机器学习算法与Python实践之(七)逻辑回归(Logistic Regression)
zouxy09@;/zouxy09
机器学习算法与Python实践这个系列主要是参考《机器学习实战》这本书。因为自己想学习Python,然后也想对一些机器学习算法加深下了解,所以就想通过Python来实现几个比较常用的机器学习算法。恰好遇见这本同样定位的书籍,所以就参考这本书的过程来学习了。
这节学习的是逻辑回归(LogisticRegression),也算进入了比较正统的机器学习算法。啥叫正统呢?我概念里面机器学习算法一般是这样一个步骤:
1)对于一个问题,我们用数学语言来描述它,然后建立一个模型,例如回归模型或者分类模型等来描述这个问题;
2)通过最大似然、最大后验概率或者最小化分类误差等等建立模型的代价函数,也就是一个最优化问题。找到最优化问题的解,也就是能拟合我们的数据的最好的模型参数;
3)然后我们需要求解这个代价函数,找到最优解。这求解也就分很多种情况了:
a)如果这个优化函数存在解析解。例如我们求最值一般是对代价函数求导,找到导数为0的点,也就是最大值或者最小值的地方了。如果代价函数能简单求导,并且求导后为0的式子存在解析解,那么我们就可以直接得到最优的参数了。
b)如果式子很难求导,例如函数里面存在隐含的变量或者变量相互间存在耦合,也就互相依赖的情况。或者求导后式子得不到解释解,例如未知参数的个数大于已知方程组的个数等。这时候我们就需要借助迭代算法来一步一步找到最有解了。迭代是个很神奇的东西,它将远大的目标(也就是找到最优的解,例如爬上山顶)记在心上,然后给自己定个短期目标(也就是每走一步,就离远大的目标更近一点),脚踏实地,心无旁贷,像个蜗牛一样,一步一步往上爬,支撑它的唯一信念是:只要我每一步都爬高一点,那么积跬步,肯定能达到自己人生的巅峰,尽享山登绝顶我为峰的豪迈与忘我。
另外需要考虑的情况是,如果代价函数是凸函数,那么就存在全局最优解,方圆五百里就只有一个山峰,那命中注定了,它就是你要找的唯一了。但如果是非凸的,那么就会有很多局部最优的解,有一望无际的山峰,人的视野是伟大的也是渺小的,你不知道哪个山峰才是最高的,可能你会被命运作弄,很无辜的陷入一个局部最优里面,坐井观天,以为自己找到的就是最好的。没想到山外有山,人外有人,光芒总在未知的远处默默绽放。但也许命运眷恋善良的你,带给你的总是最好的归宿。也有很多不信命的人,觉得人定胜天的人,誓要找到最好的,否则不会罢休,永不向命运妥协,除非自己有一天累了,倒下了,也要靠剩下的一口气,迈出一口气能支撑的路程。好悲凉啊……哈哈。
呃,不知道扯那去了,也不知道自己说的有没有错,有错的话请大家不吝指正。那下面就进入正题吧。正如上面所述,逻辑回归就是这样的一个过程:面对一个回归或者分类问题,建立代价函数,然后通过优化方法迭代求解出最优的模型参数,然后测试验证我们这个求解的模型的好坏,冥冥人海,滚滚红尘,我们是否找到了最适合的那个她。
一、逻辑回归(LogisticRegression)
Logisticregression(逻辑回归)是当前业界比较常用的机器学习方法,用于估计某种事物的可能性。之前在经典之作《数学之美》中也看到了它用于广告预测,也就是根据某广告被用户点击的可能性,把最可能被用户点击的广告摆在用户能看到的地方,然后叫他“你点我啊!”用户点了,你就有钱收了。这就是为什么我们的电脑现在广告泛滥的原因了。
还有类似的某用户购买某商品的可能性,某病人患有某种疾病的可能性啊等等。这个世界是随机的(当然了,人为的确定性系统除外,但也有可能有噪声或产生错误的结果,只是这个错误发生的可能性太小了,小到千万年不遇,小到忽略不计而已),所以万物的发生都可以用可能性或者几率(Odds)来表达。“几率”指的是某事物发生的可能性与不发生的可能性的比值。
Logisticregression可以用来回归,也可以用来分类,主要是二分类。还记得上几节讲的支持向量机SVM吗?它就是个二分类的例如,它可以将两个不同类别的样本给分开,思想是找到最能区分它们的那个分类超平面。但当你给一个新的样本给它,它能够给你的只有一个答案,你这个样本是正类还是负类。例如你问SVM,某个女生是否喜欢你,它只会回答你喜欢或者不喜欢。这对我们来说,显得太粗鲁了,要不希望,要不绝望,这都不利于身心健康。那如果它可以告诉我,她很喜欢、有一点喜欢、不怎么喜欢或者一点都不喜欢,你想都不用想了等等,告诉你她有49%的几率喜欢你,总比直接说她不喜欢你,来得温柔。而且还提供了额外的信息,她来到你的身边你有多少希望,你得再努力多少倍,知己知彼百战百胜,哈哈。Logisticregression就是这么温柔的,它给我们提供的就是你的这个样本属于正类的可能性是多少。
还得来点数学。(更多的理解,请参阅参考文献)假设我们的样本是{x,y},y是0或者1,表示正类或者负类,x是我们的m维的样本特征向量。那么这个样本x属于正类,也就是y=1的“概率”可以通过下面的逻辑函数来表示:
这里θ是模型参数,也就是回归系数,σ是sigmoid函数。实际上这个函数是由下面的对数几率(也就是x属于正类的可能性和负类的可能性的比值的对数)变换得到的:
换句话说,y也就是我们关系的变量,例如她喜不喜欢你,与多个自变量(因素)有关,例如你人品怎样、车子是两个轮的还是四个轮的、长得胜过潘安还是和犀利哥有得一拼、有千尺豪宅还是三寸茅庐等等,我们把这些因素表示为x1,x2,…,xm。那这个女的怎样考量这些因素呢?最快的方式就是把这些因素的得分都加起来,最后得到的和越大,就表示越喜欢。但每个人心里其实都有一杆称,每个人考虑的因素不同,萝卜青菜,各有所爱嘛。例如这个女生更看中你的人品,人品的权值是0.6,不看重你有没有钱,没钱了一起努力奋斗,那么有没有钱的权值是0.001等等。我们将这些对应x1,x2,…, xm的权值叫做回归系数,表达为θ1,θ2,…,θm。他们的加权和就是你的总得分了。请选择你的心仪男生,非诚勿扰!哈哈。
所以说上面的logistic回归就是一个线性分类模型,它与线性回归的不同点在于:为了将线性回归输出的很大范围的数,例如从负无穷到正无穷,压缩到0和1之间,这样的输出值表达为“可能性”才能说服广大民众。当然了,把大值压缩到这个范围还有个很好的好处,就是可以消除特别冒尖的变量的影响(不知道理解的是否正确)。而实现这个伟大的功能其实就只需要平凡一举,也就是在输出加一个logistic函数。另外,对于二分类来说,可以简单的认为:如果样本x属于正类的概率大于0.5,那么就判定它是正类,否则就是负类。实际上,SVM的类概率就是样本到边界的距离,这个活实际上就让logisticregression给干了。
所以说,LogisticRegression就是一个被logistic方程归一化后的线性回归,仅此而已。
好了,关于LR的八卦就聊到这。归入到正统的机器学习框架下,模型选好了,只是模型的参数θ还是未知的,我们需要用我们收集到的数据来训练求解得到它。那我们下一步要做的事情就是建立代价函数了。
LogisticRegression最基本的学习算法是最大似然。啥叫最大似然,可以看看我的另一篇博文“从最大似然到EM算法浅解”。
假设我们有n个独立的训练样本{(x1,y1) ,(x2, y2),…,(xn, yn)},y={0,1}。那每一个观察到的样本(xi,yi)出现的概率是:
上面为什么是这样呢?当y=1的时候,后面那一项是不是没有了,那就只剩下x属于1类的概率,当y=0的时候,第一项是不是没有了,那就只剩下后面那个x属于0的概率(1减去x属于1的概率)。所以不管y是0还是1,上面得到的数,都是(x,y)出现的概率。那我们的整个样本集,也就是n个独立的样本出现的似然函数为(因为每个样本都是独立的,所以n个样本出现的概率就是他们各自出现的概率相乘):
那最大似然法就是求模型中使得似然函数最大的系数取值θ*。这个最大似然就是我们的代价函数(costfunction)了。
OK,那代价函数有了,我们下一步要做的就是优化求解了。我们先尝试对上面的代价函数求导,看导数为0的时候可不可以解出来,也就是有没有解析解,有这个解的时候,就皆大欢喜了,一步到位。如果没有就需要通过迭代了,耗时耗力。
我们先变换下L(θ):取自然对数,然后化简(不要看到一堆公式就害怕哦,很简单的哦,只需要耐心一点点,自己动手推推就知道了。注:有xi的时候,表示它是第i个样本,下面没有做区分了,相信你的眼睛是雪亮的),得到:
这时候,用L(θ)对θ求导,得到:
然后我们令该导数为0,你会很失望的发现,它无法解析求解。不信你就去尝试一下。所以没办法了,只能借助高大上的迭代来搞定了。这里选用了经典的梯度下降算法。
二、优化求解
2.1、梯度下降(gradientdescent)
Gradientdescent 又叫 steepestdescent,是利用一阶的梯度信息找到函数局部最优解的一种方法,也是机器学习里面最简单最常用的一种优化方法。它的思想很简单,和我开篇说的那样,要找最小值,我只需要每一步都往下走(也就是每一步都可以让代价函数小一点),然后不断的走,那肯定能走到最小值的地方,例如下图所示:
但,我同时也需要更快的到达最小值啊,怎么办呢?我们需要每一步都找下坡最快的地方,也就是每一步我走某个方向,都比走其他方法,要离最小值更近。而这个下坡最快的方向,就是梯度的负方向了。
对logisticRegression来说,梯度下降算法新鲜出炉,如下:
其中,参数α叫学习率,就是每一步走多远,这个参数蛮关键的。如果设置的太多,那么很容易就在最优值附加徘徊,因为你步伐太大了。例如要从广州到上海,但是你的一步的距离就是广州到北京那么远,没有半步的说法,自己能迈那么大步,是幸运呢?还是不幸呢?事物总有两面性嘛,它带来的好处是能很快的从远离最优值的地方回到最优值附近,只是在最优值附近的时候,它有心无力了。但如果设置的太小,那收敛速度就太慢了,向蜗牛一样,虽然会落在最优的点,但是这速度如果是猴年马月,我们也没这耐心啊。所以有的改进就是在这个学习率这个地方下刀子的。我开始迭代是,学习率大,慢慢的接近最优值的时候,我的学习率变小就可以了。所谓采两者之精华啊!这个优化具体见2.3。
梯度下降算法的伪代码如下:
################################################
初始化回归系数为1
重复下面步骤直到收敛{
计算整个数据集的梯度
使用alpha xgradient来更新回归系数
返回回归系数值
################################################
注:因为本文中是求解的Logit回归的代价函数是似然函数,需要最大化似然函数。所以我们要用的是梯度上升算法。但因为其和梯度下降的原理是一样的,只是一个是找最大值,一个是找最小值。找最大值的方向就是梯度的方向,最小值的方向就是梯度的负方向。不影响我们的说明,所以当时自己就忘了改过来了,谢谢评论下面@wxltt的指出。另外,最大似然可以通过取负对数,转化为求最小值。代码里面的注释也是有误的,写的代码是梯度上升,注销成了梯度下降,对大家造成的不便,希望大家海涵。
2.2、随机梯度下降SGD (stochasticgradient descent)
梯度下降算法在每次更新回归系数的时候都需要遍历整个数据集(计算整个数据集的回归误差),该方法对小数据集尚可。但当遇到有数十亿样本和成千上万的特征时,就有点力不从心了,它的计算复杂度太高。改进的方法是一次仅用一个样本点(的回归误差)来更新回归系数。这个方法叫随机梯度下降算法。由于可以在新的样本到来的时候对分类器进行增量的更新(假设我们已经在数据库A上训练好一个分类器h了,那新来一个样本x。对非增量学习算法来说,我们需要把x和数据库A混在一起,组成新的数据库B,再重新训练新的分类器。但对增量学习算法,我们只需要用新样本x来更新已有分类器h的参数即可),所以它属于在线学习算法。与在线学习相对应,一次处理整个数据集的叫“批处理”。
随机梯度下降算法的伪代码如下:
################################################
初始化回归系数为1
重复下面步骤直到收敛{
对数据集中每个样本
计算该样本的梯度
使用alpha xgradient来更新回归系数
返回回归系数值
################################################
2.3、改进的随机梯度下降
评价一个优化算法的优劣主要是看它是否收敛,也就是说参数是否达到稳定值,是否还会不断的变化?收敛速度是否快?
上图展示了随机梯度下降算法在200次迭代中(请先看第三和第四节再回来看这里。我们的数据库有100个二维样本,每个样本都对系数调整一次,所以共有次调整)三个回归系数的变化过程。其中系数X2经过50次迭代就达到了稳定值。但系数X1和X0到100次迭代后稳定。而且可恨的是系数X1和X2还在很调皮的周期波动,迭代次数很大了,心还停不下来。产生这个现象的原因是存在一些无法正确分类的样本点,也就是我们的数据集并非线性可分,但我们的logisticregression是线性分类模型,对非线性可分情况无能为力。然而我们的优化程序并没能意识到这些不正常的样本点,还一视同仁的对待,调整系数去减少对这些样本的分类误差,从而导致了在每次迭代时引发系数的剧烈改变。对我们来说,我们期待算法能避免来回波动,从而快速稳定和收敛到某个值。
对随机梯度下降算法,我们做两处改进来避免上述的波动问题:
1)在每次迭代时,调整更新步长alpha的值。随着迭代的进行,alpha越来越小,这会缓解系数的高频波动(也就是每次迭代系数改变得太大,跳的跨度太大)。当然了,为了避免alpha随着迭代不断减小到接近于0(这时候,系数几乎没有调整,那么迭代也没有意义了),我们约束alpha一定大于一个稍微大点的常数项,具体见代码。
2)每次迭代,改变样本的优化顺序。也就是随机选择样本来更新回归系数。这样做可以减少周期性的波动,因为样本顺序的改变,使得每次迭代不再形成周期性。
改进的随机梯度下降算法的伪代码如下:
################################################
初始化回归系数为1
重复下面步骤直到收敛{
对随机遍历的数据集中的每个样本
随着迭代的逐渐进行,减小alpha的值
计算该样本的梯度
使用alpha xgradient来更新回归系数
返回回归系数值
################################################
比较原始的随机梯度下降和改进后的梯度下降,可以看到两点不同:
1)系数不再出现周期性波动。2)系数可以很快的稳定下来,也就是快速收敛。这里只迭代了20次就收敛了。而上面的随机梯度下降需要迭代200次才能稳定。
三、Python实现
我使用的Python是2.7.5版本的。附加的库有Numpy和Matplotlib。具体的安装和配置见前面的博文。在代码中已经有了比较详细的注释了。不知道有没有错误的地方,如果有,还望大家指正(每次的运行结果都有可能不同)。里面我写了个可视化结果的函数,但只能在二维的数据上面使用。直接贴代码:
logRegression.py
[python] viewplaincopy
#################################################
# logRegression: Logistic Regression
# Author : zouxy
# HomePage : /zouxy09
: zouxy09@
#################################################
from numpy import *
import matplotlib.pyplot as plt
import time
# calculate the sigmoid function
def sigmoid(inX):
return 1.0 / (1 + exp(-inX))
# train a logistic regression model using some optional optimize algorithm
# input: train_x is a mat datatype, each row stands for one sample
train_y is mat datatype too, each row is the corresponding label
opts is optimize option include step and maximum number of iterations
def trainLogRegres(train_x, train_y, opts):
# calculate training time
startTime = time.time()
numSamples, numFeatures = shape(train_x)
alpha = opts[ alpha ]; maxIter = opts[ maxIter ]
weights = ones((numFeatures, 1))
# optimize through gradient descent algorilthm
for k in range(maxIter):
if opts[ optimizeType ] ==
gradDescent : # gradient descent algorilthm
output = sigmoid(train_x * weights)
error = train_y - output
weights = weights + alpha * train_x.transpose() * error
elif opts[ optimizeType ] ==
stocGradDescent : # stochastic gradient descent
for i in range(numSamples):
output = sigmoid(train_x[i, :] * weights)
error = train_y[i, 0] - output
weights = weights + alpha * train_x[i, :].transpose() * error
elif opts[ optimizeType ] ==
smoothStocGradDescent : # smooth stochastic gradient descent
# randomly select samples to optimize for reducing cycle fluctuations
dataIndex = range(numSamples)
for i in range(numSamples):
alpha = 4.0 / (1.0 + k + i) + 0.01
randIndex = int(random.uniform(0, len(dataIndex)))
output = sigmoid(train_x[randIndex, :] * weights)
error = train_y[randIndex, 0] - output
weights = weights + alpha * train_x[randIndex, :].transpose() * error
del(dataIndex[randIndex]) # during one interation, delete the optimized sample
raise NameError( Not support optimize method type! )
Congratulations, training complete! Took %fs!
% (time.time() - startTime)
return weights
# test your trained Logistic Regression model given test set
def testLogRegres(weights, test_x, test_y):
numSamples, numFeatures = shape(test_x)
matchCount = 0
for i in xrange(numSamples):
predict = sigmoid(test_x[i, :] * weights)[0, 0] & 0.5
if predict == bool(test_y[i, 0]):
matchCount += 1
accuracy = float(matchCount) / numSamples
return accuracy
# show your trained logistic regression model only available with 2-D data
def showLogRegres(weights, train_x, train_y):
# notice: train_x and train_y is mat datatype
numSamples, numFeatures = shape(train_x)
if numFeatures != 3:
Sorry! I can not draw because the dimension of your data is not 2!
# draw all samples
for i in xrange(numSamples):
if int(train_y[i, 0]) == 0:
plt.plot(train_x[i, 1], train_x[i, 2],
elif int(train_y[i, 0]) == 1:
plt.plot(train_x[i, 1], train_x[i, 2],
# draw the classify line
min_x = min(train_x[:, 1])[0, 0]
max_x = max(train_x[:, 1])[0, 0]
weights = weights.getA()
# convert mat to array
y_min_x = float(-weights[0] - weights[1] * min_x) / weights[2]
y_max_x = float(-weights[0] - weights[1] * max_x) / weights[2]
plt.plot([min_x, max_x], [y_min_x, y_max_x],
plt.xlabel( X1 ); plt.ylabel( X2 )
plt.show()
四、测试结果
测试代码:
test_logRegression.py
[python] viewplaincopy
#################################################
# logRegression: Logistic Regression
# Author : zouxy
# HomePage : /zouxy09
: zouxy09@
#################################################
from numpy import *
import matplotlib.pyplot as plt
import time
def loadData():
train_x = []
train_y = []
fileIn = open( E:/Python/Machine Learning in Action/testSet.txt )
for line in fileIn.readlines():
lineArr = line.strip().split()
train_x.append([1.0, float(lineArr[0]), float(lineArr[1])])
train_y.append(float(lineArr[2]))
return mat(train_x), mat(train_y).transpose()
## step 1: load data
step 1: load data...
train_x, train_y = loadData()
test_x = train_x; test_y = train_y
## step 2: training...
step 2: training...
opts = { alpha : 0.01,
maxIter : 20,
optimizeType :
smoothStocGradDescent }
optimalWeights = trainLogRegres(train_x, train_y, opts)
## step 3: testing
step 3: testing...
accuracy = testLogRegres(optimalWeights, test_x, test_y)
## step 4: show the result
step 4: show the result...
The classify accuracy is: %.3f%%
% (accuracy * 100)
showLogRegres(optimalWeights, train_x, train_y)
测试数据是二维的,共100个样本。有2个类。如下:
testSet.txt
[python] viewplaincopy
训练结果:
(a)梯度下降算法迭代500次。(b)随机梯度下降算法迭代200次。(c)改进的随机梯度下降算法迭代20次。(d)改进的随机梯度下降算法迭代200次。
[转]机器学习算法与Python实践之(七)逻辑回归(Logistic Regression)由用户自行发布,[转]机器学习算法与Python实践之(七)逻辑回归(Logistic Regression)内容不代表本站立场,请自行分辨真伪。

我要回帖

更多关于 逻辑回归函数 的文章

 

随机推荐