1. 概述
逻辑回归(Logistic Regression)虽然名字中带有”回归”,但实际上是一种分类算法,主要用于二分类问题。它的核心思想是通过逻辑函数(sigmoid)将线性回归的输出映射到 区间,表示样本属于正类的概率。
1.1 与线性回归的区别
| 特征 | 线性回归 | 逻辑回归 |
|---|---|---|
| 任务类型 | 回归 | 分类 |
| 输出范围 | (概率) | |
| 损失函数 | 均方误差(MSE) | 交叉熵(Cross-Entropy) |
| 应用场景 | 预测连续值 | 预测类别概率 |
1.2 为什么需要逻辑函数?
线性回归的输出是实数范围,但分类问题需要 的概率值。sigmoid函数恰好完成了这个映射:
其函数图像呈 S 形曲线:
1.0 ┤ ╭──
│ ╭──╯
0.8 ┤ ╭──╯
│ ╭──╯
0.6 ┤ ╭──╯
│ ╭──╯
0.4 ┤ ╭──╯
│ ╭──╯
0.2 ┤ ╭──╯
│ ╭──╯
0 ┼──╯────────────────────
-4 -2 0 2 4
2. 作为广义线性模型的推导
2.1 广义线性模型(GLM)框架
逻辑回归是广义线性模型(Generalized Linear Model, GLM)的一个典型实例。GLM由三个组件构成:
- 概率分布:假设 服从指数族分布
- 线性预测器:
- 链接函数:,将均值 与线性预测器连接
2.2 从伯努利分布推导
设样本标签 ,则 服从伯努利分布:
将伯努利分布写成指数族形式:
对照指数族标准形式 :
- 自然参数:
- 对数归一化函数:
由此可得链接函数(logit link):
这就是 sigmoid 函数,也称为 logistic 函数。
2.3 模型假设
逻辑回归基于以下假设:
- 线性可分性假设:
- 条件独立假设(在某些推导中)
- 特征独立假设(与朴素贝叶斯不同)
3. 极大似然估计
3.1 似然函数
给定训练数据集 ,假设样本独立同分布,则似然函数为:
其中:
3.2 对数似然
取对数得到对数似然:
3.3 梯度推导
对 求偏导:
其中 ,利用了 sigmoid 的性质 。
4. 损失函数
4.1 二元交叉熵损失
逻辑回归的损失函数为二元交叉熵(Binary Cross-Entropy):
其中 是预测概率。
4.2 与均方误差的关系
如果使用均方误差(MSE)作为损失:
为什么不使用MSE?
- 梯度消失:当 接近 0 或 1 时,MSE 的梯度趋近于 0,学习缓慢
- 非凸优化:MSE 损失曲面可能存在多个局部极小值
- 概率解释:交叉熵来源于最大似然估计,具有概率解释
Cross-Entropy MSE
L(y,ŷ) L(y,ŷ)
│ │
0.7 ┤ ┼ │ ┼
│ ╲╱╲ │ ╲
0.4 ┤ ╲╱ ╲ │ ╲
│ ╲╱ ╲ │ ────────
0.1 ┤ ╲ ╲ │ ╲
└────────────── └──────────────
0.0 0.5 1.0 0.0 0.5 1.0
ŷ ŷ
4.3 梯度下降更新
使用梯度下降法更新参数:
或使用批量/小批量梯度下降。
5. 正则化
5.1 L2正则化(权重衰减)
在损失函数中加入 L2 惩罚项:
物理意义:L2 正则化使权重向量趋于零,但不会完全为零。这使得每个特征都对预测有贡献,但贡献较小。
5.2 L1正则化(稀疏解)
物理意义:L1 正则化产生稀疏解,使部分权重正好为零,从而实现特征选择。
5.3 Elastic Net(弹性网)
结合 L1 和 L2:
5.4 正则化参数选择
| 值 | 效果 |
|---|---|
| 无正则化,可能过拟合 | |
| 过大 | 权重趋近于零,欠拟合 |
| 适中 | 平衡偏差-方差权衡 |
6. 优化算法
6.1 梯度下降法
最简单的优化方法:
def gradient_descent(X, y, lr=0.01, n_iters=1000, lambda_reg=0.01):
n_samples, n_features = X.shape
w = np.zeros(n_features)
b = 0
for _ in range(n_iters):
z = X @ w + b
y_hat = sigmoid(z)
# 梯度计算(含L2正则化)
dw = (1/n_samples) * (X.T @ (y_hat - y)) + lambda_reg * w
db = (1/n_samples) * np.sum(y_hat - y)
w -= lr * dw
b -= lr * db
return w, b6.2 牛顿法(IRLS)
对于逻辑回归,可以使用二阶优化方法加速收敛。
参数更新公式:
其中 是 Hessian 矩阵:
这就是 IRLS(Iteratively Reweighted Least Squares) 算法。
6.3 拟牛顿法(BFGS/L-BFGS)
不需要显式计算 Hessian,适用于大规模问题。
6.4 不同优化算法对比
| 算法 | 收敛速度 | 计算复杂度 | 内存需求 | 适用场景 |
|---|---|---|---|---|
| 梯度下降 | 慢 | 大数据 | ||
| 牛顿法 | 快(二次收敛) | 小数据 | ||
| L-BFGS | 快 | 中等数据 |
7. 多分类扩展
7.1 One-vs-Rest (OvR)
训练 个二分类器,第 个分类器将第 类作为正类,其余作为负类。
预测时:选择所有分类器中输出概率最大的类别。
类别1 vs 其他 类别2 vs 其他 类别3 vs 其他
┌─┐ ┌─┐ ┌─┐
输入 ──┤ │── P(1|x) ──┤ │── P(2|x) ──┤ │── P(3|x)
└─┘ └─┘ └─┘
│ │ │
└────────┬────────┴────────┬─────────┘
▼
argmax(P(k|x))
7.2 与Softmax回归的关系
OvR 可以视为 softmax 回归的特殊情况。详见 Softmax回归。
8. 与神经网络的关系
8.1 单层神经网络视角
逻辑回归可以看作没有隐藏层的神经网络(即感知器的变体):
输入层 输出层
│
x₁ ──┬──┐ │
├──┤w₁├─┐
x₂ ──┤ │w₂├─┤ ┌─────────┐
├──┤w₃├─┼──┤ Sigmoid ├─── P(y=1|x)
x₃ ──┤ │ │ │ └─────────┘
└──┴──┘──┘
│
(偏置 b)
8.2 多层感知器的基础
在多层感知器(MLP)中:
- 逻辑回归常用作输出层,配合交叉熵损失
- Softmax 回归是逻辑回归在多分类上的推广
- 详见 多层感知机理论
9. 模型评估
9.1 分类指标
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
# 训练模型
model = LogisticRegression()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
# 计算指标
print(f"Accuracy: {accuracy_score(y_test, y_pred):.4f}")
print(f"Precision: {precision_score(y_test, y_pred):.4f}")
print(f"Recall: {recall_score(y_test, y_pred):.4f}")
print(f"F1 Score: {f1_score(y_test, y_pred):.4f}")9.2 ROC曲线与AUC
import matplotlib.pyplot as plt
from sklearn.metrics import roc_curve, auc, roc_auc_score
# 获取预测概率
y_prob = model.predict_proba(X_test)[:, 1]
# 计算ROC曲线
fpr, tpr, thresholds = roc_curve(y_test, y_prob)
roc_auc = auc(fpr, tpr)
# 绘制ROC曲线
plt.figure(figsize=(8, 6))
plt.plot(fpr, tpr, color='darkorange', lw=2, label=f'ROC curve (AUC = {roc_auc:.2f})')
plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--', label='Random')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver Operating Characteristic (ROC)')
plt.legend(loc='lower right')
plt.grid(True, alpha=0.3)
plt.show()9.3 概率校准
逻辑回归输出的概率需要进行校准,以确保预测概率反映真实概率。
from sklearn.calibration import CalibratedClassifierCV, calibration_curve
# 使用Platt缩放或等渗回归进行校准
calibrated_model = CalibratedClassifierCV(model, method='isotonic')
calibrated_model.fit(X_train, y_train)
# 绘制校准曲线
y_prob_calibrated = calibrated_model.predict_proba(X_test)[:, 1]
fraction_of_positives, mean_predicted_value = calibration_curve(y_test, y_prob_calibrated, n_bins=10)
plt.figure(figsize=(8, 6))
plt.plot([0, 1], [0, 1], 'k--', label='Perfectly calibrated')
plt.plot(mean_predicted_value, fraction_of_positives, 's-', label='Calibrated model')
plt.xlabel('Mean predicted probability')
plt.ylabel('Fraction of positives')
plt.legend()
plt.show()10. 完整代码实现
10.1 NumPy实现
import numpy as np
from typing import Tuple
class LogisticRegression:
"""逻辑回归分类器(支持L2正则化)"""
def __init__(self, lr: float = 0.01, n_iters: int = 1000,
lambda_reg: float = 0.01, tol: float = 1e-5):
self.lr = lr
self.n_iters = n_iters
self.lambda_reg = lambda_reg
self.tol = tol
self.w = None
self.b = None
def sigmoid(self, z: np.ndarray) -> np.ndarray:
"""Sigmoid激活函数,数值稳定版本"""
return np.where(z >= 0,
1 / (1 + np.exp(-z)),
np.exp(z) / (1 + np.exp(z)))
def fit(self, X: np.ndarray, y: np.ndarray) -> 'LogisticRegression':
"""训练模型"""
n_samples, n_features = X.shape
# 参数初始化
self.w = np.zeros(n_features)
self.b = 0
# 梯度下降
for i in range(self.n_iters):
z = X @ self.w + self.b
y_hat = self.sigmoid(z)
# 计算梯度(含L2正则化)
dw = (1/n_samples) * (X.T @ (y_hat - y)) + self.lambda_reg * self.w
db = (1/n_samples) * np.sum(y_hat - y)
# 参数更新
self.w -= self.lr * dw
self.b -= self.lr * db
# 收敛判断
if np.linalg.norm(dw) < self.tol:
print(f"Converged at iteration {i+1}")
break
return self
def predict_proba(self, X: np.ndarray) -> np.ndarray:
"""预测概率"""
z = X @ self.w + self.b
y_hat = self.sigmoid(z)
return np.column_stack([1 - y_hat, y_hat])
def predict(self, X: np.ndarray, threshold: float = 0.5) -> np.ndarray:
"""预测类别"""
return (self.predict_proba(X)[:, 1] >= threshold).astype(int)
# 示例使用
if __name__ == "__main__":
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
# 生成数据
X, y = make_classification(n_samples=1000, n_features=20, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
# 训练模型
model = LogisticRegression(lr=0.1, n_iters=500, lambda_reg=0.01)
model.fit(X_train, y_train)
# 预测
y_pred = model.predict(X_test)
y_prob = model.predict_proba(X_test)[:, 1]
print(f"Test Accuracy: {(y_pred == y_test).mean():.4f}")10.2 使用sklearn
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
# 加载数据
data = load_breast_cancer()
X, y = data.data, data.target
# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建管道(标准化 + 逻辑回归)
pipeline = Pipeline([
('scaler', StandardScaler()),
('clf', LogisticRegression(penalty='l2', C=1.0, solver='lbfgs', max_iter=1000))
])
# 训练
pipeline.fit(X_train, y_train)
# 评估
train_acc = pipeline.score(X_train, y_train)
test_acc = pipeline.score(X_test, y_test)
print(f"Train Accuracy: {train_acc:.4f}")
print(f"Test Accuracy: {test_acc:.4f}")
# 预测
y_pred = pipeline.predict(X_test)
y_prob = pipeline.predict_proba(X_test)[:, 1]11. 优缺点分析
优点
| 优点 | 说明 |
|---|---|
| 概率输出 | 可以输出样本属于各类别的概率 |
| 可解释性强 | 权重直接反映特征对分类的贡献 |
| 计算效率高 | 训练和预测的时间复杂度低 |
| 理论基础扎实 | 基于最大似然估计,有概率解释 |
| 不易过拟合 | 通过正则化可以有效控制模型复杂度 |
| 与神经网络兼容 | 可以视为单层神经网络 |
缺点
| 缺点 | 说明 |
|---|---|
| 线性决策边界 | 无法捕捉特征间的非线性关系 |
| 特征工程依赖 | 需要手工进行特征工程 |
| 多分类效率低 | OvR策略可能导致分类不平衡 |
| 对特征缩放敏感 | 需要特征标准化 |
| 特征共线性问题 | 高度相关特征会导致权重不稳定 |
12. 应用场景
12.1 经典应用
- 信用评分:预测用户是否会违约
- 广告点击率预测:预测用户是否会点击广告
- 医学诊断:预测病人是否患有某种疾病
- 邮件分类:判断邮件是否为垃圾邮件
12.2 在深度学习中的作用
- 作为激活函数:Sigmoid 是神经网络中的重要激活函数
- 作为损失函数:二元交叉熵是二分类问题的标准损失
- 作为输出层:用于需要概率输出的二分类任务
13. 与其他模型的关系
13.1 与SVM的关系
| 特征 | 逻辑回归 | SVM |
|---|---|---|
| 损失函数 | 交叉熵 | 合页损失(Hinge Loss) |
| 输出 | 概率 | 类别标签 |
| 决策边界 | 最大化似然 | 最大化间隔 |
| 正则化 | L1/L2 | 间隔最大化(隐式正则化) |
详见 SVM。
13.2 与朴素贝叶斯的关系
两者都是概率分类器,但假设不同:
- 逻辑回归:条件概率建模,直接估计
- 朴素贝叶斯:先验 + 似然,估计
详见 朴素贝叶斯。
13.3 与线性回归的关系
逻辑回归在线性回归的基础上:
- 添加了 sigmoid 变换
- 使用交叉熵损失替代均方误差
- 输出从连续值变为概率