逻辑回归模型和Python代码实现
创始人
2024-03-16 17:38:16
0

文章目录

  • 逻辑回归原理
    • sigmoid函数
    • 优化建模
  • 代码实现
    • 自编代码
    • sklearn代码
  • 代码测试
    • 原理测试
    • 交叉验证

逻辑回归原理

此前介绍的线性回归基本模型和增加了正则项的优化模型都只能用来预测连续值(标签值是多少),如果想要应用于分类问题(标签值是1还是0),就还需要进一步操作,即本文即将介绍的逻辑回归,其本质是预测标签值是1和0的概率分别为多少。

由于连续值的取值范围为(−∞,+∞)(-\infty, +\infty)(−∞,+∞),而概率值的取值范围是(0,1)(0, 1)(0,1),所以需要将线性回归模型得到的连续值做一次转换,压缩到(0,1)(0, 1)(0,1)中。

sigmoid函数

在逻辑回归模型中,将连续值压缩的方式是使用sigmoid函数,其表达式为
f(x)=11+e−xf(x)=\frac{1}{1+e^{-x}}f(x)=1+e−x1​
sigmoid函数的图形如下,显然f(x)f(x)f(x)的范围是(0,1)(0, 1)(0,1)。

图形实线的Python代码为

import matplotlib.pyplot as plt
import numpy as np
import math# sigmoid函数
def sigmoid(x):return 1 / (1 + math.exp(-x))def plot_sigmoid():# 构造x和y数据x = np.linspace(-6, 6, 100)y = []for i in x:y.append(sigmoid(i))# 绘制基本数据plt.figure(figsize=(5, 5))plt.plot(x, y)# 将y轴移至坐标原点,并去除右侧实线ax = plt.gca()ax.xaxis.set_ticks_position('bottom')ax.spines['bottom'].set_position(('data', 0))ax.yaxis.set_ticks_position('left')ax.spines['left'].set_position(('data', 0))ax.spines['right'].set_color('none')# 增加坐标标签plt.xlabel('x', loc='right')plt.ylabel('f(x)', loc='top', rotation=0)if __name__ == '__main__':# 绘制sigmoid曲线plot_sigmoid()

除了以上的图示,我们还可以从数学角度来推演:针对样本的预测值y^\hat{y}y^​,其线性回归表达式为
y^=w1∗x1+w2∗x2+...+wn∗xn+b\hat{y}=w_1*x_1+w_2*x_2+...+w_n*x_n+by^​=w1​∗x1​+w2​∗x2​+...+wn​∗xn​+b
y^\hat{y}y^​的范围是(−∞,+∞)(-\infty, +\infty)(−∞,+∞),那么指数函数ey^e^{\hat{y}}ey^​的范围是(0,+∞)(0, +\infty)(0,+∞),构造如下的表达式
ey^ey^+1\frac{e^{\hat{y}}}{e^{\hat{y}}+1}ey^​+1ey^​​
显然,上式的范围即为(0,1)(0, 1)(0,1),而对上式的分子和分母同时除以ey^e^{\hat{y}}ey^​,得到
11+e−y^\frac{1}{1+e^{-\hat{y}}}1+e−y^​1​
以上即为sigmoid函数。

到了这里,其实就出现了一个问题:逻辑回归为什么要使用sigmoid函数?是否可以使用其他函数替代?
我在网上找了很久,但并没有找到让我折服的解释,其中一篇算是说的比较全的了,放在这里以作参考。

优化建模

基于以上分析,我们可以做出以下定义:针对任意一个样本,其分类结果为1的概率为
f=11+e−y^f=\frac{1}{1+e^{-\hat{y}}}f=1+e−y^​1​
其中,y^=w1∗x1+w2∗x2+...+wn∗xn+b\hat{y}=w_1*x_1+w_2*x_2+...+w_n*x_n+by^​=w1​∗x1​+w2​∗x2​+...+wn​∗xn​+b。

该样本被分类为0的概率即为
g=1−11+e−y^g=1-\frac{1}{1+e^{-\hat{y}}}g=1−1+e−y^​1​
分子和分母同时乘以ey^e^{\hat{y}}ey^​,得到
g=11+ey^g=\frac{1}{1+e^{\hat{y}}}g=1+ey^​1​
对于该样本来说,要让分类模型准确,那么,如果真实标签yyy为1,则应该让fff最大化;反之,应该让ggg最大化。
因此,对于整个训练集来说,可以建立优化模型为:寻找最佳的w1,w2,...,wn,bw_1, w_2,...,w_n,bw1​,w2​,...,wn​,b,使得如下表达式最大化
F∗GF*GF∗G
其中,FFF为所有真实标签为1的样本对应的fff函数的连乘;GGG为所有真实标签为0的样本对应的ggg函数的连乘。
事实上,此即为,概率论中的最大似然函数,不过名称不重要,重要的是对建模过程的理解。

以上定义的问题是一个无约束优化问题,可以使用很多优化算法求解,例如梯度类算法等。

代码实现

自编代码

接下来看一下,如何编写代码实现对权重系数www和截距bbb的优化计算。

以下代码中,使用的是forge数据集。该数据集有2维特征,所以待优化的变量有三个:w1,w2,bw_1, w_2, bw1​,w2​,b。values实现了对连乘的计算,同时在外侧增加了log函数,以此解决因为values本身数值过小而导致提前收敛的风险。优化方法使用的是scipy.optimize命令。

from scipy import optimize# 自编代码,带优化函数
def f(t):# 【数据集1】forgeX, y = forge()values = 0for i in range(len(y)):# 去log,否则数值太小,无法优化if y[i] == 1:values -= math.log(1 / (1 + math.exp(-t[0] * X[i, 0] - t[1] * X[i, 1] - t[2])))if y[i] == 0:values -= math.log(1 / (1 + math.exp(t[0] * X[i, 0] + t[1] * X[i, 1] + t[2])))return values# self代码优化权重系数和截距
def logreg_by_self():res = optimize.minimize(f, [0, 0, 0], method='BFGS')print('coef_by_self: {}, intercept_by_self: {}'.format(res.x[0:2], res.x[2]))

sklearn代码

如果调用工具包,可以直接使用sklearn.linear_model中的LogisticRegression即可。

from sklearn.linear_model import LogisticRegression# sklearn优化权重系数和截距
def logreg_by_sklearn():# 【数据集1】forgeX, y = forge()logreg = LogisticRegression(penalty='none', solver="lbfgs")logreg.fit(X, y)print('coef_by_sklearn: {}, intercept_by_sklearn: {}'.format(logreg.coef_, logreg.intercept_))

代码测试

原理测试

首先校验自编代码的准确性,调用以上两个函数,对比各自得到的权重系数和截距值

if __name__ == '__main__':# 对比self和sklearn计算结果logreg_by_self()logreg_by_sklearn()

代码输出结果如下所示。显然,两个方法得到的权重系数和截距是一致的,由此验证了原理和代码的正确性。

coef_by_self: [1.28004377 4.13686808], intercept_by_self: -21.37174954243782
coef_by_sklearn: [[1.28004046 4.13685915]], intercept_by_sklearn: [-21.37170026]

交叉验证

事实上,逻辑回归模型中也可以使用交叉验证的策略,进一步提升算法的性能指标。以下代码针对cancer数据集,使用交叉验证的方式,得到了最佳的正则化系数C。

import numpy as np
from sklearn.linear_model import LogisticRegression, LogisticRegressionCV
from sklearn.model_selection import train_test_split# sklearn代码实现逻辑回归
def logreg_cv_by_sklearn(X, y):# 数据集拆分X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)# 构造不同的Cs值,logregCV交叉验证得到最佳CCs = np.logspace(-5, 2, 20)# 默认solver是lbfgs,会提示未收敛,故修改为liblinearlogregCV = LogisticRegressionCV(Cs=Cs, cv=5, solver="liblinear")logregCV.fit(X_train, y_train)print('Logreg_best_C: {}'.format(logregCV.C_))# 使用最佳C重新训练logreg = LogisticRegression(C=logregCV.C_[0], solver="liblinear")logreg.fit(X_train, y_train)print('Training set score: {}'.format(logreg.score(X_train, y_train)))print('Test set score: {}'.format(logreg.score(X_test, y_test)))if __name__ == '__main__':# 【数据集3】cancer,用于实现交叉验证cancer_data, X_arr, y_arr = breast_cancer()# sklearn代码实现交叉验证logreg_cv_by_sklearn(X_arr, y_arr)

运行以上的程序,可以得到如下结果。

Logreg_best_C: [100.]
Training set score: 0.9741784037558685
Test set score: 0.965034965034965

相关内容

热门资讯

AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWR报告解读 WORKLOAD REPOSITORY PDB report (PDB snapshots) AW...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
群晖外网访问终极解决方法:IP... 写在前面的话 受够了群晖的quickconnet的小水管了,急需一个新的解决方法&#x...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
Azure构建流程(Power... 这可能是由于配置错误导致的问题。请检查构建流程任务中的“发布构建制品”步骤,确保正确配置了“Arti...