逻辑回归模型——公式推导与python代码实现

1.前言

  逻辑回归模型虽然名字是回归,但是实际上是一种二类(0或1)分类模型。在本文中,0代表负类,1代表正类。逻辑模型的输入为样本的特征向量 x \boldsymbol{x} x,输出为 P ( y = 1 ∣ x ) P(y=1|\boldsymbol{x}) P(y=1x) P ( y = 0 ∣ x ) P(y=0|\boldsymbol{x}) P(y=0x),即在输入特征向量为 x \boldsymbol{x} x条件下,样本标签属于某一类的概率。因为本文讨论的只是二类分类模型,所以有 P ( y = 1 ∣ x ) + P ( y = 0 ∣ x ) = 1 P(y=1|\boldsymbol{x})+P(y=0|\boldsymbol{x})=1 P(y=1x)+P(y=0x)=1。在实际使用过程中,一般是需要指定一个阈值,比如0.5,如果逻辑回归模型的输出 P ( y = 1 ∣ x ) ≥ 0.5 P(y=1|\boldsymbol{x}) \ge 0.5 P(y=1x)0.5,则认为此样本为正类,如果 P ( y = 1 ∣ x ) < 0.5 P(y=1|\boldsymbol{x}) < 0.5 P(y=1x)<0.5,则认为样本为负类。当然阈值是根据实际需求设置的,如果对正类的要求比较严格,则可以将阈值设的高一点,比如0.7。

2.逻辑回归模型

  首先我们来说一下线性回归,我们知道线性回归是用一个一元方程来拟合输入 x \boldsymbol{x} x与输出 y y y之间的关系:
y = w ⋅ x + b y=\boldsymbol{w} \cdot \boldsymbol{x}+b y=wx+b那我们能不能直接将 P ( y = 1 ∣ x ) P(y=1|\boldsymbol{x}) P(y=1x)看作 y y y带入上式来构成逻辑回归模型呢?即:
P ( y = 1 ∣ x ) = w ⋅ x + b P(y=1|\boldsymbol{x})=\boldsymbol{w} \cdot \boldsymbol{x}+b P(y=1x)=wx+b这样显然不合理,因为等式的左边为概率,取值应该为 0 ≤ P ( y = 1 ∣ x ) ≤ 1 0 \le P(y=1|\boldsymbol{x}) \le 1 0P(y=1x)1,而等式右边的取值范围为 [ − ∞ , + ∞ ] [-\infty,+\infty] [,+]。所以应该找一个函数,将等式右边的取值范围从 [ − ∞ , + ∞ ] [-\infty,+\infty] [,+]映射到 [ 0 , 1 ] [0,1] [0,1]上,这个函数就是sigmoid函数,其数学表达式如下,其函数图像见下图:
σ ( z ) = 1 1 + exp ( − z ) = exp ( z ) 1 + exp ( z ) \sigma(\boldsymbol{z})=\frac{1}{1+\text{exp}(-z)}=\frac{\text{exp}(z)}{1+\text{exp}(z)} σ(z)=1+exp(z)1=1+exp(z)exp(z)
图1 sigmoid函数图像
将等式的右边作为 z z z带入到sigmoid函数中,便得到了逻辑回归模型:
P ( y = 1 ∣ x ) = exp ( w ⋅ x + b ) 1 + exp ( w ⋅ x + b ) P ( y = 0 ∣ x ) = 1 1 + exp ( w ⋅ x + b ) P(y=1|\boldsymbol{x})=\frac{\text{exp}(\boldsymbol{w} \cdot \boldsymbol{x}+b)}{1+\text{exp}(\boldsymbol{w} \cdot \boldsymbol{x}+b)} \\ P(y=0|\boldsymbol{x})=\frac{1}{1+\text{exp}(\boldsymbol{w} \cdot \boldsymbol{x}+b)} P(y=1x)=1+exp(wx+b)exp(wx+b)P(y=0x)=1+exp(wx+b)1有了模型之后,接下来我们就要讨论如何求解模型参数 w \boldsymbol{w} w b b b,为了后面推导方便,我们将参数模型参数 w \boldsymbol{w} w b b b合并为一个向量,还是记为 w \boldsymbol{w} w,同时为了保持维度一致,将输入向量也进行扩充即:
w = ( w ( 1 ) , w ( 2 ) , . . . , w ( n ) ) , b ) T x = ( x ( 1 ) , x ( 2 ) , . . . , x ( n ) , 1 ) T \boldsymbol{w}=(w^{(1)},w^{(2)},...,w^{(n)}),b)^T \\ \boldsymbol{x}=(x^{(1)},x^{(2)},...,x^{(n)},1)^T w=(w(1),w(2),...,w(n)),b)Tx=(x(1),x(2),...,x(n),1)T此时,逻辑回归模型就可以写为:
P ( y = 1 ∣ x ) = σ ( x ) = exp ( w ⋅ x ) 1 + exp ( w ⋅ x ) P ( y = 0 ∣ x ) = 1 − σ ( x ) = 1 1 + exp ( w ⋅ x ) P(y=1|\boldsymbol{x})=\sigma(\boldsymbol{x})=\frac{\text{exp}(\boldsymbol{w} \cdot \boldsymbol{x})}{1+\text{exp}(\boldsymbol{w} \cdot \boldsymbol{x})} \\ P(y=0|\boldsymbol{x})=1-\sigma({\boldsymbol{x}})=\frac{1}{1+\text{exp}(\boldsymbol{w} \cdot \boldsymbol{x})} P(y=1x)=σ(x)=1+exp(wx)exp(wx)P(y=0x)=1σ(x)=1+exp(wx)1

3.损失函数

3.1 交叉熵损失函数

  为了求解模型的最优参数,我们首先要找到合适的损失函数,并极小化损失函数,当损失最小时,此时的参数就是最优参数。我们首先想到的是线性回归所使用的损失函数,即均方误差:
L ( w ) = 1 2 ∑ i = 1 N ( σ ( x i ) − y i ) 2 L(\boldsymbol{w})=\frac{1}{2}\sum_{i=1}^{N}(\sigma(\boldsymbol{x}_i)-y_i)^2 L(w)=21i=1N(σ(xi)yi)2但是逻辑回归处理的是分类问题, y i y_i yi不是0就是1,而不是线性回归中的连续的数,所以均方误差在这里可能是一个非凸函数,则如下图所示,图片来源于吴恩达的机器学习课程的笔记,图中的 J ( θ ) J(\theta) J(θ)为损失函数。这就意味着损失函数有很多局部最小值,无法确保能通过梯度下降算法找到全局最优值。
图2 非凸函数和凸函数
所以均方误差将不适用于逻辑回归模型。

  实际上,逻辑回归使用的是交叉熵损失函数,其数学表达式如下:
L ( w ) = ∑ i = 1 N [ − y i ln ( σ ( x i ) ) − ( 1 − y i ) ln ( 1 − σ ( x i ) ) ] L(\boldsymbol{w})=\sum_{i=1}^{N}[-y_i\text{ln}(\sigma(\boldsymbol{x}_i))-(1-y_i)\text{ln}(1-\sigma(\boldsymbol{x}_i))] L(w)=i=1N[yiln(σ(xi))(1yi)ln(1σ(xi))]交叉熵损失函数的特点就是:当样本真实标签 y i = 1 y_i=1 yi=1时,损失函数第二项就为0,逻辑回归模型的输出 σ ( x i ) \sigma(\boldsymbol{x}_i) σ(xi)越接近1,则损失越小,当 σ ( x i ) = 1 \sigma(\boldsymbol{x}_i)=1 σ(xi)=1时,损失为0;同理,当样本真实标签 y i = 0 y_i=0 yi=0时,损失函数第一项就为0,逻辑回归模型的输出 σ ( x i ) \sigma(\boldsymbol{x}_i) σ(xi)越接近0,则损失越小,当 σ ( x i ) = 0 \sigma(\boldsymbol{x}_i)=0 σ(xi)=0时,损失为0。交叉熵损失函数被广泛应用于分类任务中,不仅适用于二分类,而且适用于多分类。

3.2 从极大似然估计角度理解损失函数

  其实也可以从极大似然估计的角度来理解逻辑回归模型的损失函数。首先,我们写出模型的似然函数:
∏ i = 1 N [ σ ( x i ) ] y i [ 1 − σ ( x i ) 1 − y i ] \prod_{i=1}^{N}[\sigma(\boldsymbol{x}_i)]^{y_i}[1-\sigma(\boldsymbol{x}_i)^{1-y_i}] i=1N[σ(xi)]yi[1σ(xi)1yi]则对数似然函数为:
L ( w ) = ∑ i = 1 N [ y i ln ( σ ( x i ) ) + ( 1 − y i ) ln ( 1 − σ ( x i ) ) ] L(\boldsymbol{w})=\sum_{i=1}^{N}[y_i\text{ln}(\sigma(\boldsymbol{x}_i))+(1-y_i)\text{ln}(1-\sigma(\boldsymbol{x}_i))] L(w)=i=1N[yiln(σ(xi))+(1yi)ln(1σ(xi))]可以发现对数似然函数就是负的交叉熵损失函数。其实二者的意思相同,只不过从损失函数的角度,我们是要极小化损失函数,而从极大似然估计的角度,我们是要使对数似然函数最大。后面的公式推导中,我们将采用极小化交叉熵损失函数求解模型参数。

4.模型参数求解

4.1 梯度下降法

  为了求导方便,我们首先对损失函数进行化简:
L ( w ) = − ∑ i = 1 N [ y i ln ( σ ( x i ) ) + ( 1 − y i ) ln ( 1 − σ ( x i ) ] = − ∑ i = 1 N [ y i ln ( σ ( x i ) 1 − σ ( x i ) ) + ln ( 1 − σ ( x i ) ) ] = − ∑ i = 1 N [ y i ln ( exp ( w ⋅ x ) ) + ln ( 1 1 + exp ( w ⋅ x ) ) ] = − ∑ i = 1 N [ y i ( w ⋅ x ) − ln ( 1 + exp ( w ⋅ x ) ) ] L(\boldsymbol{w})=-\sum_{i=1}^{N}[y_i\text{ln}(\sigma(\boldsymbol{x}_i))+(1-y_i)\text{ln}(1-\sigma(\boldsymbol{x}_i)] \\ =-\sum_{i=1}^{N}[y_i\text{ln}(\frac{\sigma(\boldsymbol{x}_i)}{1-\sigma(\boldsymbol{x}_i)})+\text{ln}(1-\sigma(\boldsymbol{x}_i))] \\ =-\sum_{i=1}^{N}[y_i\text{ln}(\text{exp}(\boldsymbol{w} \cdot \boldsymbol{x}))+\text{ln}(\frac{1}{1+\text{exp}(\boldsymbol{w} \cdot \boldsymbol{x})})] \\ =-\sum_{i=1}^{N}[y_i(\boldsymbol{w} \cdot \boldsymbol{x})-\text{ln}(1+\text{exp}(\boldsymbol{w} \cdot \boldsymbol{x}))] L(w)=i=1N[yiln(σ(xi))+(1yi)ln(1σ(xi)]=i=1N[yiln(1σ(xi)σ(xi))+ln(1σ(xi))]=i=1N[yiln(exp(wx))+ln(1+exp(wx)1)]=i=1N[yi(wx)ln(1+exp(wx))]下面开始求 L ( w ) L(\boldsymbol{w}) L(w) w \boldsymbol{w} w的梯度:
∇ w L ( w ) = − ∑ i = 1 N ( y i x i − exp ( w ⋅ x i ) 1 + exp ( w ⋅ x i ) x i ) = − ∑ i = 1 N ( y i − exp ( w ⋅ x i ) 1 + exp ( w ⋅ x i ) ) x i = ∑ i = 1 N ( exp ( w ⋅ x i ) 1 + exp ( w ⋅ x i ) − y i ) x i = ∑ i = 1 N ( σ ( x i ) − y i ) x i \nabla_{\boldsymbol{w}}L(\boldsymbol{w})=-\sum_{i=1}^{N}(y_i\boldsymbol{x}_i-\frac{\text{exp}(\boldsymbol{w} \cdot \boldsymbol{x}_i)}{1+{\text{exp}(\boldsymbol{w} \cdot \boldsymbol{x}_i)}}\boldsymbol{x}_i) \\ =-\sum_{i=1}^{N}(y_i-\frac{\text{exp}(\boldsymbol{w} \cdot \boldsymbol{x}_i)}{1+{\text{exp}(\boldsymbol{w} \cdot \boldsymbol{x}_i)}})\boldsymbol{x}_i \\ =\sum_{i=1}^{N}(\frac{\text{exp}(\boldsymbol{w} \cdot \boldsymbol{x}_i)}{1+{\text{exp}(\boldsymbol{w} \cdot \boldsymbol{x}_i)}}-y_i)\boldsymbol{x}_i \\ =\sum_{i=1}^{N}(\sigma(\boldsymbol{x}_i)-y_i)\boldsymbol{x}_i wL(w)=i=1N(yixi1+exp(wxi)exp(wxi)xi)=i=1N(yi1+exp(wxi)exp(wxi))xi=i=1N(1+exp(wxi)exp(wxi)yi)xi=i=1N(σ(xi)yi)xi有了梯度之后就可以利用梯度下降来更新模型参数了,即:
w = w − η ∇ w L ( w ) \boldsymbol{w}=\boldsymbol{w}-\eta\nabla_{\boldsymbol{w}}L(\boldsymbol{w}) w=wηwL(w)其中, η \eta η表示学习率。梯度下降的代码如下:

 #训练,梯度下降
    def train(self, train_data, train_label):
        print("start to train")
        for iter in range(self.max_iter):
            #用for循环一行一行的实现梯度下降
            for i in range(len(train_data)):
                x = np.array([train_data[i]])
                y = train_label[i]
                wx = np.dot(x, self.w)
                self.w -= self.learning_rate*(np.exp(wx)/ ( 1 + np.exp(wx))) - y) * x.T

            #直接用矩阵实现
            #计算 w*x
            # wx = np.dot(train_data, self.w)
            # #计算梯度
            # gradient = np.dot(train_data.T, (self.sigmoid(wx) - train_label))
            # #更新权值
            # self.w -= self.learning_rate*gradient
        print("training completed")
        print("w is {}".format(self.w))

4.2 牛顿法

  牛顿法的原理可以参考李航《统计学习方法》的附录B部分,这里就不详述了。利用牛顿法更新模型参数的公式如下:
w = w − H − 1 ∇ w L ( w ) \boldsymbol{w}=\boldsymbol{w}-H^{-1}\nabla_{\boldsymbol{w}}L(\boldsymbol{w}) w=wH1wL(w)其中H使Hessian矩阵,Hessian矩阵即一阶梯度 ∇ w L ( w ) \nabla_{\boldsymbol{w}}L(\boldsymbol{w}) wL(w) w T \boldsymbol{w}^T wT的梯度,其求解公式如下:
H = ∇ w T ( ∇ w L ( w ) ) = ∇ w T ( ∑ i = 1 N ( σ ( x i ) − y i ) x i ) = ∇ w T ( ∑ i = 1 N ( exp ( w ⋅ x i ) 1 + exp ( w ⋅ x i ) ) x i ) = ∑ i = 1 N x i T ( exp ( w ⋅ x i ) ( 1 + exp ( w ⋅ x i ) ) − exp ( w ⋅ x i ) 2 [ 1 + exp ( w ⋅ x i ) ] 2 ) x i = ∑ i = 1 N x i T σ ( x i ) ( 1 − σ ( x i ) ) x i H=\nabla_{\boldsymbol{w}^T}(\nabla_{\boldsymbol{w}}L(\boldsymbol{w})) \\ =\nabla_{\boldsymbol{w}^T}(\sum_{i=1}^{N}(\sigma(\boldsymbol{x}_i)-y_i)\boldsymbol{x}_i) \\ =\nabla_{\boldsymbol{w}^T}(\sum_{i=1}^{N}(\frac{\text{exp}(\boldsymbol{w} \cdot \boldsymbol{x}_i)}{1+{\text{exp}(\boldsymbol{w} \cdot \boldsymbol{x}_i)}})\boldsymbol{x}_i) \\ =\sum_{i=1}^{N}\boldsymbol{x}_i^T(\frac{\text{exp}(\boldsymbol{w} \cdot \boldsymbol{x}_i)(1+\text{exp}(\boldsymbol{w} \cdot \boldsymbol{x}_i))-\text{exp}(\boldsymbol{w} \cdot \boldsymbol{x}_i)^2}{[1+\text{exp}(\boldsymbol{w} \cdot \boldsymbol{x}_i)]^2})\boldsymbol{x}_i \\ =\sum_{i=1}^{N}\boldsymbol{x}_i^T\sigma(\boldsymbol{x}_i)(1-\sigma(\boldsymbol{x}_i))\boldsymbol{x}_i H=wT(wL(w))=wT(i=1N(σ(xi)yi)xi)=wT(i=1N(1+exp(wxi)exp(wxi))xi)=i=1NxiT([1+exp(wxi)]2exp(wxi)(1+exp(wxi))exp(wxi)2)xi=i=1NxiTσ(xi)(1σ(xi))xi上述求导过程中用到了列向量对行向量的导数,在《矩阵理论》课程里有讲到。
  求得Hessian矩阵后便可以对模型参数进行更新了,代码如下:

 #训练,牛顿法
    def train(self, train_data, train_label):
        print("start to train")
        for iter in range(self.max_iter):
            #一行一行的求解
            for i in range(len(train_data)):
                # 因为取出的x是个1维数组,无法进行转置,所以将其扩充为2维
                x = np.array([train_data[i]])
                y = train_label[i]
                wx = np.dot(x, self.w)
                #计算一阶导数
                gradient = np.dot(x.T, (self.sigmoid(wx) - y))
                #计算Hessian矩阵
                Hessian = np.dot(x.T, self.sigmoid(wx)).dot((1 - self.sigmoid(wx))).dot(x)
                #权值更新
                self.w -= self.learning_rate * np.linalg.pinv(Hessian).dot(gradient)
        print("training completed")
        print("w is {}".format(self.w))

5.参考资料

1.李航《统计学习方法》
2.https://www.cnblogs.com/veraLin/p/10003400.html
3.https://www.sohu.com/a/270954377_777125
4.https://github.com/fengdu78/lihang-code

推荐阅读:
SMO算法求解支持向量机的理论推导与代码实现
机器学习算法——支持向量机(3)
机器学习算法——支持向量机(2)
机器学习算法——支持向量机(1)

也欢迎大家关注我的公众号:MyLearningNote
在这里插入图片描述

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
本案例将使用逻辑回归模型来预测居民的出行方式选择行为。数据集包含居民的个人和家庭信息以及出行方式的选择情况。我们将使用Python语言进行分析和建模。 首先,加载需要用到的库和数据集: ```python import pandas as pd import numpy as np import matplotlib.pyplot as plt %matplotlib inline data = pd.read_csv('modechoice.csv') ``` 接下来,我们对数据集进行探索和预处理: ```python # 查看数据集的前5行 data.head() # 将数据集分为自变量和因变量 X = data.iloc[:, :-1] y = data.iloc[:, -1] # 将分类变量转换为数值型变量 X = pd.get_dummies(X, columns=['Gender', 'Education', 'Income', 'Car', 'Bike']) # 将因变量转换为0和1的二元变量 y = np.where(y=='Car', 1, 0) # 将数据集分为训练集和测试集 from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) ``` 然后,我们使用逻辑回归算法进行建模: ```python from sklearn.linear_model import LogisticRegression model = LogisticRegression() model.fit(X_train, y_train) ``` 接下来,我们评估模型的性能: ```python # 预测测试集的结果 y_pred = model.predict(X_test) # 计算模型的准确率 from sklearn.metrics import accuracy_score accuracy_score(y_test, y_pred) ``` 最后,我们可以使用模型来进行预测: ```python # 创建一个新的数据集 new_data = pd.DataFrame({ 'Gender_Female': [1], 'Gender_Male': [0], 'Education_Graduate': [0], 'Education_High School': [1], 'Education_Others': [0], 'Income_High': [1], 'Income_Low': [0], 'Income_Medium': [0], 'Car_No': [1], 'Car_Yes': [0], 'Bike_No': [0], 'Bike_Yes': [1] }) # 预测新数据的结果 model.predict(new_data) ``` 本案例中使用的数据集是一个虚构的例子,实际应用中需要根据具体的场景选择合适的数据集和特征工程方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

llfighting2018

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值