Logistic 回归,又名逻辑回归,它从线性回归发展而来,是一种广义的线性回归模型;该模型预测输出的是样本类别的条件概率分布,因而可以取概率值最大的类别作为分类结果,实质上是一个分类模型。

目录

  • 算法原理
    • sigmoid函数
    • 逻辑回归模型
    • 极大似然估计
  • numpy实现逻辑回归
    • 算法改写矩阵形式
    • 数据加载
    • 模型实现
    • 实现对比

算法原理

sigmoid函数

首先设想一个应用场景下的分类问题:某电商网站有着大量的商品,当用户看到这些商品时,有两个选择,一是点击,二是不点击。如果点击的类型是购买,则用户的这一行为将给商家带来直接的收益。由于电商网站使用的模型要预测用户是否点击这个行为,取值只有两个。目前学过的分类算法只有 KNN,但由于 KNN 严重依赖训练数据,一旦出现近邻的噪声样本,就会对最终的预测结果产生严重的影响。另一方面,KNN 用在电商这个大数据量的场景下显然是不合适的。一是计算量大、效率低:每预测一个样本,都要和所有已知的训练样本计算距离,样本的特征空间大多是成千上万的,这样就造成了计算的困难。二是电商场景下的样本类别不平衡问题会导致正样本的召回率偏低,毕竟用户的不点击行为是占多数的,而 KNN 是使用多数表决的分类规则。

回想人类自身的判断与决策过程:当有50%以上的把握时,我们就可以判定事物的属性或者决定是否要做某一件事情,这个50%以上的把握可以理解为事件发生的概率值大于0.5 。如果将线性回归的输出值zzz映射为[0,1]之间的概率值,那么就可以通过概率值来进行分类决策了。具体到前面商品点击的例子中,可以通过预测用户点击商品的概率值,来判断该用户是否会点击购买当前的商品。

现在的问题是找到一个可以将线性回归的预测值 zzz 映射到 [0,1] 之间任意取值的函数。恰好数学中就有sigmoid函数:


这个函数实际上是Logistic 分布的分布函数,它的形状为一条S形曲线,因而人们习惯把它叫做Sigmoid函数。观察图像可知,该函数关于点(0,0.5)中心对称,且靠近对称中心时的增长速度较快。sigmoid函数公式为:
σ(z)=11+e−z\sigma(z)=\frac{1}{1+e^{-z}}σ(z)=1+e−z1​
其对zzz的导数为:
σ′(z)=σ(z)[1−σ(z)]\sigma'(z)=\sigma(z)[1-\sigma(z)]σ′(z)=σ(z)[1−σ(z)]
对 sigmoid 函数求导得到的是随机变量 zzz 的概率密度函数:

图中函数曲线与 xxx 轴围成的面积为1,表示随机变量 zzz 取所有可能值的概率之和为1。物体质量的密度衡量了物体质量在空间中不同位置的分布情况;概率密度则衡量了概率值1在随机变量 zzz 的不同取值区间内的分布情况。

逻辑回归模型

将线性回归的预测输出代入 Sigmoid 函数就得到了逻辑回归的预测函数:
f(xi)=σ(w⋅xi),i∈{1,2,...,m}f(x_{i})=\sigma(w\cdot x_{i}),i\in \left \{ 1,2,...,m\right\}f(xi​)=σ(w⋅xi​),i∈{1,2,...,m}
该函数预测输出的是样本 iii 属于正例的概率值。具体地,可以理解成用户发生点击行为的概率,如果概率大于 0.5,则判断用户会点击购买当前的商品,否则不点击。

概率决策的阈值一般取 0.5,也可以根据实际情况进行调整。某医院拥有患者大量的病理特征数据,如果使用逻辑回归来预测病人得癌症的概率,进而确定病人是否患了癌症。在判断病人是否患癌症这个场景中,要从患者的角度考虑误诊风险。将阈值设置为 0.5 以上很可能导致原本患癌症的病人错过最佳的治疗时机,造成不可挽回的生命损失。正确的做法是在 0.5 的基础上调低阈值。


"回归"二字的由来
在解释这个问题之前,先了解几个概念:一个是随机事件发生的几率,另一个是对数几率。随机事件发生的几率指的是该事件发生的概率与不发生概率的比值,用来衡量该事件发生的相对可能性大小。事件 iii 发生的几率:
f(xi)1−f(xi)=ew⋅xi,i∈{1,2,...,m}\frac{f(x_{i})}{1-f(x_{i})}=e^{w \cdot x_{i}},i\in \left \{ 1,2,...,m\right\}1−f(xi​)f(xi​)​=ew⋅xi​,i∈{1,2,...,m}
对数几率,顾名思义就是上面的结果取对数:
In(f(xi)1−f(xi))=In(ew⋅xi)=w⋅xi,i∈{1,2,...,m}In(\frac{f(x_{i})}{1-f(x_{i})})=In(e^{w \cdot x_{i}})=w \cdot x_{i},i\in \left \{ 1,2,...,m\right\}In(1−f(xi​)f(xi​)​)=In(ew⋅xi​)=w⋅xi​,i∈{1,2,...,m}
由此发现,对数几率正是线性回归模型对样本 iii 的预测输出值,换句话说,logistic 回归是使用线性回归来预测事件发生的对数几率,所以 logistic 回归又叫对数几率回归。


前面已经推导出随机事件发生与不发生的概率表达式。进一步地,可以将二分类的逻辑回归模型表示成如下形式的条件概率分布:
P(yi=1∣xi)=σ(w⋅xi),i∈{1,2,...,m}P(y_{i}=1|x_{i})=\sigma(w\cdot x_{i}),i\in \left \{ 1,2,...,m\right\}P(yi​=1∣xi​)=σ(w⋅xi​),i∈{1,2,...,m}
P(yi=0∣xi)=1−σ(w⋅xi),i∈{1,2,...,m}P(y_{i}=0|x_{i})=1-\sigma(w\cdot x_{i}),i\in \left \{ 1,2,...,m\right\}P(yi​=0∣xi​)=1−σ(w⋅xi​),i∈{1,2,...,m}
等式左边是条件概率的表示方法,简单来说就是:给定样本特征 xix_{i}xi​ 的条件下,样本标记 yiy_{i}yi​ 取值为 1 或 0 的概率。由此可知,二项逻辑回归是服从伯努利分布(又称两点分布、零一分布)的概率模型。逻辑回归不是直接预测样本的类别,而是对分类的可能性进行建模,这样可以得到类别概率的近似值,更有利于分类决策。

机器学习模型可以分为概率模型非概率模型,前面的线性回归和K近邻都属于非概率模型,用预测函数y=f(x)y=f(x)y=f(x)来表示;而概率模型一般用条件概率分布 P(y∣x)P(y|x)P(y∣x) 来表示,逻辑回归既可看作是概率模型,又可看作是非概率模型。


在后面的学习中,朴素贝叶斯和决策树属于概率模型;K均值和感知机与支持向量机属于非概率模型。在监督学习中,概率模型是生成模型,非概率模型是判别模型。


极大似然估计

逻辑回归的模型参数是通过极大化对数似然函数来估计得到的。似然函数(likelihood function)是一种关于概率模型参数的函数,逻辑回归的似然函数为:
∏i=1mP(yi∣xi)\prod_{i=1}^{m}P(y_{i}|x_{i})i=1∏m​P(yi​∣xi​)
其中 mmm 是样本个数,P(yi∣xi)P(y_{i}|x_{i})P(yi​∣xi​) 是在给定样本特征 xix_{i}xi​ 的条件下, 模型将样本 iii 预测为真实标记值 yiy_{i}yi​ 的概率,将每个样本预测正确的概率连乘起来就得到了似然函数。由于 xix_{i}xi​ 和 yiy_{i}yi​ 是已知的,故似然函数的表达式是关于模型参数的函数。

二项逻辑回归的似然函数可以表示成如下样本概率连乘的形式:
∏i=1m[P(yi=1∣xi)]yi[P(yi=0∣xi)]1−yi\prod_{i=1}^{m}[P(y_{i}=1|x_{i})]^{y_{i}}[P(y_{i}=0|x_{i})]^{1-y_{i}}i=1∏m​[P(yi​=1∣xi​)]yi​[P(yi​=0∣xi​)]1−yi​
二项逻辑回归的似然函数也可以写成样本预测函数连乘的形式:
∏i=1m[σ(w⋅xi)]yi[1−σ(w⋅xi)]1−yi\prod_{i=1}^{m}[\sigma(w\cdot x_{i})]^{y_{i}}[1-\sigma(w\cdot x_{i})]^{1-y_{i}}i=1∏m​[σ(w⋅xi​)]yi​[1−σ(w⋅xi​)]1−yi​
由于每个样本的概率值位于 [0,1] 之间,连乘之后将会变成一个很小的数,可能会引起浮点数下溢。当样本数 mmm 很大时,似然函数的值会趋向于 0,非常不利于之后的计算。所以,将原似然函数取对数,使其从积的形式转变为和的形式,得到的对数似然函数 L(w)L(w)L(w) 如下:
L(w)=∑i=1m[yilog(σ(w⋅xi))+(1−yi)log(1−σ(w⋅xi))]L(w)=\sum_{i=1}^{m}[y_{i}log(\sigma(w\cdot x_{i}))+(1-y_{i})log(1-\sigma(w\cdot x_{i}))]L(w)=i=1∑m​[yi​log(σ(w⋅xi​))+(1−yi​)log(1−σ(w⋅xi​))]
由对数似然函数 L(w)L(w)L(w) 的表达式可知,模型将训练样本预测正确的概率越大,对数似然函数的值就越大。所以只要极大化 L(w)L(w)L(w),对应的 www 值就是要求解的模型参数了。

分类模型的损失函数一般使用如下形式的对数损失(又称交叉熵损失):
L(yi,P(yi∣xi))=−logP(yi∣xi),i∈{1,2,...,m}L(y_{i},P(y_{i}|x_{i}))=-logP(y_{i}|x_{i}),i\in \left \{ 1,2,...,m\right\}L(yi​,P(yi​∣xi​))=−logP(yi​∣xi​),i∈{1,2,...,m}
由公式可知,分类模型在样本 iii 上的预测损失为:模型将样本 iii 预测为真实分类 yiy_{i}yi​ 的概率取负对数。所以,对数损失函数值越小,模型在该样本上的表现就越好。进一步地,分类模型在整个训练集上的对数损失可以表示成如下形式:
−∑i=1mlogP(yi∣xi)-\sum_{i=1}^{m}logP(y_{i}|x_{i})−i=1∑m​logP(yi​∣xi​)
二分类模型在整个训练集上的对数损失如下:
−∑i=1m[yilog(σ(w⋅xi))+(1−yi)log(1−σ(w⋅xi))]-\sum_{i=1}^{m}[y_{i}log(\sigma(w\cdot x_{i}))+(1-y_{i})log(1-\sigma(w\cdot x_{i}))]−i=1∑m​[yi​log(σ(w⋅xi​))+(1−yi​)log(1−σ(w⋅xi​))]
二项逻辑回归的对数似然函数 L(w)L(w)L(w) 和它在训练集上的对数损失互为相反数。也就是说,极大化对数似然函数等价于极小化训练集上的对数损失。极小化对数损失使用梯度下降法,而极大化似然函数要使用梯度上升法:沿梯度方向更新模型参数。


梯度上升
根据对数似然函数:
L(w)=∑i=1m[yilog(σ(w⋅xi))+(1−yi)log(1−σ(w⋅xi))]L(w)=\sum_{i=1}^{m}[y_{i}log(\sigma(w\cdot x_{i}))+(1-y_{i})log(1-\sigma(w\cdot x_{i}))]L(w)=i=1∑m​[yi​log(σ(w⋅xi​))+(1−yi​)log(1−σ(w⋅xi​))]
然后根据链式法则(复合函数求导法则)求解对数似然函数的梯度:
L′(w)=∑i=1m[yi−σ(w⋅xi)]xiL'(w)=\sum_{i=1}^{m}[y_{i}-\sigma(w\cdot x_{i})]x_{i}L′(w)=i=1∑m​[yi​−σ(w⋅xi​)]xi​
最后沿梯度方向更新模型参数向量:
w=w+αL′(w)w=w+\alpha L'(w)w=w+αL′(w)


numpy实现逻辑回归

算法改写矩阵形式

使用 numpy 实现逻辑回归算法,然后利用该算法在乳腺癌数据集上进行癌症诊断。

首先回顾算法原理,将其改写至矩阵形式,输入数据xxx形状为(m,n)(m,n)(m,n),www的形状为(n,1)(n,1)(n,1),则预测为正例的概率为:
f(x)=σ(xw)f(x)=\sigma(xw)f(x)=σ(xw)
将损失函数J(w)J(w)J(w)写成矩阵形式:
J(w)=−1m[yTlog(f(x))+(1−y)Tlog(1−f(x))]J(w)=-\frac{1}{m}[y^{T}log(f(x))+(1-y)^{T}log(1-f(x))]J(w)=−m1​[yTlog(f(x))+(1−y)Tlog(1−f(x))]
其中,类别标签yyy形状为(m,1)(m,1)(m,1)

将参数www形状转换为(1,n)(1,n)(1,n),如果是极大化似然函数,参数更新需要沿着似然函数的梯度方向,前面计算过似然函数对于参数的梯度为:
L′(w)=∑i=1m[yi−σ(w⋅xi)]xiL'(w)=\sum_{i=1}^{m}[y_{i}-\sigma(w\cdot x_{i})]x_{i}L′(w)=i=1∑m​[yi​−σ(w⋅xi​)]xi​
因此矩阵表达为:
w=w+αL′(w)=w+α[y−f(x)]Txw=w+\alpha L'(w)=w+\alpha[y-f(x)]^{T}xw=w+αL′(w)=w+α[y−f(x)]Tx

数据加载

数据加载和预处理:

from sklearn.datasets import load_breast_cancer
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split# 获取乳腺癌数据集
cancer = load_breast_cancer()
# 获取数据集特征
X = cancer.data
# 获取数据集标记
y = cancer.target
# 特征归一化到 [0,1] 范围内:提升模型收敛速度
X = MinMaxScaler().fit_transform(X)
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.2, random_state=2020)

模型实现

补充一个numpy的操作:

  • np.column_stack(tuple)
    将1维数组作为一列拼接到2维数组得到一个新的2维数组,或是拼接到1维数组成为2维数组:
a = np.array((1,2,3))
b = np.array((2,3,4))
np.column_stack((a,b))"""
array([[1, 2],[2, 3],[3, 4]])
"""

通过以上分析,模型实现为:

import numpy as np
import matplotlib.pyplot as pltclass LogisticRegression:'''逻辑回归算法实现'''def __init__(self, alpha=0.1, epoch=5000, fit_bias=True, threshold=0.5):'''alpha: 学习率,控制参数更新的幅度epoch: 在整个训练集上训练迭代(参数更新)的次数fit_bias: 是否训练偏置项参数threshold:判定为正类的概率阈值'''self.alpha = alphaself.epoch = epoch# cost_record 记录每一次迭代后的经验风险self.cost_record = []self.fit_bias = fit_biasself.threshold = threshold# 概率预测函数def predict_proba(self, X_test):'''X_test: m x n 的 numpy 二维数组'''# 模型有偏置项参数时:为每个测试样本增加特征 x_0 = 1if self.fit_bias:x_0 = np.ones(X_test.shape[0])X_test = np.column_stack((x_0, X_test))# 根据预测公式返回结果z = np.dot(X_test, self.w)return 1 / (1 + np.exp(-z))# 类别预测函数def predict(self, X_test):'''X_test: m x n 的 numpy 二维数组'''probs = self.predict_proba(X_test)results = map(lambda x: int(x > self.threshold), probs)return np.array(list(results))# 模型训练:使用梯度下降法更新参数def fit(self, X_train, y_train):'''X_train: m x n 的 numpy 二维数组y_train:有 m 个元素的 numpy 一维数组'''# 训练偏置项参数时:为每个训练样本增加特征 x_0 = 1if self.fit_bias:x_0 = np.ones(X_train.shape[0])X_train = np.column_stack((x_0, X_train))# 训练样本数量m = X_train.shape[0]# 样本特征维数n = X_train.shape[1]# 初始模型参数self.w = np.ones(n)# 模型参数迭代for i in range(self.epoch):# 计算训练样本预测值z = np.dot(X_train, self.w)y_pred = 1 / (1 + np.exp(-z))# 计算训练集经验风险cost = -(np.dot(y_train, np.log(y_pred)) + np.dot(np.ones(m) - y_train, np.log(np.ones(m) - y_pred))) / m# 记录训练集经验风险self.cost_record.append(cost)# 参数更新:梯度上升法self.w += self.alpha / m * np.dot(y_train - y_pred, X_train)# 保存模型self.save_model()# 显示经验风险的收敛趋势图def polt_cost(self):plt.plot(np.arange(self.epoch), self.cost_record)plt.xlabel("epoch")plt.ylabel("cost")plt.show()# 保存模型参数def save_model(self):np.savetxt("model.txt", self.w)# 加载模型参数def load_model(self):self.w = np.loadtxt('model.txt')

模型的训练和预测:

# 实例化一个对象
model = LogisticRegression()
# 在训练集上训练
model.fit(X_train,y_train)
# 在测试集上预测
y_pred = model.predict(X_test)

查看模型收敛趋势图:

model.polt_cost()

实现对比

与sklearn实现的逻辑回归对比:

from sklearn import linear_model # 实例化一个对象
model_1 = LogisticRegression(epoch=60000)
model_2 = linear_model.LogisticRegression()
# 在训练集上训练
model_1.fit(X_train,y_train)
model_2.fit(X_train,y_train)
# 在测试集上预测
y_pred_1 = model_1.predict(X_test)
y_pred_2 = model_2.predict(X_test)

利用 sklearn.metrics 模块中的一些评估函数来对两个模型进行评估:

import pandas as pd
from sklearn.metrics import accuracy_score
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
from sklearn.metrics import f1_score
from sklearn.metrics import roc_auc_scoremetrics = dict()acc_1 = accuracy_score(y_test,y_pred_1)
acc_2 = accuracy_score(y_test,y_pred_2)
metrics['准确率'] = [acc_1,acc_2]pre_1 = precision_score(y_test,y_pred_1)
pre_2 = precision_score(y_test,y_pred_2)
metrics['精确率'] = [pre_1,pre_2]rec_1 = recall_score(y_test,y_pred_1)
rec_2 = recall_score(y_test,y_pred_2)
metrics['召回率'] = [rec_1,rec_2]f1_1 = f1_score(y_test,y_pred_1)
f1_2 = f1_score(y_test,y_pred_2)
metrics['F1值'] = [f1_1,f1_2]auc_1 = roc_auc_score(y_test, model_1.predict_proba(X_test))
# model_2.predict_proba(X_test)的形状为(m,2),第0列是分类为负例的概率,第1列是分类为正例的概率
auc_2 = roc_auc_score(y_test, model_2.predict_proba(X_test)[:,1])
metrics['AUC'] = [auc_1,auc_2]df = pd.DataFrame(metrics,index=['model_1','model_2'])

结果df为:

第七课.Logistic回归算法相关推荐

  1. python实现logistic_用Python实现机器学习算法—Logistic 回归算法

    在 Logistic 回归中,我们试图对给定输入特征的线性组合进行建模,来得到其二元变量的输出结果.例如,我们可以尝试使用竞选候选人花费的金钱和时间信息来预测选举的结果(胜或负).Logistic 回 ...

  2. Python实现 logistic 回归算法

    Python实现 logistic 回归算法 1.算法介绍 模型描述: sigmoid函数: 原理: 优化目标:最小化 sigmoid(f(x)) 和真实标签的差别(有不同的 cost functio ...

  3. circle loss代码实现_Python全栈之路-23-使用Python实现Logistic回归算法

    视频讲解地址 使用Python实现Logistic回归算法_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili​www.bilibili.com 本文代码 地址​github.com Logistic ...

  4. Logistic 回归算法原理

    Logistic 回归算法原理 Sigmoid 函数 概率决策 分布函数 函数求导 逻辑回归模型 概率预测函数 对数几率回归 条件概率分布 极大似然估计 似然函数 对数似然 对数损失 梯度上升 Log ...

  5. 机器学习中的Logistic回归算法(LR)

    Logistic回归算法(LR) 算法简介 LR名为回归,实际是一种分类算法.其针对输入样本集 x x,假设的输出结果 y=hθ(x)y=h_{\theta}(x) 的取值范围为 y=[0,1] y= ...

  6. Logistic回归算法实战

    实战--预测病马的死亡率 前面,我简单介绍了「Logistic分类器」. Logistic回归算法 今天,我们将进行实战操练:使用Logistic分类器来预测患有疝病的马的存活率. 疝病是描述马胃肠痛 ...

  7. Logistic回归算法

    Logistic回归算法 类别 学习方法 数学知识 数据集 代码 详细内容 步骤 Logistic回归的数学表达式 Logistic回归的损失函数 优化 类别 类别:分类算法 学习方法 学习方法:有监 ...

  8. 数学解析Logistic回归算法

    数学解析Logistic回归算法 在<Logistic回归算法(分类问题)>一节,我们学习了 Logistic 回归算法,并且重点认识了 Logistic 函数.我们知道分类问题的预测结果 ...

  9. 机器学习--详解基于梯度下降的Logistic回归算法原理

    先给出Logistic回归的sigmod函数数学表达式: 很简单的表达式,再看看它的性质,当时,,因此 当时,,因此 Logistic回归之所以称为Logistic是因为只有两个状态即0和1,这也是数 ...

最新文章

  1. ldconfig及 LD_LIBRARY_PATH
  2. 计算机视觉方向简介 | 深度学习视觉三维重建
  3. MongoDB 4.0 事务实现解析
  4. 中科大计算机学院的保研率,中科大2021届保研率44.7%,少年班83.4%,物理计算机人数最多...
  5. Python安装某个库,出现Read_Time_out错误,那么如何配置 “国内镜像源”呢?
  6. java语言链栈_Java语言实现数据结构栈代码详解
  7. hadoop学习笔记-目录
  8. C++/C代码审查表
  9. SyncBird Pro的PhoneCare功能如何使用
  10. 10月17日云栖精选夜读:什么是新零售?阿里巴巴最新的报告终于说清楚了!(附报告)...
  11. Gateway网关- 微服务(十五)
  12. 关于网络的命令及介绍
  13. 发布源码及依赖到网络maven仓库
  14. android代码审计框架,路印协议已完成第三方代码安全审计
  15. BZOJ1016 || 洛谷P4208 [JSOI2008]最小生成树计数【矩阵树定理】
  16. 【电脑使用】利用diskpart删除电脑的EFI分区
  17. client?0edb:161 [WDS] Errors while compiling. Reload prevented.
  18. ACP敏捷管理认证的含金量高吗?
  19. MATLAB仪表表盘数字识别解析
  20. 转载《士兵突击》观后杂感

热门文章

  1. Java基础篇:多线程
  2. 敏捷估算和计划的12条知道原则
  3. 快速搭建一个网关服务,动态路由、鉴权看完就会(含流程图)
  4. 图解 SQL,这也太形象了吧!
  5. 360°透视:云原生架构及设计原则
  6. 信息流推荐的用户增长机制
  7. Redis 越来越慢?常见延迟问题定位与分析
  8. 解密 Redis 助力双 11 背后电商秒杀系统
  9. 简历包装要避开哪些坑,资深面试官告诉你!
  10. 搭建B2B2C多用户商城系统需要注意的事项