机器学习算法系列(3)Logistic Regression

上一篇文章讲到了线性模型,线性模型形式十分简单,却有丰富的变化。一般线性模型有一定的缺陷,那就是\(y=w^Tx+b\)的预测值是为数值型的,当面对要求预测值为离散型就有些力不从心了,它会很容易受到异常值的影响,从而导致误差。那么,可不可以令预测值\(y\)变成另外一种形式呢?比如,在分类任务里,我们要求预测值为离散型的,得到一个\(yes\ or\ no\)的答案,不再是原来的连续性预测值,这里就要用到机器学习中的一个重要的模型——Logistic Regression,即逻辑斯蒂回归或对数线性回归(log-linear regression),即

\[\begin{equation} \mathrm{ln}y=w^Tx+b \end{equation}\]

实际上是在试图让\(e^{w^T+b}\)逼近\(y\),形式上仍然是线性回归,但实质上是在求线性空间到非线性空间的映射。

目录

  • Logistic分布
  • Logistic函数
  • 极大似然估计(MLE)
  • 梯度下降算法(Gradient Descent)
  • Python代码实现及分析

Logistic分布

在学习Logistic regression之前,我们有必要了解一下logistic分布函数和密度函数 \[\begin{equation} F(x)=P(X\le{x})=\frac{1}{1+e^{-(x-\mu)/\gamma}} \end{equation}\] \[\begin{equation} f(x)=F'(x)=\frac{e^{-(x-\mu)/\gamma}}{\gamma{(1+e^{-(x-\mu)/\gamma})}^2} \end{equation}\]

式中,\(\mu\)为位置参数,\(\gamma\gt0\)是形状参数

Logistic分布函数和密度函数

Logistic分布函数和密度函数

逻辑斯蒂函数实际上是线性回归模型的预测结果取逼近真是标记的对数几率,其对应的模型是对数几率回归

Logistic函数

考虑一个二分类任务,其输出标记为\(y∈\{0,1\}\),而线性回归模型产生的预测值z是实数值,于是我们需要将z转换为0/1值,理想的方法是logistic函数

\[\begin{equation} y=\frac{1}{1+e^{-z}} \end{equation}\]

logistic函数是一种“Sigmoid函数”,它将\(z\)值转化为一个接近0或1的\(y\)值,并且输出值在\(z=0\)附近的变化很陡峭,若预测值大于零就判为正例,小于零就判为反例,预测值为临界值零则可任意判别

Sigmoid函数

Sigmoid函数

如果我们将线性模型\(y=w^T+b\)代入上式,得

\[\begin{equation} y=\frac{1}{1+e^{-(w^Tx+b)}} \end{equation}\]

变形

\[\begin{equation} \mathrm{ln}\frac{y}{1-y}=w^Tx+b \end{equation}\]

若将\(y\)视为\(x\)作为正例的可能性,\(1-y\)视为反例的可能性,两者的比值称为“对数几率”(logit odds),反映了\(x\)作为正例的可能性。

由此可以看出,实际上是在用线性回归的模型的预测结果去逼近真实标记的对数几率,因此其对应的模型称为“对数几率回归”(logistic regression)。

极大似然估计(MLE)

类似线性回归,我们需要定义一个损失函数(loss function),然后通过最小化损失函数来训练出一个分类器,对于logistic regression,哪种损失函数表现最好?假设选用0-1损失函数,考虑1000个样本,用训练得到的分类器分类,960个被分在了正确的一类,其余40个划分错误,那么这里损失函数的大小就是40。考虑调整\(w\)的大小,得到的损失函数值可能仍然是相同的,没有优化的空间。0-1损失函数看来是行不通,不妨看看log损失函数,为什么选择log损失函数,考虑-log(x)函数图像,趋近于0的地方函数值趋于无穷大,相比0-1损失函数,它的惩罚性能实在太好,而且它的损失函数是凸函数,存在可优化的空间。

-log(x)损失函数

-log(x)损失函数

由logistic函数,建立如下表达式

\[\begin{equation} h_w(x)=g(w^Tx)=\frac{1}{1+e^{-w^Tx}} \end{equation}\]

显然有

\[\begin{equation} \begin{aligned} p(y=1|x)&=h_w(x)\\ p(y=0|x)&=1-h_w(x)\\ p(y|x)&={h_w(x)}^y{(1-h_w(x))}^{1-y}, y=0, 1 \end{aligned} \end{equation}\]

于是,我们可以通过极大似然估计法(maximum likelihood method)来估计\(w\)(为了计算的方便,将偏置项\(b\)的权重设为1,记为\(w_0\)

给定数据集\(\{(x_i,y_i)\}_{i=1}^m\),写出对应极大似然函数

\[\begin{equation} \begin{aligned} L(\theta)&=\prod_{i=1}^{m}p(y^(i)|x^(i);\theta) \\ &=\prod_{i=1}^{m}h_w{(x^{(i)})}^{y^{(i)}}{(1-h_w(x^{(i)}))}^{1-y^{(i)}} \end{aligned} \end{equation}\]

再对两边取对数

\[\begin{equation} logL(\theta)=\sum_{i=1}^{m}[y^{(i)}logh_w(x^{(i)})+(1-y^{(i)})log(1-h_w(x^{(i)}))] \end{equation}\]

因此损失函数可以通过最大化负的似然函数得到

\[\begin{equation} J(\theta)=-\frac{1}{m}\sum_{i=1}^{m}[y^{(i)}logh_w(x^{(i)})+(1-y^{(i)})log(1-h_w(x^{(i)}))] \end{equation}\]

梯度下降算法(Gradient Descent)

上式中\(J(\theta)\)是一个关于\(\theta\)的高阶可导连续凸函数,根据凸优化理论,采用梯度下降法求最优解,\(\theta=(w,b),minJ(\theta)\)

\[\begin{equation} {\theta}_j:={\theta}_j-\alpha\frac{\partial}{\partial{\theta}_j}J(\theta) \end{equation}\]

其中,\(\frac{\partial}{\partial{\theta}_j}J(\theta)=\frac{1}{m}\sum_{i=1}^{m}(h_w(x^{(i)})-y^{(i)})x_j^{(i)}\)\(\alpha\)是步长。

总的来说,logistic regression是一类比较简单的分类算法,可以把它看做是一类广义线性模型,即线性模型的延伸即可。logistic regression能够很好地胜任二分类问题,logistic regression中关键的问题在于参数优化,传统的0-1损失函数非凸,我们不能对其进行优化以得到一个较优参数,log损失函数是一个不错的选择,它使得损失函数呈凸函数形状(本身并非平方损失函数),这就让梯度下降算法有了施展的空间。

Python代码实现及分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
from numpy import *
import numpy as np
# 加载数据集,loadDataSet()函数的主要功能是打开文本文件,并逐行读取;
# 每行的前两列分别为X1,X2,除此以外,还为偏置项设置一列X0
def loadDataSet():
data = []; label = []
fr = open(`testSet.txt`)
for line in fr.readlines():
linArr = line.strip().split()
data.append([1.0, float(linArr[0]), float(linArr[1])])
label.append(int(linArr[2]))
return data, label
# 定义sigmoid函数
def sigmoid(z):
return 1.0 / (1.0 + exp(-z))
# 定义梯度下降算法
# 设定步长alpha为0.001,迭代次数为500次,初始权重theta为长度为n值全为1的向量
def graDescent(data, label):
dataMatrix = np.numpy(data); labelMatrix = np.numpy(label).T
m,n = shape(dataMatrix)
alpha = 0.001
iters = 500
theta = ones((n,1))
for k in range(iters):
h = sigmoid(dataMatrix * theta)
error = (labelMatrix - h)
theta = theta - alpha * dataMatrix.T * error
return theta
# 画出决策边界
def plotfit(theta):
import matplotlib.pylot as plt
import numpy as np
n = dataArr.shape[0]
x1 = []; y1 = []
x2 = []; y2 = []
for i in range(n):
if int(label[i]) == 1:
x1.append(dataArr[i,1]); y1.append(dataArr[i,2])
else:
x2.append(dataArr[i,1]); y2.append(dataArr[i,2])
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(x1, y1, s = 30, c = 'red', marker = 'o')
ax.scatter(x2, y2, s = 30, c = 'blue', marker = 'x')
x = arange(-3.0, 3.0, 0.1) # 创建等差数列,设定x的取值范围为-3.0到3.0
y = (-theta[0] - theta[1] * x) / theta[2]
ax.plot(x,y)
plt.xlabel('X1');plt.ylabel('X2');
plt.show()
梯度下降算法迭代500次之后得到的拟合曲线

梯度下降算法迭代500次之后得到的拟合曲线

分类的结果看起来还不错,从图上看,只有4个点被错分。