首页
/ 逻辑回归从理论到实践:糖尿病预测案例详解

逻辑回归从理论到实践:糖尿病预测案例详解

2026-01-23 05:22:38作者:昌雅子Ethen

还在为理解逻辑回归的数学原理而头疼?面对复杂的梯度计算和优化算法感到困惑?本文将通过一个完整的糖尿病预测案例,带你从零开始掌握逻辑回归的核心概念、数学推导和代码实现。

读完本文,你将获得:

  • 逻辑回归的完整数学推导和理解
  • 梯度下降和随机梯度下降的详细实现
  • 特征工程和模型评估的最佳实践
  • 完整的Python代码示例和可视化分析

1. 逻辑回归基础理论

1.1 什么是逻辑回归?

逻辑回归(Logistic Regression)是一种用于解决二分类问题的统计学习方法。尽管名称中包含"回归",但它实际上是一种分类算法,通过Sigmoid函数将线性回归的输出映射到(0,1)区间,表示样本属于正类的概率。

graph LR
A[输入特征] --> B[线性变换 z = wᵀx + b]
B --> C[Sigmoid函数 σ(z) = 1/(1+e⁻ᶻ)]
C --> D[概率输出 0-1]
D --> E[二分类决策]

1.2 数学模型

给定特征向量 xRdx \in \mathbb{R}^d 和权重向量 wRdw \in \mathbb{R}^d,逻辑回归的假设函数为:

hw(x)=σ(wTx)=11+ewTxh_w(x) = \sigma(w^T x) = \frac{1}{1 + e^{-w^T x}}

其中 σ(z)\sigma(z) 是Sigmoid函数,将实数映射到(0,1)区间。

1.3 损失函数

逻辑回归使用交叉熵损失函数(Cross-Entropy Loss),对于单个样本 (xi,yi)(x_i, y_i)

L(w)=[yilog(hw(xi))+(1yi)log(1hw(xi))]\mathcal{L}(w) = -[y_i \log(h_w(x_i)) + (1 - y_i) \log(1 - h_w(x_i))]

加上L2正则化项后的完整目标函数:

J(w)=1ni=1nLi(w)+λ2w22J(w) = \frac{1}{n} \sum_{i=1}^n \mathcal{L}_i(w) + \frac{\lambda}{2} \|w\|_2^2

2. 数据准备与预处理

2.1 数据集介绍

我们使用糖尿病数据集,这是一个经典的二分类数据集,包含768个样本,每个样本有8个特征:

特征名称 描述 类型
Pregnancies 怀孕次数 数值
Glucose 葡萄糖浓度 数值
BloodPressure 血压 数值
SkinThickness 皮肤厚度 数值
Insulin 胰岛素 数值
BMI 身体质量指数 数值
DiabetesPedigreeFunction 糖尿病谱系功能 数值
Age 年龄 数值
Outcome 是否患病(0/1) 标签

2.2 数据加载与分割

from sklearn import datasets
import numpy as np

# 加载数据
x_sparse, y = datasets.load_svmlight_file('diabetes')
x = x_sparse.todense()

print(f'特征矩阵形状: {x.shape}')
print(f'标签向量形状: {y.shape}')

# 数据分割(80%训练,20%测试)
n = x.shape[0]
n_train = int(np.ceil(n * 0.8))
n_test = n - n_train

rand_indices = np.random.permutation(n)
train_indices = rand_indices[0:n_train]
test_indices = rand_indices[n_train:n]

x_train = x[train_indices, :]
x_test = x[test_indices, :]
y_train = y[train_indices].reshape(n_train, 1)
y_test = y[test_indices].reshape(n_test, 1)

2.3 特征标准化

特征标准化是机器学习中的重要步骤,可以加速模型收敛并提高性能。

# 标准化处理
d = x_train.shape[1]
mu = np.mean(x_train, axis=0).reshape(1, d)
sig = np.std(x_train, axis=0).reshape(1, d)

# 训练集标准化
x_train = (x_train - mu) / sig

# 测试集使用相同的均值和标准差
x_test = (x_test - mu) / sig

# 添加偏置项
n_train, d = x_train.shape
x_train = np.concatenate((x_train, np.ones((n_train, 1))), axis=1)

n_test, d = x_test.shape
x_test = np.concatenate((x_test, np.ones((n_test, 1))), axis=1)

3. 核心算法实现

3.1 目标函数实现

def objective(w, x, y, lam):
    """
    计算逻辑回归目标函数值
    Parameters:
    w: d×1权重向量
    x: n×d特征矩阵  
    y: n×1标签向量
    lam: 正则化参数
    Returns:
    目标函数值
    """
    n, d = x.shape
    yx = np.multiply(y, x)  # n×d矩阵
    yxw = np.dot(yx, w)     # n×1矩阵
    vec1 = np.exp(-yxw)     # n×1矩阵
    vec2 = np.log(1 + vec1) # n×1矩阵
    loss = np.mean(vec2)    # 标量
    reg = lam / 2 * np.sum(w * w)  # 正则化项
    return loss + reg

3.2 梯度计算

def gradient(w, x, y, lam):
    """
    计算逻辑回归的梯度
    Parameters:
    w: d×1权重向量
    x: n×d特征矩阵
    y: n×1标签向量  
    lam: 正则化参数
    Returns:
    g: d×1梯度向量
    """
    n, d = x.shape
    yx = np.multiply(y, x)      # n×d矩阵
    yxw = np.dot(yx, w)         # n×1矩阵
    vec1 = np.exp(yxw)          # n×1矩阵
    vec2 = np.divide(yx, 1+vec1) # n×d矩阵
    vec3 = -np.mean(vec2, axis=0).reshape(d, 1)  # d×1矩阵
    g = vec3 + lam * w          # 加入正则化
    return g

3.3 批量梯度下降

def grad_descent(x, y, lam, stepsize, max_iter=100, w=None):
    """
    批量梯度下降算法
    Parameters:
    x: n×d特征矩阵
    y: n×1标签向量
    lam: 正则化参数
    stepsize: 学习率
    max_iter: 最大迭代次数
    w: 初始权重
    Returns:
    w: 优化后的权重
    objvals: 目标函数值记录
    """
    n, d = x.shape
    objvals = np.zeros(max_iter)
    if w is None:
        w = np.zeros((d, 1))  # 零初始化
    
    for t in range(max_iter):
        objval = objective(w, x, y, lam)
        objvals[t] = objval
        g = gradient(w, x, y, lam)
        w -= stepsize * g  # 权重更新
    
    return w, objvals

3.4 随机梯度下降

def stochastic_objective_gradient(w, xi, yi, lam):
    """
    计算单个样本的目标函数和梯度
    Parameters:
    w: d×1权重向量
    xi: 1×d特征向量
    yi: 标量标签
    lam: 正则化参数
    Returns:
    obj: 目标函数值
    g: 梯度向量
    """
    d = xi.shape[0]
    yx = yi * xi           # 1×d矩阵
    yxw = float(np.dot(yx, w))  # 标量
    
    # 计算目标函数
    loss = np.log(1 + np.exp(-yxw))
    reg = lam / 2 * np.sum(w * w)
    obj = loss + reg
    
    # 计算梯度
    g_loss = -yx.T / (1 + np.exp(yxw))
    g = g_loss + lam * w
    
    return obj, g

def sgd(x, y, lam, stepsize, max_epoch=100, w=None):
    """
    随机梯度下降算法
    Parameters:
    x: n×d特征矩阵
    y: n×1标签向量
    lam: 正则化参数
    stepsize: 学习率
    max_epoch: 最大迭代轮数
    w: 初始权重
    Returns:
    w: 优化后的权重
    objvals: 目标函数值记录
    """
    n, d = x.shape
    objvals = np.zeros(max_epoch)
    if w is None:
        w = np.zeros((d, 1))
    
    for t in range(max_epoch):
        # 随机打乱数据
        rand_indices = np.random.permutation(n)
        x_rand = x[rand_indices, :]
        y_rand = y[rand_indices, :]
        
        objval = 0
        for i in range(n):
            xi = x_rand[i, :]
            yi = float(y_rand[i, :])
            obj, g = stochastic_objective_gradient(w, xi, yi, lam)
            objval += obj
            w -= stepsize * g  # 每个样本更新一次
        
        stepsize *= 0.9  # 学习率衰减
        objval /= n
        objvals[t] = objval
    
    return w, objvals

4. 模型训练与评估

4.1 参数设置与训练

# 参数设置
lam = 1E-6       # 正则化参数
stepsize_gd = 1.0  # 梯度下降学习率
stepsize_sgd = 0.1 # 随机梯度下降学习率
max_iter = 100   # 最大迭代次数

# 初始化权重
d = x_train.shape[1]
w_initial = np.zeros((d, 1))

# 训练模型
print("开始批量梯度下降训练...")
w_gd, objvals_gd = grad_descent(x_train, y_train, lam, stepsize_gd, max_iter, w_initial.copy())

print("\n开始随机梯度下降训练...")
w_sgd, objvals_sgd = sgd(x_train, y_train, lam, stepsize_sgd, max_iter, w_initial.copy())

4.2 收敛性分析

import matplotlib.pyplot as plt

plt.figure(figsize=(12, 6))

# 绘制收敛曲线
plt.subplot(1, 2, 1)
plt.plot(range(len(objvals_gd)), objvals_gd, 'b-', linewidth=2, label='梯度下降')
plt.plot(range(len(objvals_sgd)), objvals_sgd, 'r-', linewidth=2, label='随机梯度下降')
plt.xlabel('迭代次数')
plt.ylabel('目标函数值')
plt.title('优化算法收敛曲线')
plt.legend()
plt.grid(True)

# 绘制对数尺度收敛曲线
plt.subplot(1, 2, 2)
plt.semilogy(range(len(objvals_gd)), objvals_gd - objvals_gd[-1], 'b-', linewidth=2, label='梯度下降')
plt.semilogy(range(len(objvals_sgd)), objvals_sgd - objvals_sgd[-1], 'r-', linewidth=2, label='随机梯度下降')
plt.xlabel('迭代次数')
plt.ylabel('目标函数值差值(对数尺度)')
plt.title('收敛速度比较(对数尺度)')
plt.legend()
plt.grid(True)

plt.tight_layout()
plt.show()

4.3 模型评估

def predict(w, x):
    """
    使用训练好的模型进行预测
    Parameters:
    w: 训练好的权重
    x: 特征矩阵
    Returns:
    predictions: 预测概率
    """
    return 1 / (1 + np.exp(-np.dot(x, w)))

def accuracy(y_true, y_pred, threshold=0.5):
    """
    计算分类准确率
    Parameters:
    y_true: 真实标签
    y_pred: 预测概率
    threshold: 分类阈值
    Returns:
    acc: 准确率
    """
    y_pred_binary = (y_pred >= threshold).astype(int)
    return np.mean(y_pred_binary == y_true)

# 在测试集上评估
y_pred_gd = predict(w_gd, x_test)
y_pred_sgd = predict(w_sgd, x_test)

acc_gd = accuracy(y_test, y_pred_gd)
acc_sgd = accuracy(y_test, y_pred_sgd)

print(f"梯度下降测试准确率: {acc_gd:.4f}")
print(f"随机梯度下降测试准确率: {acc_sgd:.4f}")

# 绘制ROC曲线
from sklearn.metrics import roc_curve, auc

fpr_gd, tpr_gd, _ = roc_curve(y_test, y_pred_gd)
fpr_sgd, tpr_sgd, _ = roc_curve(y_test, y_pred_sgd)

roc_auc_gd = auc(fpr_gd, tpr_gd)
roc_auc_sgd = auc(fpr_sgd, tpr_sgd)

plt.figure(figsize=(8, 6))
plt.plot(fpr_gd, tpr_gd, color='blue', lw=2, 
         label=f'梯度下降 (AUC = {roc_auc_gd:.3f})')
plt.plot(fpr_sgd, tpr_sgd, color='red', lw=2, 
         label=f'随机梯度下降 (AUC = {roc_auc_sgd:.3f})')
plt.plot([0, 1], [0, 1], color='gray', lw=1, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('假正率')
plt.ylabel('真正率')
plt.title('ROC曲线')
plt.legend(loc="lower right")
plt.grid(True)
plt.show()

5. 算法对比与分析

5.1 梯度下降 vs 随机梯度下降

特性 批量梯度下降 随机梯度下降
每次迭代计算量 O(nd) O(d)
收敛速度 慢但稳定 快但波动大
内存需求 需要存储所有数据 只需单个样本
适合场景 小数据集 大数据集
收敛性质 确定性收敛 随机性收敛

5.2 性能优化技巧

  1. 学习率调度:随着训练进行逐渐减小学习率
  2. 动量优化:加入动量项加速收敛
  3. 自适应学习率:使用Adam、RMSprop等自适应算法
  4. 早停策略:在验证集性能不再提升时停止训练
  5. 正则化选择:根据问题选择合适的正则化方式和强度

6. 实际应用建议

6.1 数据预处理最佳实践

flowchart TD
    A[原始数据] --> B[缺失值处理]
    B --> C[异常值检测]
    C --> D[特征编码]
    D --> E[特征缩放]
    E --> F[特征选择]
    F --> G[最终数据集]

6.2 模型调参指南

参数 推荐范围 调参建议
学习率 0.001-1.0 从较大值开始,逐渐减小
正则化参数λ 1e-6-1e-2 使用交叉验证选择
最大迭代次数 100-1000 根据收敛情况调整
批量大小 32-256 根据内存和性能权衡

6.3 常见问题与解决方案

  1. 梯度消失:使用合适的激活函数和权重初始化
  2. 过拟合:增加正则化、使用Dropout、获取更多数据
  3. 收敛慢:调整学习率、使用动量优化
  4. 数值不稳定:特征标准化、梯度裁剪

7. 总结与展望

通过本教程,我们深入探讨了逻辑回归的理论基础、数学推导和实际实现。从糖尿病预测的具体案例出发,我们:

  1. 掌握了核心概念:理解了逻辑回归的数学模型和损失函数
  2. 实现了关键算法:亲手编写了梯度下降和随机梯度下降
  3. 完成了完整流程:从数据预处理到模型评估的全过程
  4. 进行了对比分析:比较了不同优化算法的性能特点

逻辑回归作为机器学习的基础算法,不仅在学术研究中具有重要意义,在实际工业应用中也广泛使用。掌握好逻辑回归为你学习更复杂的深度学习模型奠定了坚实的基础。

下一步学习建议

  • 探索多分类逻辑回归(Softmax回归)
  • 学习正则化技术的不同变体(L1、Elastic Net)
  • 了解梯度下降的各种优化算法(Adam、RMSprop)
  • 尝试在不同的数据集上应用逻辑回归

记住,真正的掌握来自于实践。建议你下载代码,在自己的机器上运行,尝试调整参数,观察模型行为的变化,这样才能真正理解算法的工作原理。


点赞、收藏、关注三连,获取更多机器学习实战教程!下期我们将深入探讨神经网络的基础原理和实现。

登录后查看全文
热门项目推荐
相关项目推荐