以下为我的机器学习笔记,参考了黄海广博士的笔记

课程:机器学习 - 斯坦福大学 - 吴恩达 2014 @ Coursera

https://www.coursera.org/course/ml

# 逻辑回归 (Logistic Regression)

# 分类问题

这一节我们将介绍分类问题。什么是分类问题呢?我们来看几个分类问题的例子🌰 :判断一封电子邮件是否是垃圾邮件;判断一次金融交易是否是欺诈;之前我们也谈到了肿瘤分类问题的例子,区别一个肿瘤是恶性的还是良性的,如果是恶性,那么它是哪种恶性。

通过这些例子,我们可以知道,分类问题所预测的变量 yy 将不再是连续的,而是一个个离散的值。同时,我们将学习一种求解该类问题的方法,即 逻辑回归 算法。

首先我们从最简单的二元分类问题开始讨论。

我们将 因变量(dependent variable) 可能属于的两个类分别称为 负向类(negative class)正向类(positive class) ,则因变量y0,1y\in { 0,1 \\} ,其中 0 表示负向类,1 表示正向类。

如果我们要用线性回归算法来解决一个分类问题,那么假设函数的输出值可能远大于 1,或者远小于 0。而若是我们使用逻辑回归算法,那么它的输出值永远在 0 到 1 之间。

# 假说表示

在分类问题中,我们需要用函数来表示我们的假设。根据上面的讨论,我们的假设函数预测值要在 0 和 1 之间。

回顾在一开始提到的乳腺癌分类问题,我们先用线性回归的方法求出适合数据的一条直线:

因为我们要输出的是 0 或 1,我们可以规定:当hθ(x)0.5{h_\theta}\left( x \right)\ge0.5 时,预测 y=1y=1,当hθ(x)<0.5{h_\theta}\left( x \right)<0.5 时,预测 y=0y=0

这样的一个线性模型似乎能很好地完成分类任务,是吧?但是呢,我们现在情况变了,假使我们又观测到一个很大很大的恶性肿瘤(下图最右方的❌),当它加入到我们的训练集中来,我们又获得一条新的直线。

这时,再使用 0.5 作为阀值来预测肿瘤是良性还是恶性就不合适了。由此可以看出,线性回归模型并不适合解决这样的问题。

所以,我们引入一个新的模型 逻辑回归 ,该模型的输出变量范围始终在 0 和 1 之间。它的假设函数是:

hθ(x)=g(θTX)h_\theta \left( x \right)=g\left(\theta^{T}X \right)

其中:
XX 代表特征向量
gg 代表逻辑函数,它是一个常用的逻辑函数为 S 形函数(Sigmoid function),公式为:

g(z)=11+ezg\left( z \right)=\frac{1}{1+{ {e}^{-z} } }

python 代码实现:

import numpy as np  
def sigmoid(z):
   return 1 / (1 + np.exp(-z))

该函数的图像为:

对于假设函数hθ(x)h_\theta \left( x \right),我们作如下理解:我们根据给定的输入变量和参数,计算输出变量 = 1 的可能性,即hθ(x)=P(y=1x;θ)h_\theta \left( x \right)=P\left( y=1|x;\theta \right)
例如,如果对于给定的xxθ\theta, 计算得出hθ(x)=0.7h_\theta \left( x \right)=0.7,则表示有 70% 的几率yy 为正向类,相应地yy 为负向类的几率为 0.3。

# 判定边界

现在讲下决策边界 (decision boundary) 的概念。这个概念能更好地帮助我们理解逻辑回归的假设函数在计算什么。

由上图可知,当z=θTx0z={\theta^{T} }x\geq0 时,预测 y=1y=1,而当z=θTx<0z={\theta^{T} }x<0 时,预测 y=0y=0

现在我们来看个实例,假设我们有一个模型:

并且参数θ\theta 是向量 [-3 1 1]。 则当3+x1+x20-3+{x_1}+{x_2} \geq 0,即x1+x23{x_1}+{x_2} \geq 3 时,模型将预测 y=1y=1
我们可以绘制直线x1+x2=3{x_1}+{x_2} = 3,这条线便是我们模型的分界线,将预测为 1 的区域和预测为 0 的区域分隔开。

假使我们的数据呈现这样的分布情况,怎样的模型才能适合呢?

因为需要用曲线才能分隔 y=0y=0 的区域和 y=1y=1 的区域,所以我们引入二次方特征:

hθ(x)=g(θ0+θ1x1+θ2x2+θ3x12+θ4x22){h_\theta}\left( x \right)=g\left( {\theta_0}+{\theta_1}{x_1}+{\theta_{2} }{x_{2} }+{\theta_{3} }x_{1}^{2}+{\theta_{4} }x_{2}^{2} \right)

当我们取θ\theta 的值为 [-1 0 0 1 1] 时,则我们得到的判定边界恰好是圆点在原点且半径为 1 的圆形。

通过这两个例子我们可以看出,只要参数合适,我们可以用这种方法来适应形状非常复杂的边界判定。

# 代价函数

函数给出来了,它看起来非常明了。接下来我们只需要找到合适的参数θ\theta 带进去就完事儿。寻求合适的θ\theta,这便是监督学习问题中的逻辑回归模型的拟合问题。

那么怎么求θ\theta 的值呢,和线性回归一样,我们需要引入合适的 代价函数cost() 并利用 梯度下降算法 求使 cost() 最小的数。对于线性回归模型来说,我们定义的代价函数是所有模型误差的平方和。也就是:

J(θ)=1mi=1m12(hθ(x(i))y(i))2J\left( \theta \right)=\frac{1}{m}\sum\limits_{i=1}^{m}{\frac{1}{2}{ {\left( {h_\theta}\left({x}^{\left( i \right)} \right)-{y}^{\left( i \right)} \right)}^{2} } }

理论上来说,我们也可以对逻辑回归模型沿用这个定义,但是问题在于,当我们将hθ(x)=11+eθTx{h_\theta}\left( x \right)=\frac{1}{1+{e^{-\theta^{T}x} } } 带入到这样定义了的代价函数中时,我们得到的代价函数将是一个 非凸函数(non-convexfunction) , 就像左下边的这幅图。

这意味着我们的代价函数有许多局部最小值,这将影响梯度下降算法寻找全局最小值。

所以我们重新定义逻辑回归的代价函数为:

J(θ)=1mi=1mCost(hθ(x(i)),y(i))J\left( \theta \right)=\frac{1}{m}\sum\limits_{i=1}^{m}{ {Cost}\left( {h_\theta}\left( {x}^{\left( i \right)} \right),{y}^{\left( i \right)} \right)}

其中

hθ(x){h_\theta}\left( x \right)Cost(hθ(x),y)Cost\left( {h_\theta}\left( x \right),y \right) 之间的关系如下图所示:

这样构建的Cost(hθ(x),y)Cost\left( {h_\theta}\left( x \right),y \right) 函数的特点是:

  • 当实际的 y=1y=1hθ(x){h_\theta}\left( x \right) 也为 1 时误差为 0,当 y=1y=1hθ(x){h_\theta}\left( x \right) 不为 1 时误差随着hθ(x){h_\theta}\left( x \right) 变小而变大;

  • 当实际的 y=0y=0hθ(x){h_\theta}\left( x \right) 也为 0 时代价为 0,当y=0y=0hθ(x){h_\theta}\left( x \right) 不为 0 时误差随着 hθ(x){h_\theta}\left( x \right) 的变大而变大。
    将构建的 Cost(hθ(x),y)Cost\left( {h_\theta}\left( x \right),y \right) 简化如下:

Cost(hθ(x),y)=y×log(hθ(x))(1y)×log(1hθ(x))Cost\left( {h_\theta}\left( x \right),y \right)=-y\times log\left( {h_\theta}\left( x \right) \right)-(1-y)\times log\left( 1-{h_\theta}\left( x \right) \right)

带入代价函数得到:

J(θ)=1mi=1m[y(i)log(hθ(x(i)))(1y(i))log(1hθ(x(i)))]J\left( \theta \right)=\frac{1}{m}\sum\limits_{i=1}^{m}{[-{ {y}^{(i)} }\log \left( {h_\theta}\left( { {x}^{(i)} } \right) \right)-\left( 1-{ {y}^{(i)} } \right)\log \left( 1-{h_\theta}\left( { {x}^{(i)} } \right) \right)]}

Python 代码实现:

import numpy as np
def cost(theta, X, y):
  return np.mean((-y) *np.log(sigmoid(X @ theta))- (1-y)*np.log(1-sigmoid(X@theta)))

在得到这样一个代价函数以后,我们便可以用梯度下降算法来求得能使代价函数最小的参数了。算法为:

θj:=θjαθjJ(θ)\theta_j := \theta_j - \alpha \frac{\partial}{\partial\theta_j} J(\theta)

求导后得到:

θj:=θjα1mi=1m(hθ(x(i))y(i))xj(i)\theta_j := \theta_j - \alpha \frac{1}{m}\sum\limits_{i=1}^{m}{ {\left( {h_\theta}\left( {x}^{\left( i \right)} \right)-{y}^{\left( i \right)} \right)} } {x}_{j}^{(i)}

每个θ\theta 必须同时更新

代价函数J(θ)J(\theta) 会是一个凸函数,并且没有局部最优值。上面求导的过程如下:

推导过程:

J(θ)=1mi=1m[y(i)log(hθ(x(i)))+(1y(i))log(1hθ(x(i)))]J\left( \theta \right)=-\frac{1}{m}\sum\limits_{i=1}^{m}{[{ {y}^{(i)} }\log \left( {h_\theta}\left( { {x}^{(i)} } \right) \right)+\left( 1-{ {y}^{(i)} } \right)\log \left( 1-{h_\theta}\left( { {x}^{(i)} } \right) \right)]}
考虑:
hθ(x(i))=11+eθTx(i){h_\theta}\left( { {x}^{(i)} } \right)=\frac{1}{1+{ {e}^{-{\theta^T}{ {x}^{(i)} } } } }
则:
y(i)log(hθ(x(i)))+(1y(i))log(1hθ(x(i))){ {y}^{(i)} }\log \left( {h_\theta}\left( { {x}^{(i)} } \right) \right)+\left( 1-{ {y}^{(i)} } \right)\log \left( 1-{h_\theta}\left( { {x}^{(i)} } \right) \right)
=y(i)log(11+eθTx(i))+(1y(i))log(111+eθTx(i))={ {y}^{(i)} }\log \left( \frac{1}{1+{ {e}^{-{\theta^T}{ {x}^{(i)} } } } } \right)+\left( 1-{ {y}^{(i)} } \right)\log \left( 1-\frac{1}{1+{ {e}^{-{\theta^T}{ {x}^{(i)} } } } } \right)
=y(i)log(1+eθTx(i))(1y(i))log(1+eθTx(i))=-{ {y}^{(i)} }\log \left( 1+{ {e}^{-{\theta^T}{ {x}^{(i)} } } } \right)-\left( 1-{ {y}^{(i)} } \right)\log \left( 1+{ {e}^{ {\theta^T}{ {x}^{(i)} } } } \right)

所以:
θjJ(θ)=θj[1mi=1m[y(i)log(1+eθTx(i))(1y(i))log(1+eθTx(i))]]\frac{\partial }{\partial {\theta_{j} } }J\left( \theta \right)=\frac{\partial }{\partial {\theta_{j} } }[-\frac{1}{m}\sum\limits_{i=1}^{m}{[-{ {y}^{(i)} }\log \left( 1+{ {e}^{-{\theta^{T} }{ {x}^{(i)} } } } \right)-\left( 1-{ {y}^{(i)} } \right)\log \left( 1+{ {e}^{ {\theta^{T} }{ {x}^{(i)} } } } \right)]}]
=1mi=1m[y(i)xj(i)eθTx(i)1+eθTx(i)(1y(i))xj(i)eθTx(i)1+eθTx(i)]=-\frac{1}{m}\sum\limits_{i=1}^{m}{[-{ {y}^{(i)} }\frac{-x_{j}^{(i)}{ {e}^{-{\theta^{T} }{ {x}^{(i)} } } } }{1+{ {e}^{-{\theta^{T} }{ {x}^{(i)} } } } }-\left( 1-{ {y}^{(i)} } \right)\frac{x_j^{(i)}{ {e}^{ {\theta^T}{ {x}^{(i)} } } } }{1+{ {e}^{ {\theta^T}{ {x}^{(i)} } } } } }]
=1mi=1my(i)xj(i)1+eθTx(i)(1y(i))xj(i)eθTx(i)1+eθTx(i)]=-\frac{1}{m}\sum\limits_{i=1}^{m}{ {y}^{(i)} }\frac{x_j^{(i)} }{1+{ {e}^{ {\theta^T}{ {x}^{(i)} } } } }-\left( 1-{ {y}^{(i)} } \right)\frac{x_j^{(i)}{ {e}^{ {\theta^T}{ {x}^{(i)} } } } }{1+{ {e}^{ {\theta^T}{ {x}^{(i)} } } } }]
=1mi=1my(i)xj(i)xj(i)eθTx(i)+y(i)xj(i)eθTx(i)1+eθTx(i)=-\frac{1}{m}\sum\limits_{i=1}^{m}{\frac{ { {y}^{(i)} }x_j^{(i)}-x_j^{(i)}{ {e}^{ {\theta^T}{ {x}^{(i)} } } }+{ {y}^{(i)} }x_j^{(i)}{ {e}^{ {\theta^T}{ {x}^{(i)} } } } }{1+{ {e}^{ {\theta^T}{ {x}^{(i)} } } } } }
=1mi=1my(i)(1+eθTx(i))eθTx(i)1+eθTx(i)xj(i)=-\frac{1}{m}\sum\limits_{i=1}^{m}{\frac{ { {y}^{(i)} }\left( 1\text{+}{ {e}^{ {\theta^T}{ {x}^{(i)} } } } \right)-{ {e}^{ {\theta^T}{ {x}^{(i)} } } } }{1+{ {e}^{ {\theta^T}{ {x}^{(i)} } } } }x_j^{(i)} }
=1mi=1m(y(i)eθTx(i)1+eθTx(i))xj(i)=-\frac{1}{m}\sum\limits_{i=1}^{m}{({ {y}^{(i)} }-\frac{ { {e}^{ {\theta^T}{ {x}^{(i)} } } } }{1+{ {e}^{ {\theta^T}{ {x}^{(i)} } } } })x_j^{(i)} }
=1mi=1m(y(i)11+eθTx(i))xj(i)=-\frac{1}{m}\sum\limits_{i=1}^{m}{({ {y}^{(i)} }-\frac{1}{1+{ {e}^{-{\theta^T}{ {x}^{(i)} } } } })x_j^{(i)} }
=1mi=1m[y(i)hθ(x(i))]xj(i)=-\frac{1}{m}\sum\limits_{i=1}^{m}{[{ {y}^{(i)} }-{h_\theta}\left( { {x}^{(i)} } \right)]x_j^{(i)} }
=1mi=1m[hθ(x(i))y(i)]xj(i)=\frac{1}{m}\sum\limits_{i=1}^{m}{[{h_\theta}\left( { {x}^{(i)} } \right)-{ {y}^{(i)} }]x_j^{(i)} }

虽然得到的梯度下降算法表面上看上去与线性回归的梯度下降算法一样,但是这里的hθ(x)=g(θTX){h_\theta}\left( x \right)=g\left( {\theta^T}X \right) 与线性回归中不同,所以实际上是不一样的。另外,在运行梯度下降算法之前,进行特征缩放依旧是非常必要的。

# 简化的成本函数和梯度下降

对于梯度下降的式子,也就是:

θj:=θjα1mi=1m(hθ(x(i))y(i))xj(i){\theta_j}:={\theta_j}-\alpha \frac{1}{m}\sum\limits_{i=1}^{m}{({h_\theta}({ {x}^{(i)} })-{ {y}^{(i)} }){x_{j} }^{(i)} }

如果你记性还行,你会惊讶地发现,嘿,这个式子不跟线性回归的梯度下降算法一样吗!

这是不是说明线性回归和逻辑回归是同一个算法?答案肯定是 No。为啥呢?我们要观察逻辑回归看看发生了哪些变化。实际上,假设的定义发生了变化。

对于线性回归假设函数:

hθ(x)=θTX=θ0x0+θ1x1+θ2x2+...+θnxn{h_\theta}\left( x \right)={\theta^T}X={\theta_{0} }{x_{0} }+{\theta_{1} }{x_{1} }+{\theta_{2} }{x_{2} }+...+{\theta_{n} }{x_{n} }

而现在逻辑函数假设函数:

hθ(x)=11+eθTX{h_\theta}\left( x \right)=\frac{1}{1+{ {e}^{-{\theta^T}X} } }

所以,虽然这俩看起来一模一样,但由于假设函数的定义发生了变化,其含义也就截然不同了。

当使用梯度下降法来实现逻辑回归时,我们有这些不同的参数θ\theta,就是 θ0{\theta_{0} } θ1{\theta_{1} } θ2{\theta_{2} } 一直到θn{\theta_{n} },我们需要用这个表达式来更新这些参数。我们还可以使用 for 循环来更新这些参数值,用 for i=1 to n ,或者 for i=1 to n+1 。当然,不用 for 循环也是可以的,理想情况下,我们更提倡使用向量化的实现,可以把所有这些 nn 个参数同时更新。

最后还有一点,我们之前在谈线性回归时讲到的特征缩放,我们看到了特征缩放是如何提高梯度下降的收敛速度的,这个特征缩放的方法,也适用于逻辑回归。如果你的特征范围差距很大的话,那么应用特征缩放的方法,同样也可以让逻辑回归中,梯度下降收敛更快。

就是这样,现在你知道如何实现逻辑回归,这是一种非常强大,甚至可能世界上使用最广泛的一种分类算法。

# 高级优化

我们现在掌握了用梯度下降的方法最小化逻辑回归中代价函数J(θ)J\left( \theta \right)。为了提高逻辑回归的速度,我们需要了解一些高级的优化算法和优化概念。这对我们解决大型的机器学习问题是很有帮助的。
我们回顾一下梯度下降的方法,首先是我们有个代价函数J(θ)J( \theta),而我们想要使其最小化,那么我们需要做的是编写代码,当输入参数 θ\theta 时,它们会计算出两样东西:J(θ)J\left( \theta \right) 以及它的各个偏导数项。假设我们已经写好了求J(θ)J(\theta) 和它的偏导数项的代码,那么梯度下降所做的就是反复执行这些更新。过程如下图所示:

对于梯度下降来说,我认为从技术上讲,你实际并不需要编写代码来计算代价函数J(θ)J\left( \theta \right)。你只需要编写代码来计算导数项,但是,如果你希望代码还要能够监控这些J(θ)J\left( \theta \right) 的收敛性,那么我们就需要自己编写代码来计算代价函数J(θ)J(\theta) 和偏导数项θjJ(θ)\frac{\partial }{\partial {\theta_j} }J\left( \theta \right)。所以,在写完能够计算这两者的代码之后,我们就可以使用梯度下降。
然而梯度下降并不是我们可以使用的唯一算法,还有一些常被用来令代价函数最小的算法,这些算法更加复杂和优越,而且通常不需要人工选择学习率,通常比梯度下降算法要更加快速。这些算法有: 共轭梯度(Conjugate Gradient)局部优化法(Broyden fletcher goldfarb shann,BFGS)有限内存局部优化法(LBFGS) , 截断牛顿法(TNC) 等等。

它们前面的步骤是一样的,需要有编写代码求 J(θ)J\left( \theta \right) 和计算导数项,然后使用比梯度下降更复杂的算法来最小化代价函数。这其中的具体细节很复杂,要学的话估计时间得好几天,不过他们具有一些特性:

  • 一个是你通常不需要手动选择学习率 α\alpha。你可以认为算法有一个智能的内部循环,而且,事实上,他们确实有,而且被称作线性搜索 (line search) 算法,它可以自动尝试不同的学习速率 α\alpha,并自动选择一个好的学习速率 aa,因此它甚至可以为每次迭代选择不同的学习速率,那么你就不需要自己选择。

  • 这些算法实际上在做更复杂的事情,不仅仅是选择一个好的学习速率,所以它们往往最终比梯度下降收敛得快多了,不过它们到底在做什么,我们就不讨论了。

对于这些算法,我们完全可以成功地应用他们来解决问题,而不需要真正理解这些算法的内环间在做什么。如果说这些算法有缺点的话,那么他们的主要缺点是它们比梯度下降法复杂多了。但是,不会造轮子还不会搬轮子吗?人生苦短,直接调库吧。

当然,调库也不能乱调,算法实现得好或不好还是有差别的。多试试一些不同的库,从里面找一个最合适的。

下面我们来说明,如何使用这些算法:

比方说,你有一个含两个参数的问题,这两个参数是θ0{\theta_{0} }θ1{\theta_{1} },因此,通过这个代价函数,你可以得到θ1{\theta_{1} }θ2{\theta_{2} } 的值,如果你将J(θ)J\left( \theta \right) 最小化的话,那么它的最小值将是θ1=5{\theta_{1} }=5θ2=5{\theta_{2} }=5。代价函数J(θ)J\left( \theta \right) 的导数推出来就是这两个表达式:

θ1J(θ)=2(θ15)\frac{\partial }{\partial { {\theta }_{1} } }J(\theta)=2({ {\theta }_{1} }-5)

θ2J(θ)=2(θ25)\frac{\partial }{\partial { {\theta }_{2} } }J(\theta)=2({ {\theta }_{2} }-5)

当然这种情况很简单,我们看都看得出来最小值是多少。不过面对复杂得问题我们可能就看不出来了,所以我们假设不知道这个最小值,我们想用算法自动帮我们求值。我们用 python 来 for 一个 ample:

import scipy.optimize as opt
import numpy as np
def sigmoid(z):
    return 1 / (1 + np.exp(-z))
def cost(theta, X, y):
    return np.mean(-y * np.log(sigmoid(X @ theta)) - (1 - y) * np.log(1 - sigmoid(X @ theta)))
def gradient(theta, X, y):
    return (1 / len(X)) * X.T @ (sigmoid(X @ theta) - y)
def logistic_regression(X, y):
    theta = np.zeros(X.shape[1])
    res = opt.minimize(fun=cost, 
                       x0=theta, 
                       args=(X, y), 
                       method='Newton-CG', 
                       jac=gradient)
    final_theta = res.x
    return final_theta

如上图所示,代码非常简单,就是我们定义得这个 logistic_regression 函数,调库一步到位。当然,你也可以把它理解为和梯度下降算法差不多的东西,只是它不需要你给学习率而已。

# 多类别分类:一对多

之前我们讨论的例子都是二元分类问题,它看起来像这样:

但是我们在生活中遇到的情况远不止这么简单,我们经常要解决多类别分类问题。所以这节我们将介绍 一对多(one-vs-all) 的分类算法。

先看这样一些例子🌰:

  • 🌰 第一个例子:假如说你现在需要一个学习算法能自动地将邮件归类到不同的文件夹里,或者说可以自动地加上标签,那么,你也许需要一些不同的文件夹,或者不同的标签来完成这件事,来区分开来自工作的邮件、来自朋友的邮件、来自家人的邮件或者是有关兴趣爱好的邮件,那么,我们就有了这样一个分类问题:其类别有四个,分别用y=1y=1y=2y=2y=3y=3y=4y=4 来代表。

  • 🌰 第二个例子是有关药物诊断的,如果一个病人因为鼻塞来到你的诊所,他可能并没有生病,用 y=1y=1 这个类别来代表;或者患了感冒,用 y=2y=2 来代表;或者得了流感用y=3y=3 来代表。

  • 🌰 第三个例子:如果你正在做有关天气的机器学习分类问题,那么你可能想要区分哪些天是晴天、多云、雨天、或者下雪天,对上述所有的例子,yy 可以取一个很小的数值,一个相对 "谨慎" 的数值,比如 1 到 3、1 到 4 或者其它数值.

这些都是多分类的例子,对于这些例子,我们的数据集或许看起来像右边这样:

用 3 种不同的符号来代表 3 个类别,问题就是给出 3 个类型的数据集,我们如何得到一个学习算法来进行分类呢?

我们现在已经知道如何进行二元分类,即利用逻辑回归将数据集一分为二。我们可以把这种思想用在多类分类问题上。

假设现在我们有一个包含 3 个类别的训练集,我们用🔺表示 y=1y=1,🔲 表示y=2y=2,❌ 表示 y=3y=3。我们下面要做的就是将它分成 3 个二元分类问题。

比如我们要划分🔺这一类,那我们就🔺作为正样本,其余数据都作为负样本,用⚪️表示。可以这样想,设置🔺的值为 1,⚪️的值为 0,通过之前逻辑回归的方法,我们就可以得到一个正边界,我们将这个模型记作hθ(1)(x)h_\theta^{\left( 1 \right)}\left( x \right)。同样的,我们可以得出划分❌ 的模型,将其记作 hθ(2)(x)h_\theta^{\left( 2 \right)}\left( x \right), 依此类推。
最后,我们得到一系列的模型,简记为:

hθ(i)(x)=p(y=ix;θ)(i=(1,2,3....k))h_\theta^{\left( i \right)}\left( x \right)=p\left( y=i|x;\theta \right)(i=\left( 1,2,3....k \right) )

在我们需要做预测的时候,我们将所有的分类机都运行一遍,然后对每一个输入变量,都选择最高可能性的输出变量。在这个例子中,我们要做的就是在我们三个分类器里面输入 xx,然后我们选择一个让 hθ(i)(x)h_\theta^{\left( i \right)}\left( x \right) 最大的ii,即maxihθ(i)(x)\mathop{\max}\limits_i\,h_\theta^{\left( i \right)}\left( x \right)

你现在知道了基本的挑选分类器的方法,选择出哪一个分类器是可信度最高效果最好的,那么就可认为得到一个正确的分类,无论ii 值是多少,我们都有最高的概率值,我们预测yy 就是那个值。这就是多类别分类问题,以及一对多的方法,通过这个小方法,你现在也可以将逻辑回归分类器用在多类分类的问题上。

# 正则化 (Regularization)

# 过拟合的问题

到现在为止,我们已经学习了几种不同的学习算法,包括线性回归和逻辑回归,它们能够有效地解决许多问题,但是当将它们应用到某些特定的机器学习应用时,会遇到 过拟合(over-fitting) 的问题,可能会导致它们效果很差。

如果我们有非常多的特征,我们通过学习得到的假设可能能够非常好地适应训练集(代价函数可能几乎为 0),但是可能会不能推广到新的数据。

下图是一个回归问题的例子:

第一个模型是一个线性模型,欠拟合,不能很好地适应我们的训练集;第三个模型是一个四次方的模型,过于强调拟合原始数据,而丢失了算法的本质:预测新数据。我们可以看出,若给出一个新的值使之预测,它将表现的很差,是过拟合,虽然能非常好地适应我们的训练集但在新输入变量进行预测时可能会效果不好;而中间的模型似乎最合适。

分类问题中也存在这样的问题:

B 站弹幕里有个形象的比喻,这三条拟合曲线就是直男、暖男和舔狗的区别。我们可以看到,xx 的次数越高,拟合的越好,但相应的预测的能力就可能变差。

问题是,如果我们发现了过拟合问题,应该如何处理?

  1. 丢弃一些不能帮助我们正确预测的特征。可以是手工选择保留哪些特征,或者使用一些模型选择的算法来帮忙(例如 PCA

  2. 正则化。 保留所有的特征,但是减少参数的大小(magnitude)。

# 代价函数

对于上面的的回归问题,如果我们的模型是:

hθ(x)=θ0+θ1x1+θ2x22+θ3x33+θ4x44{h_\theta}\left( x \right)={\theta_{0} }+{\theta_{1} }{x_{1} }+{\theta_{2} }{x_{2}^2}+{\theta_{3} }{x_{3}^3}+{\theta_{4} }{x_{4}^4}

显而易见,是那些高次项导致了过拟合的产生,所以如果我们能让这些高次项的系数接近于 0 的话,我们就能很好的拟合了。
所以我们要做的就是在一定程度上减小这些参数 $\theta $ 的值,这就是正则化的基本方法。要想减少θ3{\theta_{3} }θ4{\theta_{4} } 的大小,我们要做的便是修改代价函数,给θ3{\theta_{3} }θ4{\theta_{4} } 设置一点惩罚。这样做的话,我们在尝试最小化代价函数时也需要将这个惩罚纳入考虑。
修改后的代价函数如下:

J(θ)=minθ12m[i=1m(hθ(x(i))y(i))2+1000θ32+10000θ42]J(\theta)=\underset{\theta }{\mathop{\min } }\,\frac{1}{2m}[\sum\limits_{i=1}^{m}{ { {\left( { {h}_{\theta } }\left( { {x}^{(i)} } \right)-{ {y}^{(i)} } \right)}^{2} }+1000\theta _{3}^{2}+10000\theta _{4}^{2}]}

通过这样的代价函数选择出的θ3{\theta_{3} }θ4{\theta_{4} } 对预测结果的影响就比之前要小许多。

➡️ 推而广之,假如我们有非常多的特征,我们并不知道其中哪些特征我们要惩罚,那我们就将对所有的特征都进行惩罚,并且让代价函数最优化的软件来选择这些惩罚的程度。这样的结果是得到了一个较为简单的能防止过拟合问题的假设:

J(θ)=12m[i=1m(hθ(x(i))y(i))2+λj=1nθj2]J\left( \theta \right)=\frac{1}{2m}[\sum\limits_{i=1}^{m}{ { {({h_\theta}({ {x}^{(i)} })-{ {y}^{(i)} })}^{2} }+\lambda \sum\limits_{j=1}^{n}{\theta_{j}^{2} }]}

其中λ\lambda 又称为正则化参数(Regularization Parameter)。

根据惯例,我们不对θ0{\theta_{0} } 进行惩罚。

经过正则化处理的模型与原模型的可能对比如下图所示:

如果选择的正则化参数λ\lambda 过大,则会把所有的参数都最小化了,导致模型变成 hθ(x)=θ0{h_\theta}\left( x \right)={\theta_{0} },也就是上图中红色直线所示的情况,造成欠拟合。
那为什么增加的一项λ=j=1nθj2\lambda =\sum\limits_{j=1}^{n}{\theta_j^{2} } 可以使θ\theta 的值减小呢?
因为如果我们令 λ\lambda 的值很大的话,为了使 cost() 尽可能的小,所有的 θ\theta 的值(不包括θ0{\theta_{0} })都会在一定程度上减小。但若λ\lambda 的值太大了,那么θ\theta(不包括θ0{\theta_{0} })都会趋近于 0,这样我们所得到的只能是一条平行于xx 轴的直线。所以对于正则化,我们要取一个合理的 λ\lambda 的值,这样才能更好的应用正则化。

回顾一下代价函数,为了使用正则化,让我们把这些概念应用到到线性回归和逻辑回归中去,那么我们就可以让他们避免过度拟合了。

# 正则化线性回归

对于线性回归的求解,我们之前推导了两种学习算法:一种基于梯度下降,一种基于正规方程。

正则化线性回归的代价函数为:

J(θ)=12mi=1m[((hθ(x(i))y(i))2+λj=1nθj2)]J\left( \theta \right)=\frac{1}{2m}\sum\limits_{i=1}^{m}{[({ {({h_\theta}({ {x}^{(i)} })-{ {y}^{(i)} })}^{2} }+\lambda \sum\limits_{j=1}^{n}{\theta _{j}^{2} })]}

如果我们要使用梯度下降法令这个代价函数最小化,因为我们未对θ0\theta_0 进行正则化,所以梯度下降算法将分两种情形:

RepeatRepeat untiluntil convergenceconvergence{

θ0:=θ0a1mi=1m((hθ(x(i))y(i))x0(i)){\theta_0}:={\theta_0}-a\frac{1}{m}\sum\limits_{i=1}^{m}{(({h_\theta}({ {x}^{(i)} })-{ {y}^{(i)} })x_{0}^{(i)} })

θj:=θja[1mi=1m((hθ(x(i))y(i))xj(i)+λmθj]{\theta_j}:={\theta_j}-a[\frac{1}{m}\sum\limits_{i=1}^{m}{(({h_\theta}({ {x}^{(i)} })-{ {y}^{(i)} })x_{j}^{\left( i \right)} }+\frac{\lambda }{m}{\theta_j}]

forfor j=1,2,...nj=1,2,...n

​ }

对上面的算法中 $ j=1,2,...,n$ 时的更新式子进行调整可得:

θj:=θj(1aλm)a1mi=1m(hθ(x(i))y(i))xj(i){\theta_j}:={\theta_j}(1-a\frac{\lambda }{m})-a\frac{1}{m}\sum\limits_{i=1}^{m}{({h_\theta}({ {x}^{(i)} })-{ {y}^{(i)} })x_{j}^{\left( i \right)} }

可以看出,正则化线性回归的梯度下降算法的变化在于,每次都在原有算法更新规则的基础上令 $\theta $ 值减少了一个额外的值。

我们同样也可以利用正规方程来求解正则化线性回归模型,方法如下所示:

图中的矩阵尺寸为 (n+1)(n+1)(n+1)*(n+1)

# 正则化的逻辑回归

针对逻辑回归问题,我们在之前的课程已经学习过两种优化算法:我们首先学习了使用梯度下降法来优化代价函数J(θ)J\left( \theta \right),接下来学习了更高级的优化算法,这些高级优化算法需要你自己设计代价函数J(θ)J\left( \theta \right)

自己计算导数同样对于逻辑回归,我们也给代价函数增加一个正则化的表达式,得到代价函数:

J(θ)=1mi=1m[y(i)log(hθ(x(i)))(1y(i))log(1hθ(x(i)))]+λ2mj=1nθj2J\left( \theta \right)=\frac{1}{m}\sum\limits_{i=1}^{m}{[-{ {y}^{(i)} }\log \left( {h_\theta}\left( { {x}^{(i)} } \right) \right)-\left( 1-{ {y}^{(i)} } \right)\log \left( 1-{h_\theta}\left( { {x}^{(i)} } \right) \right)]}+\frac{\lambda }{2m}\sum\limits_{j=1}^{n}{\theta _{j}^{2} }

Python 代码:

import numpy as np
def costReg(theta, X, y, learningRate):
    first = (-y * np.log(sigmoid(X @theta.T)))
    second = ((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

要最小化该代价函数,通过求导,得出梯度下降算法为:

RepeatRepeat untiluntil convergenceconvergence{

θ0:=θ0a1mi=1m((hθ(x(i))y(i))x0(i)){\theta_0}:={\theta_0}-a\frac{1}{m}\sum\limits_{i=1}^{m}{(({h_\theta}({ {x}^{(i)} })-{ {y}^{(i)} })x_{0}^{(i)} })

θj:=θja[1mi=1m(hθ(x(i))y(i))xj(i)+λmθj]{\theta_j}:={\theta_j}-a[\frac{1}{m}\sum\limits_{i=1}^{m}{({h_\theta}({ {x}^{(i)} })-{ {y}^{(i)} })x_{j}^{\left( i \right)} }+\frac{\lambda }{m}{\theta_j}]

forfor j=1,2,...nj=1,2,...n

​ }

我们依旧可以用 TNC 函数来求解代价函数最小化的参数,值得注意的是参数θ0{\theta_{0} } 的更新规则与其他情况不同。

目前大家对机器学习算法可能还只是略懂,但是一旦你精通了线性回归、高级优化算法和正则化技术,坦率地说,你对机器学习的理解可能已经比许多工程师深入了。接下来,我们将学习一个非常强大的非线性分类器,它比现在解决问题的方法强大 N 倍,敬请期待。