Logistic Regression原理及Python实现

本文介绍了Logistic Regression在解决二元分类问题中的应用,特别是在软性二元分类中的作用。通过实例解释了如何将线性得分转换为概率估计,并详细阐述了使用极大似然估计来确定最佳回归系数的过程。文章还提供了Python代码实现,展示如何训练对数几率回归模型并可视化结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 问题引入

相信大家都接触过分类问题,尤其是二元分类。例如现在有一些患者(训练集)的身体情况以及是否患有心脏病的数据,要求我们根据这些数据来预测其他患者(测试集)是否患有心脏病。这是比较简单的一个二元分类问题,使用线性分类器或许会取得不错的效果。但在实际生活中,我们感兴趣的往往不是其他患者是否会犯病,而是他犯心脏病的概率是多少。很直观的想法是收集患者犯病的概率,然后利用回归模型进行概率预测。但是我们并不能直接收集到患者犯病的概率,只能知到患者最后到底犯没犯病。也就是说,我们输入的标签是离散的类别型数据,但是期望得到数值型的概率。在机器学习中,这叫做“软性二元分类”(Soft Binary Classification),这类问题与普通的分类问题所要的数据相同,但是会得到不同的目标函数。接下来,我们就介绍一种可以解决“软性二元分类”问题的算法,那就是Logistic Regression(后文译为“对数几率回归)。

2. Logistic Regression

继续我们上面的预测患者是否会犯心脏病的问题。为了最终的预测,我们可以对患者的身体状况x=(x0,x1,x2⋯ ,xd)\mathbf{x} =(x_0,x_1,x_2\cdots,x_d)x=(x0,x1,x2,xd)按照不同的权重打分:

s=∑i=0dwixi s = \sum_{i = 0}^{d} w_i x_i s=i=0dwixi

然后用对数几率函数θ(s)\theta(s)θ(s)将分数转化成一个概率估计。对数几率函数的形式为:

θ(s)=es1+es=11+e−s \theta(s) = \frac {e^s} {1 + e^s} = \frac {1} {1 + e^{-s}} θ(s)=1+eses=1+es1

也就是说,对数几率回归通过h(x)=11+exp⁡(−wTx)h(\mathbf{x}) = \frac {1} {1 + \exp(-\mathbf{w}^T\mathbf{x})}h(x)=1+exp(wTx)1来逼近目标函数f(x)=P(+1∣x)f(\mathbf{x}) = P(+1 | \mathbf{x})f(x)=P(+1x),显然有:

P(y=1∣x)=f(x)P(y=0∣x)=1−f(x) P(y = 1 | \mathbf{x}) = f(\mathbf{x}) \\ P(y = 0 | \mathbf{x}) = 1 - f(\mathbf{x}) P(y=1x)=f(x)P(y=0x)=1f(x)

现在我们要面临的问题是如何对w\mathbf{w}w进行估计。在线性回归模型中,我们可以通过最小化均方误差来估计回归系数。但是在这里,好像并没有什么可以衡量误差的东西,所以我们要另辟蹊径。下面我们使用极大似然估计(Maximum Likelihood Estimation,简称MLE)来估计最优的回归系数,它是根据数据采样来估计概率分布参数的经典方法。

假设现在有一个数据集D={(x1,y1),(x2,y2),⋯ ,(xN,yn)}D = \{ (\mathbf{x}_1, y_1),(\mathbf{x}_2,y_2),\cdots,(\mathbf{x}_N,y_n) \}D={(x1,y1),(x2,y2),,(xN,yn)},生成该数据集的概率为:

∏i=1N[P(yi∣xi)]yi[1−P(yi∣xi)]1−yi \prod _{i = 1}^N [P(y_i | \mathbf{x}_i)]^{y_i}[1 - P(y_i | \mathbf{x}_i)]^{1 - y_i} i=1N[P(yixi)]yi[1P(yixi)]1yi

由于P(yi∣xi)P(y_i | \mathbf{x}_i)P(yixi)未知,所以我们用h(xi)h(\mathbf{x}_i)h(xi)来代替它:

∏i=1N[h(xi)]yi[1−h(xi)](1−yi) \prod _{i = 1}^N [h( \mathbf{x}_i)]^{y_i}[1 - h(\mathbf{x}_i)]^{(1 - y_i)} i=1N[h(xi)]yi[1h(xi)](1yi)

由于连乘不好优化,所以要将上式变成连加的形式,对上式取对数得对数似然函数:

L(w)=∑n=1N[yilog⁡h(xi)+(1−yi)log⁡(1−h(xi))]=∑n=1N[yilog⁡h(xi)1−h(xi)+log⁡(1−h(xi))]=∑n=1N[yilog⁡exp⁡(w⋅xi)/(1+exp⁡(w⋅xi))1/(1+exp⁡(w⋅xi))+log⁡(1−h(xi))]=∑n=1N[yi(w⋅xi)+log⁡(1+exp⁡(w⋅xi))] \begin{aligned} L(w) &= \sum _{n=1}^N \left[ y_i \log h(x_i) + (1-y_i)\log(1 - h(x_i)) \right ] \\ &= \sum _{n=1}^N \left[ y_i \log \frac {h(x_i)} {1 - h(x_i)} + \log(1 - h(x_i)) \right ] \\ &= \sum _{n=1}^N \left[ y_i \log \frac { {\exp(w·x_i)} / (1 + \exp(w·x_i))} {{1} /(1 + \exp(w·x_i))} + \log(1 - h(x_i)) \right ] \\ &= \sum _{n=1}^N \left[ y_i (w · x_i) + \log(1 + \exp (w · x_i)) \right ] \end{aligned} L(w)=n=1N[yilogh(xi)+(1yi)log(1h(xi))]=n=1N[yilog1h(xi)h(xi)+log(1h(xi))]=n=1N[yilog1/(1+exp(wxi))exp(wxi)/(1+exp(wxi))+log(1h(xi))]=n=1N[yi(wxi)+log(1+exp(wxi))]

L(w)L(w)L(w)求极大值即可得到www的估计值。这样,问题就变成了以对数似然函数为目标函数的最优化问题。求极大值可以采用梯度上升法。首先求得L(w)L(w)L(w)www上的梯度:

∇L(w)=∑n=1N[yi⋅xi−11+exp⁡(w⋅xi)⋅exp⁡(w⋅xi)⋅xi]=∑n=1N[yi⋅xi−exp⁡(w⋅xi)1+exp⁡(w⋅xi)⋅xi]=∑n=1N[xi⋅(yi−exp⁡(w⋅xi)1+exp⁡(w⋅xi))]=∑n=1N[xi⋅(yi−h(w⋅xi))] \begin{aligned} \nabla L(w) &= \sum _{n=1}^N \left [y_i \cdot x_i - \frac {1} {1 + \exp(w \cdot x_i)} \cdot \exp(w \cdot x_i) \cdot x_i\right ] \\ &= \sum _{n=1}^N \left [y_i \cdot x_i - \frac {\exp(w \cdot x_i)} {1 + \exp(w \cdot x_i)} \cdot x_i\right ] \\ &= \sum _{n=1}^N \left [x_i \cdot \left (y_i - \frac {\exp(w \cdot x_i)} {1 + \exp(w \cdot x_i)} \right )\right] \\ &= \sum _{n=1}^N \left [x_i \cdot \left (y_i - h(w \cdot x_i) \right )\right] \end{aligned} L(w)=n=1N[yixi1+exp(wxi)1exp(wxi)xi]=n=1N[yixi1+exp(wxi)exp(wxi)xi]=n=1N[xi(yi1+exp(wxi)exp(wxi))]=n=1N[xi(yih(wxi))]

那么,第k轮迭代时www的极大似然估计值为:

w^(k+1)←w^(k)+η⋅∇L(w(k)) \hat{w}^{(k+1)} \leftarrow \hat{w}^{(k)} + \eta \cdot \nabla L(w^{(k)}) w^(k+1)w^(k)+ηL(w(k))

经过多轮迭代后,我们便可以求得www的极大似然估计值。下面我们使用Python来实现对数几率回归这一算法。

首先,我们引入需要用到的模块,并加载数据集。

import numpy as np
import pandas as pd
from pandas import Series, DataFrame
import matplotlib.pyplot as plt
%matplotlib inline
df = pd.read_table('testSet.txt',header=None)
df.shape
(100, 3)
df.head()
012
0-0.01761214.0530640
1-1.3956344.6625411
2-0.7521576.5386200
3-1.3223717.1528530
40.42336311.0546770
data_mat = DataFrame({0:1, 1:df[0], 2:df[1]})
data_mat.head()
012
01-0.01761214.053064
11-1.3956344.662541
21-0.7521576.538620
31-1.3223717.152853
410.42336311.054677
label_mat = DataFrame(df[2])
label_mat.head()
2
00
11
20
30
40

通过观察数据集,我们可以看出data_mat是一个100×3100 \times 3100×3的矩阵,其中第一列全是111,表示模型中的常数(类似于线性回归中的bbb),而label_mat是一个100×1100 \times 1100×1的矩阵。下面我们先实现sigmoid函数:

def sigmoid(x_arr):
    return 1.0/(1+np.exp(-x_arr))

接下来我们实现对数几率回归。logistic_regression函数一共有四个参数:第一个参数代表输入的数据;第二个参数表示输入数据的标签;参数alpha代表学习率,默认为0.001;最后一个参数代表梯度上升的迭代次数,默认为500次。我们首先初始化变量weight为一个3×13 \times 13×1的全1矩阵,然后在每一轮迭代中计算h(x⋅w)h(x \cdot w)h(xw)的值,然后计算h与y_mat的差值error,error与x_mat相乘就是梯度,梯度与alpha相乘之后就可以更新weight。注意这里全都是矩阵运算。

def logistic_regression(x_arr, y_arr, alpha=.001, max_iter=500):
    x_mat = np.mat(x_arr)
    y_mat = np.mat(y_arr)
    weight = np.ones((x_mat.shape[1],1))
    for k in range(max_iter):
        h = sigmoid(x_mat * weight)
        error = (y_mat - h)
        weight = weight + alpha * x_mat.T * error
    return weight

将data_mat和label_mat作为参数传递给logistic_regression函数,得到回归系数的最佳估计值:

weight = logistic_regression(data_mat, label_mat)
weight
matrix([[ 4.12414349],
        [ 0.48007329],
        [-0.6168482 ]])

最后,通过图形来观察我们的模型:

data_arr = np.array(data_mat)
n = data_arr.shape[0]

xcord1 = list()
ycord1 = list()
xcord2 = list()
ycord2 = list()

for i in range(n):
    if int(label_mat.iloc[i]) == 1:
        xcord1.append(float(data_arr[i][1]))
        ycord1.append(float(data_arr[i][2]))
    else:
        xcord2.append(data_arr[i,1])
        ycord2.append(data_arr[i,2])
fig = plt.figure(figsize=(16,12))
plt.scatter(xcord1,ycord1,s=30,c='red',marker='s')
plt.scatter(xcord2,ycord2,s=30,c='green')
x = np.arange(-3.0, 3.0, .1)
y = -(weight[0] + weight[1] * x) / weight[2]
plt.plot(x,y)
plt.show()

这里写图片描述

可以看到,这条直线基本上将红点和绿点全部区分开来,这说明我们的模型效果还不错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值