机器学习学习笔记--逻辑回归

Page content

Andrew NG's Machine Learning.

1. 逻辑回归

逻辑回归(Logistics Regression)是一种用于解决二分类问题的机器学学习算法,其用于估计某种事物的可能性下面我们就从实际问题出发来学习和推导逻辑回归问题。

1.1 分类问题

在分类问题中,我们需要尝试预测结果是否属于某一个类。如:判断一封邮件是否是垃圾邮件;判断一次金融交易是否存在欺诈;判断一个肿瘤是恶性还是良性等等。

我们首先从二分类问题开始,我们将预测的结果可能属于的两个类分别称为负向类(negative class)和正向类(positive class),即$y \in {0,1}$,其中0表示负向类,1表示正向类。

分类问题和线性回归问题的原理是相似的,其解决步骤可以归纳如下:

  1. 找一个合适的假设函数(hypothesis),用$h$表示,
  2. 构造一个Cost Function即代价函数,该函数表示预测的输出($h$)和训练数据类别($y$)之间的偏差。综合考虑所有训练数据的预测偏差,记为$J(\theta)$,表示所有训练数据预测值和实际类别的偏差
  3. 求出$J(\theta)$的局部最小值,即找到预测函数中的$\theta$值。

1.2 假设函数(hypothesis function)

逻辑回归采用的假设函数是Sigmoid函数,也称为逻辑函数。

\[ g(z) = \frac {1} {1 + e^{-z}} \]

其用python代码实现如下:

from numpy import e

def sigmoid(z):
    return 1/(1+pow(e,-z))

其函数图像如下:

对于sigmoid函数来说,其值在$[0,1]$之间。当$z$的值越远离0,其值越趋近0或者1。那么将其应用到二分类问题中,我们有如下假设:

\[ H _\theta(x) = g(\theta ^Tx) = \frac {1}{1 + e^{- \theta ^Tx}} \]

其中,$x$是输入的样本,$\theta$是待求的参数。有了上面的模型,我们对分类问题就有了如下的决策函数:

\[ y^* = 1 \qquad if \ P(y=1 | x,\theta) = H _\theta(x) >0.5 \\ y^* = 0 \qquad if \ P(y=1 | x,\theta) = H _\theta(x) <0.5 \]

1.3 决策边界(Decision Boundary)

决策边界,也称决策面,是用于在N维空间,将不同类别样本分开的平面或曲面。

在逻辑回归中,我们有如下决策:

  • 当$H _\theta(x)>0.5$时,预测$y =1$
  • 当$H _\theta(x)<0.5$时,预测$y =0$

假设现在我们有一个模型,$h _\theta(x) = g(\theta _0+ \theta _1x _1 + \theta _2x _2)$ 于是存在:

  • 当$\theta _0+ \theta _1x _1 + \theta _2x _2 > 0$时,预测$y =1$
  • 当$\theta _0+ \theta _1x _1 + \theta _2x _2 < 0$时,预测$y =0$

引用课程中的截图,我们可以画出一条直线,来区分这两类,这条直线就是决策边界。

我们再来考虑一种复杂的决策边界,如下图所示:

我们的预测函数$h _\theta(x) = g(\theta _0+ \theta _1x _1 + \theta _2x _2 + \theta _3x _1^2 | \theta _4x _2^2)$, 取$\theta = $,我们得到决策边界的方程$-1 + x _1^2 + x _2 ^2$,图中区分两类样本数据的决策边界是一个圆。

那么,在逻辑回归中决策边界其实就是一个函数方程,决策边界由$\theta ^T x$定义。决策边界是假设函数的一个属性,由假设函数的参数$\theta$决定。

\[ P(y =1 | x, \theta) = g(\theta ^Tx) = \frac {1}{1+e ^{-\theta ^Tx}} \]

1.4 代价函数(CostFunction)

对于线性回归问题,我们采用均方差(Mean squared error)来表示代价函数。但是,这并不适合逻辑函数,因为我们将上面的假设函数带入到均方差方程中,发现其是一个非凸函数(non-convexfunction),非凸函数有很多局部最优值,如下图所示:

在逻辑回归中,我们采用交叉熵(Cross Entropy)作为代价函数。首先我们来看简单的定义:

\[ Cost(h _\theta(x),y)==\begin{cases}-log(h _\theta(x)),&\text{if y =1}\\-log(1 - h _\theta (x)),&\text{if y = 0}\end{cases} \]

其中, $h _\theta(x)$和$Cost(h _\theta(x),y)$的关系如下:

我们来理解一下这个代价函数 :

  • 在$y=1$中,当$h _\theta(x) = 1$时,即$P(y=1|x,\theta) =1$,$Cost(h _\theta(x),y)=0$; 当$h _\theta(x)->0$时,即$P(y=1|x,\theta) =0$,$Cost(h _\theta(x),y) -> \infty$,这正好符合预期。
  • 在$y=0$中,当$h _\theta(x) = 0$时,即$P(y=1|x,\theta) =0$,$Cost(h _\theta(x),y) =0$;当$h _\theta(x)->1$时,即$P(y=1|x,\theta) =1$, $Cost(h _\theta(x),y) -> \infty$,这也是我们希望看到的。

我们再来看用交叉熵来定义代价函数,也就是将上面的case公式组合成一个,如下:

\[ J(\theta) = -\frac{1}{m} [\sum\limits _{i =1}^{m} (y ^{(i)}logh _\theta(x^{(i)}) + (1-y ^{(i)}log(1- h _\theta(x^{(i)} ))] \]

代价函数用python实现如下:

from numpy import log
from sigmoid import sigmoid  # sigmoid上面有实现

def costFunction(theta, X,y):
    """ computes the cost of using theta as the
    parameter for logistic regression and the
    gradient of the cost w.r.t. to the parameters."""

    # Initialize some useful values
    m = y.size # number of training examples
    h = sigmoid(X.dot(theta))
    temp = 1-y
    J = 1/m * (-y.dot(log(h)) - temp.dot(log(1- h)))
    return J

接下来,我们就可以用梯度下降的方式来求解使代价函数最小的参数了,算法表示如下:

Repeat { $\theta_j := \theta_j - \alpha \frac{\partial}{\partial\theta_j} J(\theta)$ (simultaneously update all ) }

这里我们来推到一下代价函数的求导:

\[ \begin{align} \frac{\partial }{\partial {\theta_{j}}}J\left( \theta \right) &= \frac{\partial }{\partial {\theta_{j}}} -\frac{1}{m} [\sum\limits _{i =1}^{m} (y ^{(i)}logh _\theta(x^{(i)}) + (1-y ^{(i)}log(1- h _\theta(x^{(i)} ))] \\\\ &= -\frac{1}{m} \sum\limits _{i =1}^{m}(y^{(i)} \frac{1}{h _\theta(x^{(i)})} \frac{\partial }{\partial {\theta_{j}}} h _\theta(x^{(i)}) + (1-y ^{(i)}) \frac{1}{1- h _\theta(x^{(i)})} \frac{\partial }{\partial {\theta_{j}}} h _\theta(x^{(i)})) \\\\ &= -\frac{1}{m} \sum\limits _{i =1}^{m}(y^{(i)} \frac{1}{h _\theta(x^{(i)})} + (1-y ^{(i)}) \frac{1}{1- h _\theta(x^{(i)})}) \frac{\partial }{\partial {\theta_{j}}} h _\theta(x^{(i)}) \end{align} \]

其中, $\frac{\partial }{\partial {\theta_{j}}} h _\theta(x^{(i)})$ 推导如下:

\[ \begin{align} \frac{\partial }{\partial {\theta_{j}}} h _\theta(x^{(i)}) &= \frac{\partial }{\partial {\theta_{j}}} \frac {1}{1+e ^{-\theta ^Tx}} \\\\ &= \frac {-e ^{-\theta ^Tx}} {(1+e ^{-\theta ^Tx})^2} \frac{\partial }{\partial {\theta_{j}}} (-\theta ^Tx^{(i)}) \\\\ &= \frac { 1 + e ^{-\theta ^Tx} -1 } {(1+e ^{-\theta ^Tx})^2} \frac{\partial }{\partial {\theta_{j}}} (\theta _0 + \theta_1x_1 + ... + \theta_nx_n) \\\\ &= \frac {1} {1+e ^{-\theta ^Tx}} (1 - \frac {1} {1+e ^{-\theta ^Tx}}) x_j^{(i)} \\\\ &= h _\theta(x^{(i)})(1-h _\theta(x^{(i)})) x_j^{(i)} \end{align} \]

将推导结果带入代价函数的求导推导中,可得:

\[ \begin{align} \frac{\partial }{\partial {\theta_{j}}}J\left( \theta \right) &= -\frac{1}{m} \sum\limits _{i =1}^{m}[y^{(i)} \frac{1}{h _\theta(x^{(i)})} + (1-y ^{(i)}) \frac{1}{1- h _\theta(x^{(i)})}] h _\theta(x^{(i)})(1-h _\theta(x^{(i)})) x_j^{(i)} \\\\ &= -\frac{1}{m} \sum\limits _{i =1}^{m} (y^{(i)}(1-h _\theta(x^{(i)})) + (1-y ^{(i)})h _\theta(x^{(i)})) x_j^{(i)} \\\\ &= \frac{1}{m} \sum\limits _{i =1}^{m} (h _\theta(x^{(i)}) -y^{(i)}) x_j^{(i)} \end{align} \]

推导到这里,我们就可以用线性回归中用到的向量化的方式来一步得到更新后的$\theta$值,代码就不赘述了。

1.5 高级优化

在前面提到的梯度下降算法中,我们首先需要提出假设函数和代价函数,其次对代价函数进行求导,然后同步更新$\theta$的值,直到达到收敛。

除了梯度下降算法外,"共轭梯度", "BFGS"和"L-BFGS"这些更加复杂的函数,能代替梯度下降算法,使我们能更快速的找到能使$J(\theta)$达到最优值的参数$\theta$。这些算法目前超出了课程的教学范围,每个算法估计要花费一周甚至更长时间来实现和理解。现阶段不建议自行实现这些算法,我们可以利用一些封装好的库函数来帮我们实现这些算法,它们往往是被优化到极致的函数。

这些算法的优势在于:

  • 不需要手动选择学习率$\alpha$
  • 比梯度下降更快

缺点在于:

  • 算法过于复杂

在python中,可以使用scipy提供的优化函数库optimize中的minimize函数来实现对$J(\theta)$求取最优值参数。代码如下:

from scipy.optimize import minimize

res = minimize(costFunction, initial_theta, method='TNC', jac=False, args=(X, y), options={'gtol': 1e-3, 'disp': True, 'maxiter': 1000})
theta = res.x
cost = res.fun
# Print theta to screen
print('Cost at theta found by scipy: %f' % cost)
print('theta:', ["%0.4f" % i for i in theta])

1.6 多元分类问题

对于多元分类问题,我们可以将其转换成多个二分类问题。如下图所示:

因此对于$n$分类问题,我们可以求出$n$个假设函数,如下:

\[ h ^{(0)} _\theta(x) = P(y = 0 | x,\theta) \\ h ^{(1)} _\theta(x) = P(y = 1 | x,\theta) \\ ... \\ h ^{(n)} _\theta(x) = P(y = n | x,\theta) \\ \]

于是,对于待分类的数据来说,我们可以有如下分类算法:

\[ prediction = \mathop {max} _i (h ^ {(i)} _\theta (x)) \]

1.7 过拟合和正则化

1.7.1 过拟合

在线性回归中,我们可以通过多项式来增加特征,从而使得预测函数能更好的拟合样本,但是如果“无休止的”增加特征,就会导致出现“过拟合”的现象,下图很好的说明了在线性回归中会碰到的“欠拟合”和“过拟合”现象。

要记住,我们在拿到样本数据集和选择预测函数时,并不是为了让预测函数很好地拟合样本数据集,而是对于一个新的数据,能通过预测函数很好的预测,这才是我们要达到的目的。因此,出现“过拟合”现象不是我们希望看到的。

在逻辑回归中,我们同样可能会出现“欠拟合”和“过拟合“现象,NG视频中也通过图形很好的说明了这一点,如下:

那么,我们来分析一下为什么会出现欠拟合和过拟合现象。

现象 产生原因 解决方法
欠拟合 特征太少或者特征较为单一 1. 增加特征
2. 采用多项式拟合
过拟合 假设函数太过复杂 1. 减少特征
2. 正则化,保留所有的特征,但是减小特征的权重

增加或减少特征这里就不赘述了,采用多项式拟合前面的章节也已经介绍过了,这里重点介绍正则化的方法。

1.7.2 正则化

我们来看上面这张图,如果我们在最小化损失函数的时候加上$1000\theta _3 ^2 + 1000\theta _4 ^2$,那么在计算参数的时候,会使得$\theta _3$和$\theta _4$特别小,从而使得预测函数更加平滑,更符合期望。

正则化的思想就是在一定程度上减小某些参数$\theta$的值,从而降低某些特征对结果的影响,相当于对特征进行了惩罚,使其对样本集的预测不必过于精确,要尽量泛化,毕竟预测函数的最终目的是对未知的样本进行预测,而不是对已有的样本。

那么为什么$\theta$变小会防止过拟合的现象呢?

一个很显而易见的解释就是:参数越小,从某种意义上来说模型的复杂度就越低,对数据的拟合效果就越好。过拟合的时候,拟合参数往往很大,因为拟合函数要顾及到每一个点,最终形成的拟合函数波动很大,在某些很小的区间里,函数值的变化很剧烈。这就意味着函数在某些小区间里的导数值(绝对值)非常大,由于自变量值可大可小,所以只有系数足够大,才能保证导数值很大。而正则化是通过约束参数的范数使其不要太大,所以可以在一定程度上减少过拟合情况。

还有一些其他的解释,可以参考下面的链接,由于本人目前能力有限,暂时只能意会,但是难以言传,这里就不赘述了。 机器学习中使用正则化来防止过拟合是什么原理? - 刑无刀的回答 - 知乎 https://www.zhihu.com/question/20700829/answer/21156998

这样一来,我们尝试修改代价函数,加入正则化,一般来说,对于$\theta _0$来说,不必加入正则项。函数如下:

\[ J(\theta) = \frac{1}{2m}[\sum _{i=1}^{m} (h _\theta(x^{(i)}) -y^{(i)}) ^ 2 + \lambda \sum _{j =1} ^n \theta _j ^2] \]

其中$\lambda$为正则化参数。 依然采用梯度下降的方法,对损失函数进行求导,可以得到如下梯度下降算法:

\[ \begin{align} Repeat \ until \ converage \{ & \\ \theta _0 &:= \theta _0 - \alpha \frac{1}{m} \sum _{i=1} ^ m(h _\theta(x^{(i)}) - y ^{(i)})x _0^{(i)} \\ \theta _j & := (1 - \alpha \frac {\lambda}{m})\theta _j - \alpha \frac{1}{m} \sum _{i=1} ^ m(h _\theta(x^{(i)}) - y ^{(i)})x _j^{(i)} \ for \ j = 1, 2, 3, 4... \end{align}\\ \} \]

上式中,$1 - \alpha \frac {\lambda}{m} < 1$,相当于我们给$\theta _j$加了一个惩罚项,每次都会使$\theta _j$更小,即增强预测函数的泛化性,避免过拟合。

这里,对正则化参数$\lambda$来做一下解释,如果$\lambda$过小,正则化效果不明显,导致过拟合现象依然存在;如果$\lambda$恰好,则会有效的改善过拟合现象;如果$\lambda$过大,将会造成欠拟合现象,当$\lambda$无穷大时,$\theta$将无穷小,导致预测函数退化成一根直线,如下图所示。所以在实际应用中,选择恰当的$\lambda$将显得尤其重要,当然后面我们也会接触到一些高级算法,能帮助我们选取$\lambda$的值,这里也不在赘述。

1.7.2.1 正规方程正则化

前面我们介绍过正规方程来代替梯度下降算法来求解最优解,其公式如下:

\[ \theta = (X ^T X) ^ {-1} Y ^T X \]

那么加入正则化后,正规方程演变成如下:

\[ \theta = (X ^T X + \lambda L) ^ {-1} Y ^T X \\ where \ L = \begin{bmatrix} 0 & & & & & \\ & 1 & & & & \\ & & 1 & & & \\ & & & ... & & \\ & & & & 1& \end{bmatrix} \]

正规方程$A ^TA$可逆性,之前我们提到,如果特征之间具有相关性或者特征数大于样本集数时,会导致$A ^TA$不可逆。那么,在本节中,加入了正则化之后,由于$\lambda > 0$,可以证明$X ^T X + \lambda L$这个矩阵始终可逆,这也是正则化为我们带来求解正规方程带来的好处。

1.7.2.2 逻辑回归正则化

针对逻辑回归,我们先来看看逻辑回归的代价函数如下:

\[ J(\theta) = -\frac{1}{m} [\sum\limits _{i =1}^{m} (y ^{(i)}logh _\theta(x^{(i)}) + (1-y ^{(i)}log(1- h _\theta(x^{(i)} ))] \]

同样,加入正则化之后,代价函数演变成如下:

\[ J(\theta) = -\frac{1}{m} [\sum\limits _{i =1}^{m} (y ^{(i)}logh _\theta(x^{(i)}) + (1-y ^{(i)}log(1- h _\theta(x^{(i)} ))] + \frac{\lambda }{2m}\sum\limits_{j=1}^{n}{\theta _{j}^{2}} \]

对其进行求导后,得到梯度下降算法如下:

\[ \begin{align} Repeat \ until \ converage \{ & \\ \theta _0 &:= \theta _0 - \alpha \frac{1}{m} \sum _{i=1} ^ m(h _\theta(x^{(i)}) - y ^{(i)})x _0^{(i)} \\ \theta _j & := (1 - \alpha \frac {\lambda}{m})\theta _j - \alpha \frac{1}{m} \sum _{i=1} ^ m(h _\theta(x^{(i)}) - y ^{(i)})x _j^{(i)} \ for \ j = 1, 2, 3, 4... \end{align}\\ \} \]

这里看起来和线性回归的正则化表达式一样,不过,我们要注意$h _\theta(x)$是不一样的。

2. 总结

这里稍微总结一下目前学到的知识:

  • 机器学习基本概念和分类
  • 监督学习和非监督学习
  • 线性回归,梯度下降以及正规方程
  • 逻辑回归
  • 正规化以及一些高级优化算法

基本上如果能精通这些知识并应用到实际问题中,就可以解决大部分工程问题。学到这里,感觉前面的知识中有很多半懂不懂的问题,在进行后面的学习前,先消化消化把,稳扎稳打,加油!