逻辑回归(Logistic Regression)算法详解

一、逻辑回归:从线性回归到二分类的跨越

1.1 逻辑回归简介

逻辑回归(Logistic Regression)是机器学习中解决二分类问题的经典算法,尽管名称中包含"回归",但它本质上是一种分类方法。其核心思想是通过将线性回归的输出映射到(0,1)概率区间,从而实现分类预测。具体来说:

  • 利用线性模型 f ( x ) = w T x + b f(x) = w^T x + b f(x)=wTx+b 计算特征的线性组合
  • 通过Sigmoid函数将线性输出转换为概率值 P ( y = 1 ∣ x ) P(y=1|x) P(y=1∣x)
  • 设置概率阈值(如0.5)将概率转换为类别标签

逻辑回归广泛应用于医学诊断、金融风控、广告点击率预估等场景,其优势在于模型简单、可解释性强,且在小规模数据上表现优异。

  1. f ( x ) = w T x + b f(x) = w^T x + b f(x)=wTx+b 的数学推导

    线性模型 f ( x ) = w T x + b f(x) = w^T x + b f(x)=wTx+b 的推导源于概率论中的伯努利分布对数几率变换

  2. 什么是伯努利分布?
    伯努利分布是描述二元随机变量(只有两种可能结果)的最基本概率分布。在二分类问题中,样本标签 y ∈ { 0 , 1 } y \in \{0,1\} y{0,1} 正好满足:

    1. 结果互斥:每个样本只能属于一个类别
    2. 概率完备 P ( y = 1 ) + P ( y = 0 ) = 1 P(y=1) + P(y=0) = 1 P(y=1)+P(y=0)=1
    3. 形式简洁:单参数 p p p 完全定义整个分布

与经典概率分布(如正态分布)相比,伯努利分布:

  • 直接建模离散的二分类结果
  • 完美匹配分类问题的概率特性
  • 数学形式简单且可解释性强
  1. 伯努利分布 vs 经典概率求法
  • 经典概率求法(频率学派)

    在传统概率计算中,我们通过统计事件发生的频率来估计概率:
    p = 正类样本数 总样本数 p = \frac{\text{正类样本数}}{\text{总样本数}} p=总样本数正类样本数

    示例
    抛硬币10次,出现正面7次,则正面概率:
    p = 7 10 = 0.7 p = \frac{7}{10} = 0.7 p=107=0.7

  • 伯努利分布的本质

    伯努利分布 P ( y ) = p y ( 1 − p ) 1 − y P(y) = p^y(1-p)^{1-y} P(y)=py(1p)1y 是经典概率的数学抽象

    • y = 1 y=1 y=1 (正类): P ( 1 ) = p 1 ( 1 − p ) 0 = p P(1) = p^1(1-p)^0 = p P(1)=p1(1p)0=p
    • y = 0 y=0 y=0 (负类): P ( 0 ) = p 0 ( 1 − p ) 1 = 1 − p P(0) = p^0(1-p)^1 = 1-p P(0)=p0(1p)1=1p
  • 关键联系
    经典概率 k n \frac{k}{n} nk 正是伯努利分布在 n n n 次独立试验中正类出现次数 k k k 的期望值:
    E [ y ] = p = k n E[y] = p = \frac{k}{n} E[y]=p=nk

  • 对比分析

特性经典概率求法伯努利分布
表达形式统计比值 k n \frac{k}{n} nk参数化概率模型 p y ( 1 − p ) 1 − y p^y(1-p)^{1-y} py(1p)1y
计算基础依赖具体观测数据基于概率参数 p p p
预测能力只能描述已观测数据可预测未知样本概率
数学处理难以建立特征-概率的映射可连接特征与概率(如 p = σ ( w T x + b ) p=\sigma(w^Tx+b) p=σ(wTx+b))
  • 实际应用示例
    假设医学检测:
  • 100人中20人阳性 → 经典概率: p = 20 / 100 = 0.2 p=20/100=0.2 p=20/100=0.2
  • 伯努利分布建模:
    • P ( y = 1 ) = 0.2 P(y=1)=0.2 P(y=1)=0.2
    • P ( y = 0 ) = 0.8 P(y=0)=0.8 P(y=0)=0.8
    • 对新患者 x x x,可通过 p = σ ( w T x + b ) p=\sigma(w^Tx+b) p=σ(wTx+b) 预测患病概率

核心优势:伯努利分布将离散的频率统计转化为连续的概率模型,为建立特征与概率的数学关系奠定了基础,这是经典概率比无法实现的。

  1. 继续 f ( x ) = w T x + b f(x) = w^T x + b f(x)=wTx+b 的数学推导
    对于二分类问题, y y y 服从伯努利分布:
    P ( y ∣ x ) = p y ( 1 − p ) 1 − y P(y|x) = p^y(1-p)^{1-y} P(yx)=py(1p)1y
    其中 p = P ( y = 1 ∣ x ) p = P(y=1|x) p=P(y=1∣x) 是样本属于正类的概率。

  2. 对数几率变换
    为建立 p p p 与特征 x x x 的关系,定义对数几率
    logit ( p ) = ln ⁡ ( p 1 − p ) \text{logit}(p) = \ln \left( \frac{p}{1-p} \right) logit(p)=ln(1pp)

    • 该变换将概率 p ∈ [ 0 , 1 ] p \in [0,1] p[0,1] 映射到实数域 ( − ∞ , + ∞ ) (-\infty, +\infty) (,+)
  3. 关键假设
    逻辑回归的核心假设是:对数几率与特征呈线性关系
    ln ⁡ ( p 1 − p ) = w T x + b \ln \left( \frac{p}{1-p} \right) = w^T x + b ln(1pp)=wTx+b

  4. 代数求解
    通过代数变换求解 p p p
    p 1 − p = e w T x + b p = ( 1 − p ) e w T x + b p ( 1 + e w T x + b ) = e w T x + b p = e w T x + b 1 + e w T x + b = 1 1 + e − ( w T x + b ) \begin{align*} \frac{p}{1-p} &= e^{w^T x + b} \\ p &= (1-p)e^{w^T x + b} \\ p(1 + e^{w^T x + b}) &= e^{w^T x + b} \\ p &= \frac{e^{w^T x + b}}{1 + e^{w^T x + b}} \\ &= \frac{1}{1 + e^{-(w^T x + b)}} \end{align*} 1pppp(1+ewTx+b)p=ewTx+b=(1p)ewTx+b=ewTx+b=1+ewTx+bewTx+b=1+e(wTx+b)1

  5. 最终形式
    得到线性模型与Sigmoid函数的组合:
    P ( y = 1 ∣ x ) = σ ( w T x + b ) = 1 1 + e − ( w T x + b ) P(y=1|x) = \sigma(w^T x + b) = \frac{1}{1 + e^{-(w^T x + b)}} P(y=1∣x)=σ(wTx+b)=1+e(wTx+b)1
    其中:

    • w w w:权重向量,表示各特征的重要性
    • b b b:偏置项,表示决策边界的偏移
    • w T x = ∑ i = 1 n w i x i w^T x = \sum_{i=1}^n w_i x_i wTx=i=1nwixi:特征线性组合
  6. 关键数学关系

概念数学表达式取值范围解释
原始概率$p = P(y=1x)$ [ 0 , 1 ] [0, 1] [0,1]
几率 p 1 − p \frac{p}{1-p} 1pp [ 0 , + ∞ ) [0, +\infty) [0,+)正负类概率比
对数几率 ln ⁡ ( p 1 − p ) \ln\left(\frac{p}{1-p}\right) ln(1pp) ( − ∞ , + ∞ ) (-\infty, +\infty) (,+)几率的自然对数
线性模型 w T x + b w^T x + b wTx+b ( − ∞ , + ∞ ) (-\infty, +\infty) (,+)特征线性组合

1.2 Sigmoid函数:概率映射的数学本质

  1. 函数定义与几何意义

    Sigmoid函数是逻辑回归的核心,其数学表达式为:
    σ ( z ) = 1 1 + e − z \sigma(z) = \frac{1}{1 + e^{-z}} σ(z)=1+ez1

    • 符号解析
      • z z z:线性组合结果(为 z = w T x + b z = w^T x + b z=wTx+b);
      • e e e:自然对数底数(≈2.71828),负责将线性输出映射到指数空间。
        Sigmoid函数曲线(图1)
        图 1 图1 1

    Sigmoid函数曲线(图1) 可见:

    • z → + ∞ z \to +\infty z+ 时, e − z → 0 e^{-z} \to 0 ez0 σ ( z ) → 1 \sigma(z) \to 1 σ(z)1(正类概率趋近1);
    • z → − ∞ z \to -\infty z 时, e − z → + ∞ e^{-z} \to +\infty ez+ σ ( z ) → 0 \sigma(z) \to 0 σ(z)0(正类概率趋近0);
    • z = 0 z=0 z=0 时, σ ( z ) = 0.5 \sigma(z)=0.5 σ(z)=0.5,是二分类的天然决策阈值( σ ( z ) ≥ 0.5 \sigma(z) \geq 0.5 σ(z)0.5 预测为正类,反之为负类)。

1.3 参数 w w w b b b 对Sigmoid的调控

在这里插入图片描述
图 2 图2 2

  1. 权重 w w w 的影响

    w w w 控制Sigmoid曲线的陡峭程度(对 z z z 变化的敏感程度):

    • ∣ w ∣ |w| w 越大,曲线越陡峭(如 w = 5 w=5 w=5 时, z z z 微小变化即可让 σ ( z ) \sigma(z) σ(z) 从0跃升至1);
    • ∣ w ∣ |w| w 越小,曲线越平缓(如 w = 0.5 w=0.5 w=0.5 时, z z z 需大幅变化才会改变 σ ( z ) \sigma(z) σ(z))。
  2. 偏置 b b b 的影响

    b b b 控制Sigmoid曲线的左右平移(决策阈值的位置):

    • b > 0 b>0 b>0 时,曲线左移(更小的 z z z 就能让 σ ( z ) = 0.5 \sigma(z)=0.5 σ(z)=0.5);
    • b < 0 b<0 b<0 时,曲线右移(更大的 z z z 才能让 σ ( z ) = 0.5 \sigma(z)=0.5 σ(z)=0.5)。
  3. 权重符号的影响

    w w w 的正负决定Sigmoid曲线的倾斜方向

    • w > 0 w>0 w>0 时, σ ( z ) \sigma(z) σ(z) z z z 增大而递增(正相关);
    • w < 0 w<0 w<0 时, σ ( z ) \sigma(z) σ(z) z z z 增大而递减(负相关),需通过 b b b 调整决策逻辑。

1.4 从线性回归到分类

  1. 线性组合: z = w T x + b z = w^T x + b z=wTx+b

    逻辑回归首先计算 线性组合 z z z,继承线性回归的形式:
    z = w 1 x 1 + w 2 x 2 + ⋯ + w n x n + b z = w_1 x_1 + w_2 x_2 + \dots + w_n x_n + b z=w1x1+w2x2++wnxn+b

    • 符号解析
      • w = [ w 1 , w 2 , … , w n ] T w = [w_1, w_2, \dots, w_n]^T w=[w1,w2,,wn]T:权重向量,每个 w i w_i wi 表示特征 x i x_i xi 的“重要性”;
      • x = [ x 1 , x 2 , … , x n ] T x = [x_1, x_2, \dots, x_n]^T x=[x1,x2,,xn]T:样本的特征向量( n n n 为特征维度);
      • b b b:偏置项,代表“基准概率”(所有 x i = 0 x_i=0 xi=0 时的 z z z 值)。

在这里插入图片描述
图 3 图3 3

  1. 概率映射: P ( y = 1 ∣ x ) = σ ( z ) P(y=1|x) = \sigma(z) P(y=1∣x)=σ(z)(结合图3)

    通过Sigmoid函数,线性组合 z z z 被映射为 正类概率
    P ( y = 1 ∣ x ; w , b ) = σ ( w T x + b ) P(y=1|x; w, b) = \sigma(w^T x + b) P(y=1∣x;w,b)=σ(wTx+b)
    负类概率为:
    P ( y = 0 ∣ x ; w , b ) = 1 − σ ( w T x + b ) P(y=0|x; w, b) = 1 - \sigma(w^T x + b) P(y=0∣x;w,b)=1σ(wTx+b)

    合并表达式(全概率公式)
    P ( y ∣ x ; w , b ) = [ σ ( w T x + b ) ] y ⋅ [ 1 − σ ( w T x + b ) ] 1 − y P(y|x; w, b) = \left[\sigma(w^T x + b)\right]^y \cdot \left[1 - \sigma(w^T x + b)\right]^{1-y} P(yx;w,b)=[σ(wTx+b)]y[1σ(wTx+b)]1y

    • y = 1 y=1 y=1 时,公式退化为 σ ( w T x + b ) \sigma(w^T x + b) σ(wTx+b)(仅保留正类概率);
    • y = 0 y=0 y=0 时,公式退化为 1 − σ ( w T x + b ) 1 - \sigma(w^T x + b) 1σ(wTx+b)(仅保留负类概率)。

在这里插入图片描述
图 3 图3 3
在这里插入图片描述

图 4 图4 4

1.5 决策边界:从概率到类别(结合图3、图4)

σ ( z ) ≥ 0.5 \sigma(z) \geq 0.5 σ(z)0.5 时,预测 y = 1 y=1 y=1;否则预测 y = 0 y=0 y=0。此时决策边界满足:
w T x + b = 0 w^T x + b = 0 wTx+b=0

  • 一维特征(图3):决策边界是 x x x 的具体值(如 x = 0.67 x=0.67 x=0.67);
  • 二维特征(图4):决策边界是直线(如 w 1 x 1 + w 2 x 2 + b = 0 w_1 x_1 + w_2 x_2 + b = 0 w1x1+w2x2+b=0);
  • 高维特征:决策边界扩展为超平面,分割特征空间为两个区域。

绘图代码:

import numpy as np  # 导入NumPy库,用于数值计算
import matplotlib.pyplot as plt  # 导入Matplotlib绘图库
from matplotlib.colors import ListedColormap  # 导入颜色映射工具
from mpl_toolkits.mplot3d import Axes3D  # 导入3D绘图工具

# 设置中文字体,确保图表能正确显示中文
plt.rcParams["font.family"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False  


# 定义Sigmoid函数,数学公式为σ(z) = 1/(1+e^(-z))
def sigmoid(z):
    return 1 / (1 + np.exp(-z))


# 1. 绘制Sigmoid函数的基本曲线
def plot_sigmoid():
    z = np.linspace(-10, 10, 1000)  # 生成-10到10之间的1000个等距点作为输入
    sigma_z = sigmoid(z)  # 计算Sigmoid函数值

    plt.figure(figsize=(10, 6))  # 创建10x6英寸的画布
    plt.plot(z, sigma_z, linewidth=2.5)  # 绘制Sigmoid曲线,线宽2.5
    plt.axhline(y=0.5, color='r', linestyle='--', alpha=0.5)  # 添加y=0.5的红色虚线
    plt.axvline(x=0, color='gray', linestyle='--', alpha=0.5)  # 添加x=0的灰色虚线
    plt.title('Sigmoid函数曲线', fontsize=15)  # 设置标题
    plt.xlabel('z 值 (线性组合结果)', fontsize=12)  # 设置x轴标签
    plt.ylabel('σ(z) 值 (概率值)', fontsize=12)  # 设置y轴标签
    plt.grid(True, alpha=0.3)  # 添加网格线,透明度0.3

    # 填充z≥0区域(蓝色)和z<0区域(红色),突出概率大于/小于0.5的部分
    plt.fill_between(z, sigma_z, 0.5, where=(z >= 0), color='lightblue', alpha=0.3)
    plt.fill_between(z, sigma_z, 0.5, where=(z < 0), color='lightcoral', alpha=0.3)

    # 添加文本注释,说明概率大于/小于0.5的区域
    plt.text(3, 0.85, 'σ(z) > 0.5', fontsize=12)
    plt.text(-3, 0.15, 'σ(z) < 0.5', fontsize=12)

    plt.tight_layout()  # 自动调整布局
    plt.savefig('sigmoid_function.png', dpi=300)  # 保存图片
    plt.show()  # 显示图表


# 2. 绘制不同参数对Sigmoid函数的影响对比
def plot_sigmoid_with_different_params():
    z = np.linspace(-10, 10, 1000)  # 生成输入数据

    plt.figure(figsize=(12, 8))  # 创建12x8英寸的画布

    # 第一个子图:不同权重w对Sigmoid的影响
    plt.subplot(2, 2, 1)
    for w in [0.5, 1, 2, 5]:  # 遍历不同的权重值
        plt.plot(z, sigmoid(w * z), label=f'w={w}')  # 绘制不同w的曲线
    plt.title('不同权重 w 的影响', fontsize=13)  # 设置标题
    plt.xlabel('z', fontsize=10)  # 设置坐标轴标签
    plt.ylabel('σ(z)', fontsize=10)
    plt.legend()  # 显示图例
    plt.grid(True, alpha=0.3)  # 添加网格

    # 第二个子图:不同偏置b对Sigmoid的影响
    plt.subplot(2, 2, 2)
    for b in [-2, -1, 0, 1, 2]:  # 遍历不同的偏置值
        plt.plot(z, sigmoid(z + b), label=f'b={b}')  # 绘制不同b的曲线
    plt.title('不同偏置 b 的影响', fontsize=13)
    plt.xlabel('z', fontsize=10)
    plt.ylabel('σ(z)', fontsize=10)
    plt.legend()
    plt.grid(True, alpha=0.3)

    # 第三个子图:不同参数组合(w,b)的影响
    plt.subplot(2, 2, 3)
    params = [(1, 0), (2, 0), (1, -2), (2, 2)]  # 参数组合列表
    for w, b in params:  # 遍历参数组合
        plt.plot(z, sigmoid(w * z + b), label=f'w={w}, b={b}')  # 绘制曲线
    plt.title('不同参数组合的影响', fontsize=13)
    plt.xlabel('z', fontsize=10)
    plt.ylabel('σ(z)', fontsize=10)
    plt.legend()
    plt.grid(True, alpha=0.3)

    # 第四个子图:权重符号对Sigmoid的影响
    plt.subplot(2, 2, 4)
    for w in [1, -1, 2, -2]:  # 遍历正负权重
        plt.plot(z, sigmoid(w * z), label=f'w={w}')  # 绘制曲线
    plt.title('权重符号的影响', fontsize=13)
    plt.xlabel('z', fontsize=10)
    plt.ylabel('σ(z)', fontsize=10)
    plt.legend()
    plt.grid(True, alpha=0.3)

    plt.tight_layout()  # 调整布局
    plt.savefig('sigmoid_params_comparison.png', dpi=300)  # 保存图片
    plt.show()  # 显示图表


# 3. 绘制逻辑回归从线性组合到概率映射的完整过程
def plot_logistic_probability_mapping():
    np.random.seed(42)  # 设置随机种子,确保结果可复现
    x = np.linspace(-5, 5, 100)  # 生成输入特征x
    w = 1.5  # 权重
    b = -1  # 偏置
    z = w * x + b  # 线性组合z = wx + b
    prob = sigmoid(z)  # 计算属于正类的概率

    # 根据概率生成分类标签(概率>0.5为正类1,否则为负类0)
    y = (prob > 0.5).astype(int)

    # 添加噪声模拟真实数据
    noise = np.random.normal(0, 0.2, 100)  # 生成均值0、标准差0.2的噪声
    x_noise = x + noise  # 带噪声的特征
    prob_noise = sigmoid(w * x_noise + b)  # 带噪声的概率
    y_noise = (prob_noise > 0.5).astype(int)  # 带噪声的标签

    plt.figure(figsize=(12, 10))  # 创建画布

    # 第一子图:线性回归结果z = wx + b
    plt.subplot(2, 2, 1)
    # 绘制带噪声的数据点,颜色根据标签区分
    plt.scatter(x_noise, z, c=y_noise, cmap=ListedColormap(['#FF9999', '#99CCFF']),
                edgecolors='k', alpha=0.7)
    plt.plot(x, z, 'r-', linewidth=2)  # 绘制线性回归直线
    plt.axhline(y=0, color='gray', linestyle='--', alpha=0.5)  # 添加y=0的虚线
    plt.title('线性回归结果 (z = wx + b)', fontsize=13)
    plt.xlabel('输入特征 x', fontsize=10)
    plt.ylabel('线性组合结果 z', fontsize=10)
    plt.grid(True, alpha=0.3)

    # 第二子图:Sigmoid函数映射过程
    plt.subplot(2, 2, 2)
    # 绘制z到概率的映射关系,点颜色根据标签区分
    plt.scatter(z, prob_noise, c=y_noise, cmap=ListedColormap(['#FF9999', '#99CCFF']),
                edgecolors='k', alpha=0.7)
    plt.plot(z, prob, 'g-', linewidth=2)  # 绘制Sigmoid曲线
    plt.axhline(y=0.5, color='r', linestyle='--', alpha=0.5)  # 添加y=0.5虚线
    plt.axvline(x=0, color='gray', linestyle='--', alpha=0.5)  # 添加x=0虚线
    plt.title('Sigmoid函数映射', fontsize=13)
    plt.xlabel('线性组合结果 z', fontsize=10)
    plt.ylabel('概率值 P(y=1|x)', fontsize=10)
    plt.grid(True, alpha=0.3)

    # 第三子图:逻辑回归的最终分类结果
    plt.subplot(2, 2, 3)
    # 绘制特征x与预测概率的关系,点颜色根据标签区分
    plt.scatter(x_noise, y_noise, c=y_noise, cmap=ListedColormap(['#FF9999', '#99CCFF']),
                edgecolors='k', alpha=0.7, s=50)
    plt.plot(x, prob, 'g-', linewidth=2)  # 绘制概率曲线
    plt.axhline(y=0.5, color='r', linestyle='--', alpha=0.5)  # 添加决策阈值线
    plt.title('逻辑回归分类结果', fontsize=13)
    plt.xlabel('输入特征 x', fontsize=10)
    plt.ylabel('预测概率 P(y=1|x)', fontsize=10)
    plt.grid(True, alpha=0.3)

    # 第四子图:逻辑回归的决策边界
    plt.subplot(2, 2, 4)
    # 绘制特征x与标签y的关系,点颜色根据标签区分
    plt.scatter(x_noise, y_noise, c=y_noise, cmap=ListedColormap(['#FF9999', '#99CCFF']),
                edgecolors='k', alpha=0.7, s=50)
    plt.axhline(y=0.5, color='r', linestyle='--', alpha=0.5)  # 添加概率阈值线
    decision_boundary = -b / w  # 计算决策边界x值
    plt.axvline(x=decision_boundary, color='blue', linestyle='-', alpha=0.7)  # 绘制决策边界
    # 填充决策边界两侧的区域,区分分类结果
    plt.fill_between(x, 0, 1, where=(x > decision_boundary), color='#99CCFF', alpha=0.2)
    plt.fill_between(x, 0, 1, where=(x <= decision_boundary), color='#FF9999', alpha=0.2)
    plt.title(f'决策边界 (x = {decision_boundary:.2f})', fontsize=13)
    plt.xlabel('输入特征 x', fontsize=10)
    plt.ylabel('类别标签 y', fontsize=10)
    plt.grid(True, alpha=0.3)

    plt.tight_layout()  # 调整布局
    plt.savefig('logistic_regression_mapping.png', dpi=300)  # 保存图片
    plt.show()  # 显示图表


# 4. 绘制二维特征空间中的逻辑回归决策面
def plot_3d_decision_boundary():
    np.random.seed(42)  # 设置随机种子
    x1 = np.linspace(-5, 5, 50)  # 生成特征x1
    x2 = np.linspace(-5, 5, 50)  # 生成特征x2
    x1, x2 = np.meshgrid(x1, x2)  # 生成二维网格点

    w1, w2, b = 1, 2, -3  # 设置权重和偏置

    # 计算线性组合z = w1x1 + w2x2 + b和对应的概率
    z = w1 * x1 + w2 * x2 + b
    prob = sigmoid(z)

    fig = plt.figure(figsize=(12, 10))  # 创建画布

    # 第一子图:3D决策面
    ax1 = fig.add_subplot(221, projection='3d')  # 创建3D子图
    # 绘制3D曲面,颜色映射为viridis,透明度0.8
    surf = ax1.plot_surface(x1, x2, prob, cmap='viridis', alpha=0.8)
    # 在3D曲面上绘制z=0.5的等高线(决策边界)
    ax1.contour(x1, x2, prob, levels=[0.5], colors='r', linestyles='dashed', linewidths=2)
    ax1.set_title('逻辑回归决策面', fontsize=13)  # 设置标题
    ax1.set_xlabel('特征 x1', fontsize=10)  # 设置坐标轴标签
    ax1.set_ylabel('特征 x2', fontsize=10)
    ax1.set_zlabel('P(y=1|x1,x2)', fontsize=10)
    ax1.view_init(elev=30, azim=45)  # 设置3D视图角度
    fig.colorbar(surf, ax=ax1, shrink=0.5, aspect=5)  # 添加颜色条

    # 第二子图:决策边界等高线图
    ax2 = fig.add_subplot(222)  # 创建子图
    # 绘制概率的填充等高线图,20个层级,颜色映射viridis
    contour = ax2.contourf(x1, x2, prob, levels=20, cmap='viridis', alpha=0.8)
    # 绘制概率=0.5的等高线(决策边界)
    ax2.contour(x1, x2, prob, levels=[0.5], colors='r', linestyles='dashed', linewidths=2)
    ax2.set_title('决策边界等高线图', fontsize=13)
    ax2.set_xlabel('特征 x1', fontsize=10)
    ax2.set_ylabel('特征 x2', fontsize=10)
    fig.colorbar(contour, ax=ax2, shrink=0.5, aspect=5)  # 添加颜色条

    # 生成随机样本点
    n_samples = 100  # 样本数量
    x1_samples = np.random.uniform(-5, 5, n_samples)  # 随机生成x1
    x2_samples = np.random.uniform(-5, 5, n_samples)  # 随机生成x2
    z_samples = w1 * x1_samples + w2 * x2_samples + b  # 计算线性组合
    prob_samples = sigmoid(z_samples)  # 计算概率
    y_samples = (prob_samples > 0.5).astype(int)  # 生成标签

    # 第三子图:带样本点的决策边界
    ax3 = fig.add_subplot(223)  # 创建子图
    # 绘制概率的填充等高线图
    contour = ax3.contourf(x1, x2, prob, levels=20, cmap='viridis', alpha=0.6)
    # 绘制决策边界
    ax3.contour(x1, x2, prob, levels=[0.5], colors='r', linestyles='dashed', linewidths=2)
    # 绘制样本点,颜色根据标签区分
    scatter = ax3.scatter(x1_samples, x2_samples, c=y_samples,
                          cmap=ListedColormap(['#FF9999', '#99CCFF']),
                          edgecolors='k', alpha=0.8, s=50)
    ax3.set_title('带样本点的决策边界', fontsize=13)
    ax3.set_xlabel('特征 x1', fontsize=10)
    ax3.set_ylabel('特征 x2', fontsize=10)
    # 添加类别图例
    legend1 = ax3.legend(*scatter.legend_elements(), title="类别")
    ax3.add_artist(legend1)
    fig.colorbar(contour, ax=ax3, shrink=0.5, aspect=5)  # 添加颜色条

    # 第四子图:概率分布热图
    ax4 = fig.add_subplot(224)  # 创建子图
    # 绘制概率热图,设置范围和颜色映射
    im = ax4.imshow(prob, extent=[-5, 5, -5, 5], origin='lower',
                    cmap='viridis', aspect='auto')
    # 绘制决策边界
    ax4.contour(x1, x2, prob, levels=[0.5], colors='r', linestyles='dashed', linewidths=2)
    ax4.set_title('概率分布热图', fontsize=13)
    ax4.set_xlabel('特征 x1', fontsize=10)
    ax4.set_ylabel('特征 x2', fontsize=10)
    fig.colorbar(im, ax=ax4, shrink=0.5, aspect=5)  # 添加颜色条

    plt.tight_layout()  # 调整布局
    plt.savefig('3d_decision_boundary.png', dpi=300)  # 保存图片
    plt.show()  # 显示图表


# 5. 绘制逻辑回归的对数损失函数
def plot_logistic_loss():
    # 定义对数损失函数
    def log_loss(y_true, y_pred):
        epsilon = 1e-15  # 防止对数计算中出现0或1,导致数值溢出
        y_pred = np.clip(y_pred, epsilon, 1 - epsilon)  # 限制预测概率范围
        # 对数损失公式:- [y_true*log(y_pred) + (1-y_true)*log(1-y_pred)]
        return -(y_true * np.log(y_pred) + (1 - y_true) * np.log(1 - y_pred))

    y_pred = np.linspace(0.01, 0.99, 100)  # 生成0.01到0.99的100个预测概率值

    plt.figure(figsize=(10, 6))  # 创建画布

    # 绘制真实标签为1时的损失曲线
    plt.plot(y_pred, log_loss(1, y_pred), label='y=1 (正类)')
    # 绘制真实标签为0时的损失曲线
    plt.plot(y_pred, log_loss(0, y_pred), label='y=0 (负类)')

    plt.title('逻辑回归的对数损失函数', fontsize=15)  # 设置标题
    plt.xlabel('预测概率 P(y=1|x)', fontsize=12)  # 设置坐标轴标签
    plt.ylabel('损失值', fontsize=12)
    plt.grid(True, alpha=0.3)  # 添加网格
    plt.legend(fontsize=12)  # 显示图例

    # 添加注释,说明预测正确和错误时的损失情况
    plt.annotate('预测正确时损失小', xy=(0.95, log_loss(1, 0.95)), xytext=(0.7, 0.5),
                 arrowprops=dict(facecolor='black', shrink=0.05, width=1.5, headwidth=8))
    plt.annotate('预测错误时损失大', xy=(0.05, log_loss(1, 0.05)), xytext=(0.3, 3),
                 arrowprops=dict(facecolor='black', shrink=0.05, width=1.5, headwidth=8))

    plt.tight_layout()  # 调整布局
    plt.savefig('logistic_loss_function.png', dpi=300)  # 保存图片
    plt.show()  # 显示图表


# 主程序:依次调用所有绘图函数
if __name__ == "__main__":
    plot_sigmoid()  # 绘制Sigmoid函数基本曲线
    plot_sigmoid_with_different_params()  # 绘制不同参数的Sigmoid对比
    plot_logistic_probability_mapping()  # 绘制逻辑回归概率映射
    plot_3d_decision_boundary()  # 绘制二维特征的决策面
    plot_logistic_loss()  # 绘制对数损失函数

二、似然函数与交叉熵损失:从概率建模到参数优化的数学桥梁

2.1 似然函数:基于伯努利分布的联合概率建模

过渡衔接:在通过伯努利分布与对数几率变换建立特征-概率映射后,如何求解最优参数 ( w , b ) (w, b) (w,b)?这需要从样本的联合概率分布出发,构建优化目标函数。

在逻辑回归中,样本标签 y i y_i yi 服从伯努利分布,单个样本的概率为:
P ( y i ∣ x i ; w , b ) = [ σ ( w T x i + b ) ] y i [ 1 − σ ( w T x i + b ) ] 1 − y i P(y_i|x_i; w, b) = \left[\sigma(w^T x_i + b)\right]^{y_i} \left[1 - \sigma(w^T x_i + b)\right]^{1-y_i} P(yixi;w,b)=[σ(wTxi+b)]yi[1σ(wTxi+b)]1yi
m m m 个样本独立同分布,则联合似然函数为所有样本概率的乘积:
L ( w , b ) = ∏ i = 1 m P ( y i ∣ x i ; w , b ) = ∏ i = 1 m [ σ ( z i ) ] y i [ 1 − σ ( z i ) ] 1 − y i L(w, b) = \prod_{i=1}^{m} P(y_i|x_i; w, b) = \prod_{i=1}^{m} \left[\sigma(z_i)\right]^{y_i} \left[1 - \sigma(z_i)\right]^{1-y_i} L(w,b)=i=1mP(yixi;w,b)=i=1m[σ(zi)]yi[1σ(zi)]1yi

  • 符号说明
    • z i = w T x i + b z_i = w^T x_i + b zi=wTxi+b
    • y i ∈ { 0 , 1 } y_i \in \{0, 1\} yi{0,1} 为第 i i i 个样本的真实标签;
    • ∏ \prod 为连乘符号,体现独立事件联合概率的计算逻辑。

核心目标:寻找参数 ( w , b ) (w, b) (w,b) 使得 L ( w , b ) L(w, b) L(w,b) 最大,即让观测数据出现的概率最大化(与1.4节伯努利分布的概率建模逻辑连贯)。

2.2 对数似然:从连乘到连加的数学变换

直接优化连乘式计算复杂,利用对数函数性质 ln ⁡ ( ∏ f i ) = ∑ ln ⁡ ( f i ) \ln(\prod f_i) = \sum \ln(f_i) ln(fi)=ln(fi) 转换为对数似然函数
ln ⁡ L ( w , b ) = ∑ i = 1 m [ y i ln ⁡ σ ( z i ) + ( 1 − y i ) ln ⁡ ( 1 − σ ( z i ) ) ] \ln L(w, b) = \sum_{i=1}^{m} \left[ y_i \ln \sigma(z_i) + (1-y_i) \ln (1 - \sigma(z_i)) \right] lnL(w,b)=i=1m[yilnσ(zi)+(1yi)ln(1σ(zi))]

  • 详细推导步骤
    1. 对似然函数取自然对数: ln ⁡ L ( w , b ) = ln ⁡ ( ∏ i = 1 m P ( y i ∣ x i ) ) \ln L(w, b) = \ln \left( \prod_{i=1}^{m} P(y_i|x_i) \right) lnL(w,b)=ln(i=1mP(yixi)),其中 P ( y i ∣ x i ) P(y_i|x_i) P(yixi) 为单个样本概率;
    2. 利用对数乘法性质展开: ln ⁡ L ( w , b ) = ∑ i = 1 m ln ⁡ P ( y i ∣ x i ) \ln L(w, b) = \sum_{i=1}^{m} \ln P(y_i|x_i) lnL(w,b)=i=1mlnP(yixi)
    3. 代入伯努利分布概率表达式:
      ln ⁡ P ( y i ∣ x i ) = ln ⁡ { [ σ ( z i ) ] y i [ 1 − σ ( z i ) ] 1 − y i } = y i ln ⁡ σ ( z i ) + ( 1 − y i ) ln ⁡ ( 1 − σ ( z i ) ) \ln P(y_i|x_i) = \ln \left\{ \left[\sigma(z_i)\right]^{y_i} \left[1 - \sigma(z_i)\right]^{1-y_i} \right\} = y_i \ln \sigma(z_i) + (1-y_i) \ln (1 - \sigma(z_i)) lnP(yixi)=ln{[σ(zi)]yi[1σ(zi)]1yi}=yilnσ(zi)+(1yi)ln(1σ(zi))

2.3 交叉熵损失:从最大化到最小化的目标转换

为将“最大化对数似然”转化为机器学习中常见的损失函数最小化问题,定义:
L o s s ( w , b ) = − ln ⁡ L ( w , b ) = − ∑ i = 1 m [ y i ln ⁡ σ ( z i ) + ( 1 − y i ) ln ⁡ ( 1 − σ ( z i ) ) ] Loss(w, b) = -\ln L(w, b) = -\sum_{i=1}^{m} \left[ y_i \ln \sigma(z_i) + (1-y_i) \ln (1 - \sigma(z_i)) \right] Loss(w,b)=lnL(w,b)=i=1m[yilnσ(zi)+(1yi)ln(1σ(zi))]

  • 信息论视角

    交叉熵 H ( y , y ^ ) = − ∑ i = 1 m [ y i ln ⁡ y ^ i + ( 1 − y i ) ln ⁡ ( 1 − y ^ i ) ] H(y, \hat{y}) = -\sum_{i=1}^{m} \left[ y_i \ln \hat{y}_i + (1-y_i) \ln (1 - \hat{y}_i) \right] H(y,y^)=i=1m[yilny^i+(1yi)ln(1y^i)] 衡量真实分布 y y y 与预测分布 y ^ \hat{y} y^ 的差异,当 y ^ i = σ ( z i ) \hat{y}_i = \sigma(z_i) y^i=σ(zi) 时, L o s s Loss Loss 即为交叉熵,直接量化1.4节中“概率映射准确性”的损失。

  • 几何意义
    • 当预测概率 σ ( z i ) \sigma(z_i) σ(zi) 与真实标签 y i y_i yi 一致时(如 y i = 1 y_i=1 yi=1 σ ( z i ) → 1 \sigma(z_i)\to1 σ(zi)1), L o s s → 0 Loss \to 0 Loss0
    • 当预测相反时(如 y i = 1 y_i=1 yi=1 σ ( z i ) → 0 \sigma(z_i)\to0 σ(zi)0)。

2.4 等价性证明:最大化似然 ≡ 最小化交叉熵

从数学变换看:
arg ⁡ max ⁡ w , b L ( w , b ) ⇔ arg ⁡ max ⁡ w , b ln ⁡ L ( w , b ) ⇔ arg ⁡ min ⁡ w , b L o s s ( w , b ) \arg\max_{w,b} L(w,b) \quad \Leftrightarrow \quad \arg\max_{w,b} \ln L(w,b) \quad \Leftrightarrow \quad \arg\min_{w,b} Loss(w,b) argw,bmaxL(w,b)argw,bmaxlnL(w,b)argw,bminLoss(w,b)
三者本质是同一优化问题的不同表达,核心是 对数函数的单调性极值方向的反转(取负号)。

三、sklearn 实现逻辑回归:从 API 到实战应用

3.1 sklearn逻辑回归API详解

核心类与参数说明

from sklearn.linear_model import LogisticRegression
  1. 主要参数:

    • solver:优化算法选择

      • liblinear:适用于小数据集,支持L1/L2正则化
      • sag/saga:适用于大数据集,支持增量学习
      • lbfgs:拟牛顿法,收敛速度快,默认选项
    • penalty:正则化类型

      • l1:L1正则化(Lasso),可产生稀疏解
      • l2:L2正则化(Ridge),默认选项,防止过拟合
    • C:正则化强度的倒数,值越小惩罚越严厉,默认值为1.0

    • class_weight:类别不平衡处理

      • balanced:自动调整权重,适用于正负样本比例悬殊场景
      • 字典形式:如 {0:1, 1:10} 表示正类权重为负类的10倍

3.2 模型训练与预测流程

数据集:电信客户流失数据集
官方数据集下载地址:下载链接
百度网盘下载地址:下载链接 提取码: pujh
将数据集导入项目根目录即可

  1. 工具准备:导入核心库
    pandas 处理表格数据(读文件、列操作),numpy 支持数值计算;
    matplotlib+seaborn 画图表(看数据分布、模型结果);
    sklearn 模块分工:train_test_split 分训练 / 测试集,MinMaxScaler 归一化特征,LogisticRegression 建模型,classification_report/roc_auc_score 评估效果。
    中文字体设置:解决图表中文乱码、负号异常问题,让结果更直观。

  2. 数据加载与初检
    pd.read_csv('churn.csv') 读数据,info() 看 列名、数据类型、缺失值(本案例无缺失,简化处理)。

  3. 数据预处理:让模型 “读懂” 数据
    独热编码(get_dummies):把 “性别”“合同类型” 等字符串转成 0/1 数值(模型只能处理数值),drop_first=True 避免 多重共线性(如 “性别” 只留 “男” 列,女则为 0)。
    列重命名:把编码后的机器名(如 gender_Male)改成中文(如 性别),方便分析。
    拆分特征与目标:data_x 存客户属性 / 服务 / 费用(特征),data_y 存 “是否流失”(目标)。

  4. 可视化:发现数据规律
    sns.countplot 画 流失分布,发现 未流失客户远多于流失客户(数据不平衡)→ 后续评估需重点看 流失类的召回率(别漏判流失客户)。

  5. 数据分割:训练 vs 测试
    train_test_split 按 8:2 拆分,random_state=44 固定随机种子(结果可复现)。

  6. 特征工程:归一化
    MinMaxScaler 把特征缩到 [0,1] 范围(如 “月费” 10→100、“总费用” 100→1000,缩放后统一尺度)。
    训练集 fit_transform(先学规则再转换),测试集 transform(复用规则,避免 “作弊”)→ 逻辑回归对特征尺度敏感,归一化加速模型收敛。

  7. 模型训练:逻辑回归
    LogisticRegression(max_iter=1000):设最大迭代次数 1000(避免默认次数不足导致不收敛),用训练集 fit 学规律(特征→流失的关系)。
    归一化的介绍网页链接

  8. 运行效果

    精确率:0.8020
    AUC得分:0.8331
    分类报告:

           precision    recall  f1-score   support
    
    False       0.84      0.91      0.87      1027
    True       0.68      0.52      0.59       382
    accuracy                           0.80      1409
    macro avg       0.76      0.71      0.73      1409
    weighted avg       0.79      0.80      0.79      1409
    

在这里插入图片描述
在这里插入图片描述

3.3程序代码

import pandas as pd                # 导入Pandas库用于数据处理
import numpy as np                 # 导入NumPy库用于数值计算
import matplotlib.pyplot as plt    # 导入Matplotlib用于数据可视化
import seaborn as sns              # 导入Seaborn用于高级数据可视化
from sklearn.preprocessing import MinMaxScaler  # 导入特征缩放工具
from sklearn.linear_model import LogisticRegression  # 导入逻辑回归模型
from sklearn.metrics import classification_report, roc_auc_score  # 导入评估指标
from sklearn.model_selection import train_test_split  # 导入数据分割工具

# 设置中文字体支持
plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置中文字体,确保中文能正常显示
plt.rcParams['axes.unicode_minus'] = False  # 确保负号能正常显示

# 1.加载数据
base_data = pd.read_csv('churn.csv')  # 从CSV文件读取数据
print("数据基本信息:")
base_data.info()  # 查看数据的基本信息,包括列名、数据类型和缺失值情况

# 2.数据预处理
# 2.1 将字符串转变成数值(独热编码),并重命名列
data = pd.get_dummies(base_data, drop_first=True)  # 将分类特征转换为数值特征,使用drop_first避免多重共线性
data.rename(
    columns={
        'gender_Male': '性别', 'Partner_att': '配偶状态', 'Dependents_att': '受抚养人状态',
        'landline': '固定电话',
        'internet_att': '互联网服务', 'internet_other': '其他互联网服务', 'StreamingTV': '电视流媒体服务',
        'StreamingMovies': '电影流媒体服务',
        'Contract_Month': '月付合同', 'Contract_1YR': '一年期合同', 'PaymentBank': '银行支付',
        'PaymentCreditcard': '信用卡支付',
        'PaymentElectronic': '电子支付', 'MonthlyCharges': '月费', 'TotalCharges': '总费用'
    },
    inplace=True  # 原地修改列名
)

# 2.2 数据分割(特征集和目标集)
data['客户流失'] = data['Churn_Yes']  # 创建目标变量列
data.drop(['Churn_Yes'], axis=1, inplace=True)  # 删除原始目标变量列
data_x = data.iloc[:, :-1]  # 提取特征集(所有列除了最后一列)
data_y = data.iloc[:, -1]   # 提取目标集(最后一列)

# 2.3 数据展示 - 添加可视化:客户流失分布情况
plt.figure(figsize=(10, 6))  # 设置图表大小
sns.countplot(x='客户流失', data=data)  # 绘制客户流失分布柱状图
plt.title('客户流失分布情况')  # 设置图表标题
plt.savefig('churn_distribution.png')  # 保存图表为图片
plt.show()  # 显示图表

# 3.数据分割:将数据分为训练集和测试集
x_train, x_test, y_train, y_test = train_test_split(
    data_x, data_y, test_size=0.2, random_state=44  # 测试集占比20%,设置随机种子确保结果可复现
)

# 4.特征工程:使用Min-Max缩放对特征进行归一化
ss = MinMaxScaler()  # 初始化MinMaxScaler
nx_train = ss.fit_transform(x_train)  # 对训练集进行缩放并学习缩放参数
nx_test = ss.transform(x_test)  # 使用训练集学习的参数对测试集进行缩放

# 5.模型创建与训练
lr = LogisticRegression(max_iter=1000)  # 初始化逻辑回归模型,设置最大迭代次数为1000
lr.fit(nx_train, y_train)  # 使用训练数据训练模型

# 6.模型预测
pred_y = lr.predict(nx_test)  # 预测测试集的分类标签
pred_proba = lr.predict_proba(nx_test)[:, 1]  # 获取测试集样本属于正类的概率

# 7.模型评估
print(f"\n精确率:{lr.score(nx_test, y_test):.4f}")  # 计算并打印模型准确率
print(f"AUC得分:{roc_auc_score(y_test, pred_proba):.4f}")  # 计算并打印AUC值
print("\n分类报告:")
print(classification_report(y_test, pred_y))  # 打印分类报告,包含精确率、召回率、F1分数等指标

# 8.特征重要性分析
plt.figure(figsize=(12, 8))  # 设置图表大小
# 创建特征重要性DataFrame,使用系数的绝对值作为重要性指标
importance = pd.DataFrame({
    '特征': data_x.columns,
    '重要性': np.abs(lr.coef_[0])  # 获取逻辑回归模型的系数绝对值
}).sort_values('重要性', ascending=False)  # 按重要性降序排序

# 只展示前10个重要特征
sns.barplot(x='重要性', y='特征', data=importance.head(10))  # 绘制特征重要性条形图
plt.title('Top 10特征重要性')  # 设置图表标题
plt.tight_layout()  # 自动调整布局
plt.savefig('feature_importance.png')  # 保存图表
plt.show()  # 显示图表
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值