机器学习-逻辑回归

5.5 逻辑回归

上次讲到了感知机,感知机的最大缺点就是只能解决线性可分的问题,即只能使用直线分类的情况。所以,感知机也被称为简单感知机或者是单层感知机,虽然单层感知机很弱,但是多层感知机就是我们所熟悉的神经网络了,所以感知机也是学习分类的基础。

既然感知机不能用于线性不可分的问题,那么有什么方法能解决线性不可分问题呢?那么就引入了这个小节我们要讲的内容,即逻辑回归。虽然叫逻辑回归,实际上它做的是分类的问题,主要是用于二分类,即只分为两类,是某个事物或者不是某个事物。而逻辑回归不同于感知机之处在于,逻辑回归是把分类作为概率来考虑的。

5.5.1 sigmoid函数

我们首先给出sigmoid函数的表达式,即:

 

现在我们来探究一下sigmoid函数是如何起作用的,如图5-5-1所示:

图5-5-1 

左边的坐标轴我们用于表示线性回归所预测出来的y值,而如右图所示的曲线为sigmoid函数,我们将线性回归预测出的y值当作自变量映射到sigmoid函数中,如图虚线所示。由于sigmoid的函数的取值范围在0-1之间,所以说我们可以利用这一特性把分类作为概率来考虑,这就是逻辑回归的原理。这就是为什么说逻辑回归名字叫回归却为什么干着分类的事,实际上是线性回归的一种映射,映射的效果是分类。现在我们将t换成线性回归的表达式

                            

所以sigmoid函数表达式可以写成如下:  

我们用上次讲感知机的时候讲的矩形分为横向或者是纵向来研究,如图5-5-2所示:

图5-5-2

我们可以把表达式写为这样:

1表示分类为横向,0表示分类为纵向。我们知道矩形有宽高两个特征,即宽(x1)高(x2),我们先对θ进行随意取个值便于理解,

 

 

这个不等式表示的范围就是分类为横向的范围,如图5-5-3所示:

图5-5-3

同理上图虚线的左边就被分类为纵向,我们称这条用于决策分类的线为决策边界。很明显这个虚线并不能正确的分类矩形的横纵向,所以我们的目标就是求得正确的θ。

5.5.2似然函数

如何来求参数θ的更新表达式呢?其实跟梯度下降迭代的表达式类似,不过损失函数的表达式不太一样,我们这里用到似然函数。假设P(y=1|x)表示图像为横向的概率,P(y=0|x)表示图像为纵向的概率,如图所示对于6个训练数据,我们期待的最大概率如表5-5-4所示:

表5-5-4

假设所有的训练数据都是互不影响、独立发生的,这种情况下整体的概率就可以用下面的联合概率来表示:

将概率全部乘起来的意思就是连续发生的概率,例如仍骰子,第一次仍1点,第二次仍2点,第三次仍3点的概率为三个六分之一连乘。回归的时候处理的是误差,所以要最小化,而现在考虑联合概率,我们希望尽可能大,这里的目标函数L(θ)被称为是似然函数。我们可以公式化的表示似然函数,这样即简洁又有利于我们之后的计算:

 

利用任何数的0次方都为1的特性,当y(i)带入1和0时,都能够正确的表示。

 

5.5.3对数似然函数

我们直接把似然函数作为损失函数进行微分会很难,首先它是联合概率。概率都是1以下,如果训练数据过多,那么概率乘法的值会越来越小,编程时也会出现精度问题。如何使之计算量变小呢?我们知道与乘法相比加法的计算量要小很多,那我们可不可以使之,转化为加法运算而不影响得出的结果呢?如果学习过高数,那我们就可能联想到对数运算,对数内的乘法可以拆分为加法运算,且对数是具有单调性的,如图5-5-5所示:

图5-5-5

那么x1<x2时,log(x1)< log(x2)也是成立的,那么似然函数L(θ1)<  L(θ2)时,

也有logL(θ1)< log L(θ2),那么求似然函数的对数的最大值对应的θ也就是求似然函数最大值对应的θ。

既然这样,那我们只需要在似然函数等式两边加上log即可:

顺着我们利用对数将乘法转加法的思路,将对数似然函数变形:

 

对数似然函数的变形主要用到了,对数函数的特性

log(ab)=loga + logb

logab = bloga

所以我们将这个对数似然函数作为目标函数,像梯度下降法一样对各个参数θj求微分,得到θj的更新表达式即可。详细推导步骤如下图5-5-6所示:

图5-5-6

不过我们与梯度下降法不同的是,我们要以最大化为目标,迭代方向要与微分结果符号相同的方向移动,即:

这就是我们所要求得的目标θ的迭代公式了。

既然知道了θ的更新表达式,那么逻辑回归的代码就容易很多了:

import numpy as np
import matplotlib.pyplot as plt

# 读入训练数据
train = np.loadtxt('images2.csv', delimiter=',', skiprows=1)
train_x = train[:,0:2]
train_y = train[:,2]

# 参数初始化
theta = np.random.rand(3)

# 标准化
mu = train_x.mean(axis=0)
sigma = train_x.std(axis=0)
def standardize(x):
    return (x - mu) / sigma

train_z = standardize(train_x)

# 增加 x0
def to_matrix(x):
    x0 = np.ones([x.shape[0], 1])
    return np.hstack([x0, x])

X = to_matrix(train_z)

# sigmoid 函数
def f(x):
    return 1 / (1 + np.exp(-np.dot(x, theta)))

# 分类函数
def classify(x):
    return (f(x) >= 0.5).astype(np.int)

# 学习率
ETA = 1e-3

# 重复次数
epoch = 5000

# 更新次数
count = 0

# 重复学习
for _ in range(epoch):
    theta = theta - ETA * np.dot(f(X) - train_y, X)  # θ的更新表达式

    # 日志输出
    count += 1
    print('第 {} 次 : theta = {}'.format(count, theta))

# 绘图确认
x0 = np.linspace(-2, 2, 100)
plt.plot(train_z[train_y == 1, 0], train_z[train_y == 1, 1], 'o')
plt.plot(train_z[train_y == 0, 0], train_z[train_y == 0, 1], 'x')
plt.plot(x0, -(theta[0] + theta[1] * x0) / theta[2], linestyle='dashed')
plt.show()

迭代运行结果如下图:

 截图和代码引自《白话机器学习的数学》

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值