二分类logistic回归实现讲解——梯度下降与可视化全过程

文章目录


前言

针对logistics回归中成本函数,梯度下降,公式推导,正则化约束全过程进行详细的讲解,可以针对感兴趣的部分点击目录跳转哦
梯度下降入门指导链接~


一、logistic回归

介绍

虽然名字里带回归,但它与线性回归不同,logistic回归本质上是分类问题 ,特别是二分类问题 (采用01进行分类,例如是或否问题)

logistic回归还可以认为是没有隐藏层的分类神经网络哦

如何获得logistic回归的输出值呢?一般采用线性回归+sigmoid激活实现

线性回归

z ⃗ = w ⃗ ⋅ x ⃗ + b i a s \vec{z} = \vec{w} \cdot \vec{x}+ bias z =w ⋅x +bias

优化方法 :

通过拓展特征向量 x ⃗ \vec{x} x 和权重向量 w ⃗ \vec{w} w ,可以将偏置项 b i a s bias bias 合并到权重向量中

通过拓展 X ⃗ : [ x 1 , x 2 , ... ... x n , 1 ] \vec{X}:[x_1 ,x_2, ......x_n, 1] X :[x1,x2,......xn,1],

拓展 W ⃗ : [ w 1 , w 2 ... ... w n , b ] \vec{W}: [w_1, w_2 ......w_n, b] W :[w1,w2......wn,b]

就可以讲 z ⃗ \vec{z} z 化简为 W ⃗ ⋅ X ⃗ \vec{W} \cdot \vec{X} W ⋅X

Sigmoid函数

sigmoid函数可以将输入映射到0~1之间
σ ( z ⃗ ) = 1 1 + e z ⃗ \sigma (\vec{z} ) = \frac{1}{1 + e^{\vec{z}}} σ(z )=1+ez 1

最后就可以输出一个概率标签

决策边界

一般设置p = 0.5,将输出的概率标签转换为类别标签,大于p判断为1,小于p判断为0

二、梯度下降

代价函数

代价函数是衡量我们训练的模型的好坏程度

提醒:

损失函数 (Loss Function):定义在单个样本上,计算一个样本 的误差。
代价函数 (Cost Function):定义在整个训练集 上,是所有样本误差的平均 。线性回归通常也采用最小二乘法求解参数 ,!

因为logistic回归本质上是分类问题,所以照搬线性回归的代价函数并没有意义

这里采用
L i ( f w , b ( X i ) ) = { − l n ( f w , b ( X i ) ) , y i = 1 − l n ( 1 − f w , b ( X i ) ) , y i = 0 L_{i}(f_{w,b}(X^{i})) =\left\{\begin{matrix} - ln(f_{w,b}(X^{i})), y^{i} = 1 \\ - ln(1 - f_{w,b}(X^{i})), y^{i} = 0 \end{matrix}\right . Li(fw,b(Xi))={−ln(fw,b(Xi)),yi=1−ln(1−fw,b(Xi)),yi=0
L = Σ i = 1 m L ( f w , b ( X i ) ) m L = \frac{\Sigma_{i = 1}^{m}{L(f_{w,b}(X^{i}))}}{m} L=mΣi=1mL(fw,b(Xi))

其中 f w , b ( X ) = 1 1 + e w ⋅ X ⃗ f_{w,b}(X) = \frac{1}{1 + e^{\vec{w \cdot X}}} fw,b(X)=1+ew⋅X 1

优化方法:

原有的 L i L_{i} Li函数还要根据 y y y值进行分类,在求导的时候难以处理,所以最好能够化简进行计算
根据01分类,一般采用 ( 1 − y ) f 1 ( x ) + y f 2 ( x ) (1 - y)f_1(x) + yf_2(x) (1−y)f1(x)+yf2(x)的格式 ,这样就可以合并01分类的函数,无需分类
J i ( f w , b ( X ( i ) ) ) = − y i ∗ l n ( f w , b ( X i ) ) − ( 1 − y i ) ∗ l n ( 1 − f w , b ( X i ) ) J_{i}(f_{w,b}(X^{(i)})) = - y^{i} * ln(f_{w,b}(X^{i})) - (1 - y^{i}) * ln(1 - f_{w,b}(X^{i})) Ji(fw,b(X(i)))=−yi∗ln(fw,b(Xi))−(1−yi)∗ln(1−fw,b(Xi))

求导过程

由于从L对 w i w_{i} wi和对b求偏导,只有在最后一步求偏导会有区别 ,区别在于

乘 x i x^{i} xi和 1 1 1的区别(因为 w i w_{i} wi与 x i x_{i} xi直接相乘,而b * 1对b求导为1

因此这里只展示对 w i w_{i} wi的偏导,对b的偏导几乎一摸一样
∂ J ( f w , b ( X ( i ) ) ) ∂ w j = − y ( i ) 1 f w , b ( X ( i ) ) ∂ f w , b ( X ( i ) ) ∂ e − w ⋅ X ( i ) ⋅ ∂ e − w ⋅ X ( i ) ∂ w j − ( 1 − y ( i ) ) 1 1 − f w , b ( X ( i ) ) ∂ ( 1 − f w , b ( X ( i ) ) ) ∂ e − w ⋅ X ( i ) ⋅ ∂ e − w ⋅ X ( i ) ∂ w j \frac{\partial J(f_{w,b}(X^{(i)}))}{\partial w_j} = - y^{(i)} \frac{1}{f_{w,b}(X^{(i)})} \frac{\partial f_{w,b}(X^{(i)})}{\partial e^{-w \cdot X^{(i)}}} \cdot \frac{\partial e^{-w \cdot X^{(i)}}}{\partial w_j} \\ - (1 - y^{(i)}) \frac{1}{1 - f_{w,b}(X^{(i)})} \frac{\partial (1 - f_{w,b}(X^{(i)}))}{\partial e^{-w \cdot X^{(i)}}} \cdot \frac{\partial e^{-w \cdot X^{(i)}}}{\partial w_j} ∂wj∂J(fw,b(X(i)))=−y(i)fw,b(X(i))1∂e−w⋅X(i)∂fw,b(X(i))⋅∂wj∂e−w⋅X(i)−(1−y(i))1−fw,b(X(i))1∂e−w⋅X(i)∂(1−fw,b(X(i)))⋅∂wj∂e−w⋅X(i)

代入 f w , b ( X ( i ) ) = 1 1 + e − w ⋅ X ( i ) f_{w,b}(X^{(i)}) = \frac{1}{1 + e^{-w \cdot X^{(i)}}} fw,b(X(i))=1+e−w⋅X(i)1 并化简:

= − y ( i ) ( 1 + e − w ⋅ X ( i ) ) ( − 1 ( 1 + e − w ⋅ X ( i ) ) 2 ) ∂ e − w ⋅ X ( i ) ∂ w i − ( 1 − y ( i ) ) 1 + e − w ⋅ X ( i ) e − w ⋅ X ( i ) 1 ( 1 + e − w ⋅ X ( i ) ) 2 ∂ e − w ⋅ X ( i ) ∂ w i = − y ( i ) 1 1 + e − w ⋅ X ( i ) e − w ⋅ X ( i ) x j ( i ) + ( 1 − y ( i ) ) 1 1 + e − w ⋅ X ( i ) x j ( i ) = x j ( i ) ⋅ 1 1 + e − w ⋅ X ( i ) ( 1 − y ( i ) ( 1 + e − w ⋅ X ( i ) ) ) = x j ( i ) ⋅ ( f w , b ( X ( i ) ) − y ( i ) ) = - y^{(i)} (1 + e^{-w \cdot X^{(i)}})( -\frac{1}{(1 + e^{-w \cdot X^{(i)}}) ^{2}}) \frac{\partial e^{-w\cdot X^{(i)}}}{\partial w_{i}} \\- (1 - y^{(i)})\frac{1 + e^{-w \cdot X^{(i)}}}{e^{-w\cdot X^{(i)}}}\frac{1}{(1 + e^{-w \cdot X^{(i)}}) ^{2}} \frac{\partial e^{-w\cdot X^{(i)}}}{\partial w_{i}}\\ \newline = -y^{(i)} \frac{1}{1 + e^{-w \cdot X^{(i)}}} e^{-w \cdot X^{(i)}} x_j^{(i)} + (1 - y^{(i)}) \frac{1}{1 + e^{-w \cdot X^{(i)}}} x_j^{(i)} \\ = x_j^{(i)} \cdot \frac{1}{1 + e^{-w \cdot X^{(i)}}} \left( 1 - y^{(i)}(1 + e^{-w \cdot X^{(i)}}) \right) \\ = x_j^{(i)} \cdot \left( f_{w,b}(X^{(i)}) - y^{(i)} \right) =−y(i)(1+e−w⋅X(i))(−(1+e−w⋅X(i))21)∂wi∂e−w⋅X(i)−(1−y(i))e−w⋅X(i)1+e−w⋅X(i)(1+e−w⋅X(i))21∂wi∂e−w⋅X(i)=−y(i)1+e−w⋅X(i)1e−w⋅X(i)xj(i)+(1−y(i))1+e−w⋅X(i)1xj(i)=xj(i)⋅1+e−w⋅X(i)1(1−y(i)(1+e−w⋅X(i)))=xj(i)⋅(fw,b(X(i))−y(i))

总梯度(对所有 m m m 个样本求平均):

∂ J ∂ w j = 1 m ∑ i = 1 m x j ( i ) ( f w , b ( X ( i ) ) − y ( i ) ) \frac{\partial J}{\partial w_j} = \frac{1}{m} \sum_{i=1}^{m} x_j^{(i)} \left( f_{w,b}(X^{(i)}) - y^{(i)} \right) ∂wj∂J=m1i=1∑mxj(i)(fw,b(X(i))−y(i))

是不是非常像线性回归的梯度公式呢 ∂ J ( w , b ) ∂ w = 1 n Σ i = 0 n x ( y ^ i − y i ) \frac{\partial{J}(w, b)}{\partial{w}} = \frac{1}{n}\Sigma^{n}{i=0}x(\hat y{i} - y_{i}) ∂w∂J(w,b)=n1Σi=0nx(y^i−yi)

这就是推导的全过程啦,如果有错误或者不理解的地方欢迎到评论区指出哦,非常感谢

代码实现

主要的代码内容都在创建数据集上

python 复制代码
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

np.random.seed(42)

def get_data():
    """这里使用ai帮忙生成一些数据"""
    n_samples = 200
    X0 = np.random.multivariate_normal(mean=[1, 1], cov=np.array([[1, 0.5], [0.5, 1]]), size=n_samples)  # 从二维正态分布,中获取数据,协方差矩阵为
    # [1, 0.5]
    # [0.5, 1]
    y0 = np.zeros(n_samples)

    # 类别1 (均值[4,4], 协方差矩阵)
    X1 = np.random.multivariate_normal(mean=[4, 4], cov=np.array([[1, -0.3], [-0.3, 1]]), size=n_samples)  # 与上面一样
    y1 = np.ones(n_samples)

    # 合并数据
    X = np.vstack((X0, X1))  # vstack相当于横向链接,将x0和x1的元素拼接成一行,一共有n_samples的数据点,每个数据点(x0, x1)
    y = np.hstack((y0, y1))  # hstack相当于拼接,在axis=0的时候,合并成一个向量
    return X, y

X, y = get_data()
X = (X - np.mean(X, axis=0)) / np.std(X, axis=0)  # 经典正态分布标准化
X = np.c_[np.ones(X.shape[0]), X]  # 将偏置的1设置在开头,一个数据点由(1, x0, x1)组成
weight = np.zeros(X.shape[1])  # 初始化所有weight为0,由[b, w1, w2]组成

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

def cul_j(X, theta, y):
    m = len(y)
    predictions = sigmoid(X @ theta)   # 这是预测的概率值,相当于f(x)
    error = predictions - y  # 计算误差
    gradient = (X.T @ error) / m  # 利用矩阵乘法,简化求和
    return gradient

def main(X, theta, y, epoch, lr):
    for i in range(epoch):
        theta = theta - lr * cul_j(X, theta, y)  # 梯度下降公式
    return theta

theta = main(X, weight, y, 500000, 0.01)
print(theta)

可视化

python 复制代码
def plot_decision_boundary(X, y, theta):
    x_f1_min, x_f1_max = X[:, 1].min() - 0.5, X[:, 1].max() + 0.5  # 设置坐标轴范围,方便显示,这是feature1的范围
    x_f2_min, x_f2_max = X[:, 2].min() - 0.5, X[:, 2].max() + 0.5  # 这是feature2的范围
    h = 0.02  # 设置mesh的步长,步长越小,分割的mesh越细,数据点越多
    x_f1_mesh, x_f2_mesh = np.meshgrid(np.arange(x_f1_min, x_f1_max, h), np.arange(x_f2_min, x_f2_max, h))
    # 将网格数据展平并组合成一个二维数组
    X_grid = np.c_[np.ones(x_f1_mesh.ravel().shape[0]),
                x_f1_mesh.ravel(),
                x_f2_mesh.ravel()]
    # ravel会将多维数组按顺序展平成一维数组
    Z = np.where(sigmoid(X_grid @ theta) > 0.5, 1, 0)  # 进行判断计算
    Z = Z.reshape(x_f1_mesh.shape)  # 将Z转换为X的形状

    plt.figure(figsize=(8, 6))
    plt.pcolormesh(x_f1_mesh, x_f2_mesh, Z, cmap=plt.cm.Paired, alpha=0.4)  # 利用这个函数,可以帮助绘制伪彩色分类图

    # 绘制真实的数据点
    plt.scatter(X[:, 1], X[:, 2], c=y, edgecolors='k', cmap=plt.cm.Paired)
    plt.xlabel('Feature 1')
    plt.ylabel('Feature 2')
    plt.xlim(x_f1_min, x_f1_max)
    plt.ylim(x_f2_min, x_f2_max)
    plt.xticks(())
    plt.yticks(())
    plt.show()

plot_decision_boundary(X, y, theta)

我们可以通过三维网格可视化梯度下降的路径

注意w1和w2为变量,此时将b固定为求解的实际值哦

python 复制代码
def cul_J(X, theta, y):
    predictions = sigmoid(X @ theta)   # 这是预测的概率值,相当于f(x)
    cost = (-y * np.log(predictions) - (1 - y) * np.log(1 - predictions)).mean()
    return cost  # 代价函数值

def gradient_down_3d(theta, costs, thetas):
    """theta是最终的参数,
    costs是成本列表,t
    hetas是参数变化路径"""
    # 创建网格数据
    start = 0; stop = 10  # 根据需求设置
    b = theta[0]
    w1_range = np.linspace(start, stop, 100)  # 所有的w1参数
    w2_range = np.linspace(start, stop, 100)  # 所有的w2参数
    W1, W2 = np.meshgrid(w1_range, w2_range)  # 组合出所有的w1,w2参数可能

    # 计算损失函数的网格值
    Z = np.zeros_like(W1)
    min_cost = float('inf')  # 设置无限值,接下来将不断更新这个最小值,也可以用np.min获得成本函数最小值, np.argmin定位对应参数组合
    min_w1 = 0
    min_w2 = 0
    for i in range(W1.shape[0]):
        for j in range(W1.shape[1]):
            theta_temp = np.array([b, W1[i, j], W2[i, j]])
            cost = cul_J(X, theta_temp, y)  # 计算代价函数
            Z[i, j] = cost  # 当前参数组合下的成本,进行记录
            if cost < min_cost:  # 更新最优参数组合
                min_cost = cost
                min_w1 = W1[i, j]
                min_w2 = W2[i, j]

    # 绘制三维图
    fig = plt.figure(figsize=(12, 8))
    ax = fig.add_subplot(111, projection='3d')  # 设置fig类型为3d
    # 绘制损失函数的表面
    ax.plot_surface(W1, W2, Z, cmap='viridis', alpha=0.7)  # 绘制这个曲面
    # 绘制梯度下降路径
    ax.plot(thetas[:, 1], thetas[:, 2], costs, 'r', label='梯度下降路径', linewidth=2)
    # 标注最小值
    ax.scatter(min_w1, min_w2, min_cost, c='g', s=100, marker='x', label='最小代价函数点')
    # 设置标签
    ax.set_xlabel('w1')
    ax.set_ylabel('w2')
    ax.set_zlabel('Cost')
    ax.legend()

    plt.show()
相关推荐
clownAdam2 小时前
通俗易懂的分类算法之K近邻详解
人工智能·算法·分类·数据挖掘·knn·k邻近
clownAdam8 小时前
通俗易懂的分类算法之支持向量机详解
算法·支持向量机·分类·数据挖掘
大霸王龙8 小时前
基于MATLAB与深度学习的医学图像分类系统开发全流程解析
深度学习·matlab·分类
Jason-河山12 小时前
如何利用数据分析优化库存策略
数据挖掘·数据分析
Python数据分析与机器学习12 小时前
《基于大数据的相州镇新农村商务数据分析与研究》开题报告
大数据·人工智能·python·算法·数据挖掘·数据分析
dundunmm13 小时前
【数据挖掘】Pandas之DataFrame
大数据·人工智能·机器学习·数据挖掘·pandas
青橘MATLAB学习13 小时前
基于深度学习的网络摄像头图像实时分类实践:从理论到完整实现
网络·图像处理·深度学习·matlab·分类
dundunmm14 小时前
数据挖掘与数据分析
人工智能·数据挖掘·数据分析
码界筑梦坊14 小时前
基于大数据的音乐网站数据分析与可视化推荐系统
大数据·python·信息可视化·数据挖掘·数据分析·毕业设计