1.分类问题
如果我们要预测的变量y是一个离散情况下的分类问题,比如判断邮件是否是垃圾邮件。就要使用logistic回归算法:最广泛使用的算法之一。
如果之前的线性回归是一个预测问题,那么现在就是一个判断问题:是与不是
在分类问题中,我们尝试预测的是结果是否属于某一个类(例如正确或错误)。分类问题的例子有:判断一封电子邮件是否是垃圾邮件;判断一次金融交易是否是欺诈;之前我们也谈到了肿瘤分类问题的例子,区别一个肿瘤是恶性的还是良性的。
我们从二元的分类问题开始讨论。
我们将因变量(dependent variable)可能属于的两个类分别称为负向类(negative class)和正向类(positive class),则因变量y { 0,1},其中 0 表示负向类,1 表示正向类。
逻辑回归算法是分类算法,我们将它作为分类算法使用。有时候可能因为这个算法的名字中出现了“回归”使你感到困惑,但逻辑回归算法实际上是一种分类算法,它适用于标签 y取值离散的情况,如:1 0 0 1。
2.假说表示
在分类问题中,要用什么样的函数来表示我们的假设。希望我们的分类器的输出值在0和1之间,因此,我们希望想出一个满足某个性质的假设函数,这个性质是它的预测值要在0和1之间。
假设形式(sigmoid函数/logistic函数):
在给定x的条件下y = 1的概率θ。
python代码实现:
import numpy as np
def sigmoid(z):
return 1 / (1 + np.exp(-z))
3.判定边界
决策边界(decision boundary)的概念。这个概念能更好地帮助我们理解逻辑回归的假设函数在计算什么。
在逻辑回归中,我们预测:
当时,预测 。
当时,预测 。
根据上面绘制出的 S 形函数图像,我们知道当:
时
时
时
又 ,即: 时,预测 , 时,预测
现在假设我们有一个模型:
并且参数 是向量[-3 1 1]。 则当,即时,模型将预测 。 我们可以绘制直线,这条线便是我们模型的分界线,将预测为1的区域和预测为 0的区域分隔开。
假使我们的数据呈现这样的分布情况,怎样的模型才能适合呢?
因为需要用曲线才能分隔 的区域和 的区域,我们需要二次方特征:是[-1 0 0 1 1],则我们得到的判定边界恰好是圆点在原点且半径为1的圆形。
我们可以用非常复杂的模型来适应非常复杂形状的判定边界。
4.代价函数
如何拟合逻辑回归模型的参数。具体来说,我要定义用来拟合参数的优化目标或者叫代价函数,这便是监督学习问题中的逻辑回归模型的拟合问题。
对于线性回归模型,我们定义的代价函数是所有模型误差的平方和。理论上来说,我们也可以对逻辑回归模型沿用这个定义:
在线性回归中,最小化的带价值被定义为1/2乘以预测值h和实际观测值y的差的平方,实际上,在logistic回归中,它会变成参数θ的非凸函数,如果用梯度下降法可能就不会收敛到局部最优值。
所以我们需要另外找一个不同的代价函数,使它变成凸函数,从而可以使用梯度下降法找到局部最优值。
为了使代价函数在代入h(θ)后会变得很简单,构造函数如下:
它有一些有趣而且很好的性质:
当y = 1时:
有趣在哪里呢?
当实际情况为1,而代价函数预测也为1的时候,这个代价等于0符合预测
当实际情况为0,而代价函数预测为0的时候,这个算法计算出的代价值为无穷大
当y = 0时:
可以证明我们所选的代价函数会给我们一个凸优化问题,整体的代价函数J(θ)会变成一个凸函数,并且没有局部最优值。基于以上,使用梯度下降法就可以得到logistic回归算法。
Python代码实现:
import numpy as np
def cost(theta, X, y):
theta = np.matrix(theta)
X = np.matrix(X)
y = np.matrix(y)
first = np.multiply(-y, np.log(sigmoid(X* theta.T)))
second = np.multiply((1 - y), np.log(1 - sigmoid(X* theta.T)))
return np.sum(first - second) / (len(X))
5.简化代价函数与梯度下降法
首先合并两种情况下的式子:
接下来就是弄清楚:如何最小化θ的代价函数J(θ),这样我们才能为训练集拟合出参数θ。
最小化代价函数θ的方法是使用梯度下降法。
我们要反复更新每个参数,用这个式子来更新,就是用它自己减去学习率乘以后面的微分项。
特征缩放可以提高梯度下降的收敛速度,特征缩放也适用于logistic回归,如果你的特征范围差距很大的话,应用特征缩放同样也可以让logistic回归中的梯度下降收敛更快。
6.高级优化
高级优化算法和一些高级的优化概念,这些算法和梯度下降相比能大大提高logistic回归运行的速度,而这也会使算法更加适合解决大型的机器学习问题。比如,我们有数目庞大的特征。
现在我们换个角度来看什么是梯度下降?
我们有个代价函数J(θ),我们想要使它最小化,那么我们需要做的就是编写代码,当输入参数θ时,它们会计算出两样东西,J(θ)以及J等于0,1..直到n的偏导数项,假设我们已经完成了可以实现这两件事的代码,那么梯度下降所做的就是反复执行更新,给出我们用于计算这些偏导数的代码,梯度下降法就把它代入θj中,从而来更新参数θ。因此另一种分析梯度下降的思路是我们需要写出代码来计算J(θ)和偏导数,然后把这些代入到梯度下降中,然后它就可以为我们最小化这个函数。从技术上讲,你实际并不需要编写代码,来计算代价函数J(θ),你只需要编写代码计算导数项,但是如果你希望能够监控这些J(θ)的收敛性,那么我们就需要自己编写代码来计算代价函数和偏导数项:
但梯度下降并不是我们使用的唯一算法,还有一些其他更高级更复杂的算法,如果我们能用这些方法来计算J(θ)和偏导数项,那么这些算法就是为我们优化代价函数的不同方法。
这些算法很难懂,但是他们有一些性质:
1.使用其中任何一个算法,都不需要手动选择学习率α(你可以认为这些算法有一个智能内循环,称为线搜索算法,它可以自动尝试不同的学习速率α并自动选择一个好的学习速率α,它甚至可以为每次迭代选择不同的学习速率,那么你就不需要自己选择,所以它们往往收敛的远远快于梯度下降)不需要理解原理,但是要会用。
2.缺点就是复杂,最好不要自己去实现,除非你是数值计算方面的专家,还是建议直接使用软件库和函数。
举个例子:
首先运行costFunction函数以后,就可以调用高级的优化函数,这个函数叫做fminunc(),它在Octave中表示无约束最小化函数,调用它时,需要设置几个options,这个option变量是可以存储你想要的options的数据结构,设置梯度目标参数为打开,意味着你现在需要给这个算法提供一个梯度,然后设置最大迭代次数,比如100,我们给出一个θ的猜测初始值,它是一个2X1的向量,那么这个命令就调用fminunc,@指向我们刚刚定义的costFunction函数的指针,如果你调用它,它就会使用高级优化算法中的一个,自动选择学习率α,算法将会使用加强版的梯度下降自动为你找到最佳的θ值。
即写一个函数,它能返回代价函数值以及梯度值。
当然,你也可以把这些优化算法应用于线性回归,你需要做的就是输入合适的代码来计算图中红圈中的值。
因为高级算法复杂,但是运算速度是比梯度下降法更快的,所以当我有一个大的机器学习问题,我会选择使用高级优化算法,而不是梯度下降。
7.多类别分类:一对多
第一个例子:假如说你现在需要一个学习算法能自动地将邮件归类到不同的文件夹里,或者说可以自动地加上标签,那么,你也许需要一些不同的文件夹,或者不同的标签来完成这件事,来区分开来自工作的邮件、来自朋友的邮件、来自家人的邮件或者是有关兴趣爱好的邮件,那么,我们就有了这样一个分类问题:其类别有四个,分别用y=1、y=2、y=3、y=4 来代表。
第二个例子是有关药物诊断的,如果一个病人因为鼻塞来到你的诊所,他可能并没有生病,用 y=1这个类别来代表;或者患了感冒,用 y=2 来代表;或者得了流感用y=3来代表。
第三个例子:如果你正在做有关天气的机器学习分类问题,那么你可能想要区分哪些天是晴天、多云、雨天、或者下雪天,对上述所有的例子,y 可以取一个很小的数值,一个相对"谨慎"的数值,比如1 到3、1到4或者其它数值,以上说的都是多类分类问题,顺便一提的是,对于下标是0 1 2 3,还是 1 2 3 4 都不重要,我更喜欢将分类从 1 开始标而不是0,其实怎样标注都不会影响最后的结果。
对于之前的一个,二元分类问题,我们的数据看起来可能是像这样:
对于一个多类分类问题,我们的数据集或许看起来像这样:
我用3种不同的符号来代表3个类别,问题就是给出3个类型的数据集,我们如何得到一个学习算法来进行分类呢?
我们现在已经知道如何进行二元分类,可以使用逻辑回归,对于直线或许你也知道,可以将数据集一分为二为正类和负类。用一对多的分类思想,我们可以将其用在多类分类问题上。
下面将介绍如何进行一对多的分类工作,有时这个方法也被称为"一对余"方法。
现在我们有一个训练集,好比上图表示的有3个类别,我们用三角形表示 y=1,方框表示y=2,叉叉表示 y=3。我们下面要做的就是使用一个训练集,将其分成3个二元分类问题。
我们先从用三角形代表的类别1开始,实际上我们可以创建一个,新的"伪"训练集,类型2和类型3定为负类,类型1设定为正类,我们创建一个新的训练集,如下图所示的那样,我们要拟合出一个合适的分类器。
即在比如三个分类器中运行输入x,然后选择h最大的类别,也就是要选择分类器(选择三个中可信度最高、效果最好的)无论i值是多少,我们都能得到一个最高的概率值,我们的预测y就是那个值
8.过拟合问题
到现在为止,我们已经学习了几种不同的学习算法,包括线性回归和逻辑回归,它们能够有效地解决许多问题,但是当将它们应用到某些特定的机器学习应用时,会遇到过拟合(over-fitting)的问题,可能会导致它们效果很差。
正则化(regularization)的技术,可以改善或者减少过度拟合问题。
下图是一个回归问题的例子:
第一个模型是一个线性模型,欠拟合,不能很好地适应我们的训练集;第三个模型是一个四次方的模型,过于强调拟合原始数据,而丢失了算法的本质:预测新数据。我们可以看出,若给出一个新的值使之预测,它将表现的很差,是过拟合,虽然能非常好地适应我们的训练集但在新输入变量进行预测时可能会效果不好;而中间的模型似乎最合适。
分类问题中也存在这样的问题:
就以多项式理解,x的次数越高,拟合的越好,但相应的预测的能力就可能变差。
问题是,如果我们发现了过拟合问题,应该如何处理?
1.丢弃一些不能帮助我们正确预测的特征。可以是手工选择保留哪些特征,或者使用一些模型选择的算法来帮忙(例如PCA)
2.正则化。 保留所有的特征,但是减少参数的大小(magnitude)。
9.代价函数
正则化是怎么样运行的?
加入惩罚,增大两个参数所带来的效果:
如果把每一项都加上惩罚项,这就相当于尽量去简化这个假设模型,因为当这些参数都接近0的时候,这些参数越小,我们得到的函数就会越平滑,也越简单。
在参数后面加上一个正则化项?
这里的λ被称为正则化参数,它的作用是控制两个不同目标之间的取舍
第一个目标与目标函数的第一项有关,即想去更好的训练和拟合数据
第二个目标是我们要保持参数尽量的小,与目标函数的第二项有关,与正则化项有关
正则化参数的作用是控制这两个目标之间的平衡关系,即更好地拟合训练集的目标和将参数控制得更小的目标,从而保持假设模型的相对简单,避免出现过拟合的情况。
如果正则参数λ的值设置过大,就代表对θ1,θ2,θ3,θ4的惩罚程度太大,那么最后这些参数都会接近于0,这就相当于把假设函数的全部项都忽略掉了,就相当于房屋价格就等于θ0,相当于用平行于x轴的直线去拟合数据(欠拟合)。换句话说,这个假设模型的偏见性太强,或者说偏差过高。
为了让正则化起到应有的效果,我们应该注意去选择一个合适的正则化参数λ。
10.线性回归的正则化
线性回归的两种算法:一种基于梯度下降,一种基于正规方程
将这两种方法如何推广到正则化线性回归中去?
注意:分离θ0,因为对于正则化线性回归,我们惩罚的对象是参数θ1,θ2...一直到θn,我们没有惩罚θ0。
θj更新的结果就是θj变成了θj*0.99,也就是把θj向0的方向缩小了一点点,说的正式一点,就是θj的平方范数变小了,第二项和没有添加正则化保持不变。
即当我们进行正则化线性回归时,我们要做的就是每次迭代时,都将θj乘以一个比1小的数,即每次都把参数缩小一点,然后进行和之前一样的更新操作,从数学的角度来看,我们要做的就是对代价函数J(θ)进行梯度下降。
用正规方程来解决(不含证明):
不可逆问题:
如果你用不同的语言来运行,如果你只是求它的常规逆矩阵,也就是对应Octave的inv函数,也就是对X的转置乘X取逆矩阵,这种情况下(m<n),你会发现X的转置乘X是个奇异矩阵,是不可逆的。其他编程语言或者线性代数库,可能得不到输出结果。
在正则化中已经考虑到了这个问题:
如果λ>0,那么X的转置乘X再加上λ乘以这个有趣的矩阵,就可以确定这个矩阵一定不是奇异矩阵,即一定是可逆矩阵。
因此使用正则化,也可以解决一些X的转置乘X出现不可逆的问题。
实现正则化线性回归可以避免出现过拟合问题,及时你在一个很小的训练集中拥有大量的特征,也能让你更好地使用线性回归来解决问题。
11.logistic回归的正则化
对于逻辑回归问题,我们谈到过两种优化方法,一种是用梯度下降来优化代价函数J(θ),另一种是用更高级的优化算法。这些算法都需要你去想办法计算函数的导数,如何改进这两种算法?
逻辑回归中也存在过拟合问题:
如何实现?
对于梯度下降法(和线性回归非常像,不同之处是代价函数的表达式不同):
如何在更高级的优化算法中使用正则化:
对于参数jVal,在后面和线性回归一样添加了一项
对于参数梯度,θ0保持不变,但是θ1,θ2,...θn需要在后面加上一项表示正则化目标的梯度
Python代码实现:
import numpy as np
def costReg(theta, X, y, learningRate):
theta = np.matrix(theta)
X = np.matrix(X)
y = np.matrix(y)
first = np.multiply(-y, np.log(sigmoid(X*theta.T)))
second = np.multiply((1 - y), np.log(1 - sigmoid(X*theta.T)))
reg = (learningRate / (2 * len(X))* np.sum(np.power(theta[:,1:theta.shape[1]],2))
return np.sum(first - second) / (len(X)) + reg
注意:
1.虽然正则化的逻辑回归中的梯度下降和正则化的线性回归中的表达式看起来一样,但由于两者的hθ(x)不同所以还是有很大差别。
2.θ0不参与其中的任何一个正则化。