启程即是少年
Published on 2025-12-07 / 3 Visits
0
0

「机器学习三」逻辑回归

逻辑回归(Logistic Regression)原理与实现详解

逻辑回归是机器学习中最基础、最常用的分类算法之一。尽管名字中带有“回归”,但它解决的是分类问题,尤其适用于二分类任务。本文将从背景动机出发,系统讲解其核心原理、数学推导,并提供从零实现与 scikit-learn 调用的完整示例。

一、为什么需要逻辑回归?

线性回归擅长预测连续值(如房价、温度),但无法直接用于分类任务。例如:

  • 判断邮件是否为垃圾邮件(0 或 1)
  • 预测肿瘤是否为恶性(良性/恶性)

若强行使用线性回归:

  • 输出可能小于 0 或大于 1,无法解释为“概率”
  • 对异常值敏感,决策边界不稳定

逻辑回归通过引入 Sigmoid 函数,将线性输出映射到 ​(0,1) 区间,使其可自然解释为样本属于正类的概率,从而完美衔接回归思想与分类任务。

二、模型原理

给定输入特征向量 ​\mathbf{x} = [x_1, x_2, \dots, x_n]^T,逻辑回归首先计算线性组合:

z = \mathbf{w}^T \mathbf{x} + b

其中 ​\mathbf{w} 为权重向量,​b 为偏置项。

随后,通过 Sigmoid 函数(又称 Logistic 函数)进行非线性变换:

\sigma(z) = \frac{1}{1 + e^{-z}}

最终预测结果为:

\hat{y} = P(y=1 \mid \mathbf{x}) = \sigma(\mathbf{w}^T \mathbf{x} + b)

由于 ​\sigma(z) \in (0,1)​\hat{y} 可直接视为“属于类别 1 的概率”。

决策规则

  • ​\hat{y} \geq 0.5,预测为 ​1
  • ​\hat{y} < 0.5,预测为 ​0

对应的决策边界为:

\mathbf{w}^T \mathbf{x} + b = 0

这是一个线性超平面(在二维空间中为一条直线)。

三、数学推导

1. 概率建模

假设标签 ​y \in \{0,1\} 服从伯努利分布,则条件概率可写为:

P(y \mid \mathbf{x}; \mathbf{w}, b) = [\sigma(z)]^y [1 - \sigma(z)]^{1 - y}

2. 极大似然估计

设训练集为 ​\{(\mathbf{x}^{(i)}, y^{(i)})\}_{i=1}^m,似然函数为:

L(\mathbf{w}, b) = \prod_{i=1}^m [\sigma(z^{(i)})]^{y^{(i)}} [1 - \sigma(z^{(i)})]^{1 - y^{(i)}}

取对数似然以简化计算:

\ell(\mathbf{w}, b) = \sum_{i=1}^m \left[ y^{(i)} \log \sigma(z^{(i)}) + (1 - y^{(i)}) \log (1 - \sigma(z^{(i)})) \right]

3. 损失函数(交叉熵)

最大化对数似然等价于最小化其负值。定义平均损失函数为:

J(\mathbf{w}, b) = -\frac{1}{m} \sum_{i=1}^m \left[ y^{(i)} \log \hat{y}^{(i)} + (1 - y^{(i)}) \log (1 - \hat{y}^{(i)}) \right]

此即二元交叉熵损失(Binary Cross-Entropy Loss)

4. 梯度计算

​\hat{y}^{(i)} = \sigma(z^{(i)}),可推导出梯度为:

\frac{\partial J}{\partial w_j} = \frac{1}{m} \sum_{i=1}^m (\hat{y}^{(i)} - y^{(i)}) x_j^{(i)}
\frac{\partial J}{\partial b} = \frac{1}{m} \sum_{i=1}^m (\hat{y}^{(i)} - y^{(i)})

5. 参数更新

采用梯度下降法更新参数(学习率为 ​\alpha):

w_j := w_j - \alpha \cdot \frac{\partial J}{\partial w_j}
b := b - \alpha \cdot \frac{\partial J}{\partial b}

值得注意的是,该梯度形式与线性回归高度相似,区别仅在于 ​\hat{y}^{(i)} 是 Sigmoid 输出。

四、Python 实现

1. 从零实现(NumPy)

import numpy as np  
from sklearn.datasets import make_classification  
  
# 生成模拟数据  
X, y = make_classification(  
 n_samples=200, n_features=2, n_redundant=0, n_informative=2, n_clusters_per_class=1, random_state=42)  
  
# 添加偏置项(将 b 合并到权重向量中)  
X_b = np.c_[np.ones((X.shape[0], 1)), X]  
  
def sigmoid(z):  
 # 使用 clip 防止指数溢出  
 return 1 / (1 + np.exp(-np.clip(z, -250, 250)))  
def compute_loss(y_true, y_pred):  
 epsilon = 1e-15 y_pred = np.clip(y_pred, epsilon, 1 - epsilon) return -np.mean(y_true * np.log(y_pred) + (1 - y_true) * np.log(1 - y_pred))  
# 初始化参数  
np.random.seed(42)  
theta = np.random.randn(X_b.shape[1])  # [b, w1, w2]  
  
# 超参数  
learning_rate = 0.1  
epochs = 1000  
  
# 梯度下降  
losses = []  
for epoch in range(epochs):  
 z = X_b.dot(theta) y_pred = sigmoid(z) loss = compute_loss(y, y_pred) losses.append(loss)     gradient = (1 / len(y)) * X_b.T.dot(y_pred - y)  
 theta -= learning_rate * gradient  
print("训练完成!参数:", theta)

2. 使用 scikit-learn

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score

model = LogisticRegression()
model.fit(X, y)
y_pred_sk = model.predict(X)

print("sklearn 准确率:", accuracy_score(y, y_pred_sk))
print("sklearn 参数: w =", model.coef_, "b =", model.intercept_)

3. 两种方法的可视化决策

import matplotlib.pyplot as plt

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

# 手写模型
plt.subplot(1, 2, 1)
plt.scatter(X[y == 0, 0], X[y == 0, 1], color='red', label='Class 0')
plt.scatter(X[y == 1, 0], X[y == 1, 1], color='blue', label='Class 1')

x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
x1_vals = np.linspace(x1_min, x1_max, 100)
x2_vals = -(theta[0] + theta[1] * x1_vals) / theta[2]
plt.plot(x1_vals, x2_vals, 'k--', label='Decision Boundary')
plt.title('From Scratch')
plt.legend()

# sklearn 模型
plt.subplot(1, 2, 2)
plt.scatter(X[y == 0, 0], X[y == 0, 1], color='red', label='Class 0')
plt.scatter(X[y == 1, 0], X[y == 1, 1], color='blue', label='Class 1')

coef = model.coef_[0]
intercept = model.intercept_[0]
x2_vals_sk = -(intercept + coef[0] * x1_vals) / coef[1]
plt.plot(x1_vals, x2_vals_sk, 'k--', label='Decision Boundary')
plt.title('Scikit-learn')
plt.legend()

plt.tight_layout()
plt.show()

image.png

五、总结

项目 说明
任务类型 二分类
输出 P(y=1∣x)∈(0,1)
激活函数 Sigmoid
损失函数 二元交叉熵
优化方法 梯度下降
决策边界 线性
优点 概率输出、可解释性强、训练高效
局限 仅能学习线性可分边界

Comment