逻辑回归从理论到实践:糖尿病预测案例详解
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 数学模型
给定特征向量 和权重向量 ,逻辑回归的假设函数为:
其中 是Sigmoid函数,将实数映射到(0,1)区间。
1.3 损失函数
逻辑回归使用交叉熵损失函数(Cross-Entropy Loss),对于单个样本 :
加上L2正则化项后的完整目标函数:
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 性能优化技巧
- 学习率调度:随着训练进行逐渐减小学习率
- 动量优化:加入动量项加速收敛
- 自适应学习率:使用Adam、RMSprop等自适应算法
- 早停策略:在验证集性能不再提升时停止训练
- 正则化选择:根据问题选择合适的正则化方式和强度
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 常见问题与解决方案
- 梯度消失:使用合适的激活函数和权重初始化
- 过拟合:增加正则化、使用Dropout、获取更多数据
- 收敛慢:调整学习率、使用动量优化
- 数值不稳定:特征标准化、梯度裁剪
7. 总结与展望
通过本教程,我们深入探讨了逻辑回归的理论基础、数学推导和实际实现。从糖尿病预测的具体案例出发,我们:
- 掌握了核心概念:理解了逻辑回归的数学模型和损失函数
- 实现了关键算法:亲手编写了梯度下降和随机梯度下降
- 完成了完整流程:从数据预处理到模型评估的全过程
- 进行了对比分析:比较了不同优化算法的性能特点
逻辑回归作为机器学习的基础算法,不仅在学术研究中具有重要意义,在实际工业应用中也广泛使用。掌握好逻辑回归为你学习更复杂的深度学习模型奠定了坚实的基础。
下一步学习建议:
- 探索多分类逻辑回归(Softmax回归)
- 学习正则化技术的不同变体(L1、Elastic Net)
- 了解梯度下降的各种优化算法(Adam、RMSprop)
- 尝试在不同的数据集上应用逻辑回归
记住,真正的掌握来自于实践。建议你下载代码,在自己的机器上运行,尝试调整参数,观察模型行为的变化,这样才能真正理解算法的工作原理。
点赞、收藏、关注三连,获取更多机器学习实战教程!下期我们将深入探讨神经网络的基础原理和实现。
登录后查看全文
热门项目推荐
相关项目推荐
kernelopenEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。C0131
let_datasetLET数据集 基于全尺寸人形机器人 Kuavo 4 Pro 采集,涵盖多场景、多类型操作的真实世界多任务数据。面向机器人操作、移动与交互任务,支持真实环境下的可扩展机器人学习00
mindquantumMindQuantum is a general software library supporting the development of applications for quantum computation.Python059
PaddleOCR-VLPaddleOCR-VL 是一款顶尖且资源高效的文档解析专用模型。其核心组件为 PaddleOCR-VL-0.9B,这是一款精简却功能强大的视觉语言模型(VLM)。该模型融合了 NaViT 风格的动态分辨率视觉编码器与 ERNIE-4.5-0.3B 语言模型,可实现精准的元素识别。Python00
GLM-4.7-FlashGLM-4.7-Flash 是一款 30B-A3B MoE 模型。作为 30B 级别中的佼佼者,GLM-4.7-Flash 为追求性能与效率平衡的轻量化部署提供了全新选择。Jinja00
AgentCPM-ReportAgentCPM-Report是由THUNLP、中国人民大学RUCBM和ModelBest联合开发的开源大语言模型智能体。它基于MiniCPM4.1 80亿参数基座模型构建,接收用户指令作为输入,可自主生成长篇报告。Python00
最新内容推荐
项目优选
收起
deepin linux kernel
C
27
11
OpenHarmony documentation | OpenHarmony开发者文档
Dockerfile
496
3.64 K
Ascend Extension for PyTorch
Python
300
338
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
307
131
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
868
479
暂无简介
Dart
744
180
React Native鸿蒙化仓库
JavaScript
297
346
Nop Platform 2.0是基于可逆计算理论实现的采用面向语言编程范式的新一代低代码开发平台,包含基于全新原理从零开始研发的GraphQL引擎、ORM引擎、工作流引擎、报表引擎、规则引擎、批处理引引擎等完整设计。nop-entropy是它的后端部分,采用java语言实现,可选择集成Spring框架或者Quarkus框架。中小企业可以免费商用
Java
11
1
🔥LeetCode solutions in any programming language | 多种编程语言实现 LeetCode、《剑指 Offer(第 2 版)》、《程序员面试金典(第 6 版)》题解
Java
66
20
仓颉编译器源码及 cjdb 调试工具。
C++
150
882