当前位置: 首页 > news >正文

分类问题的基石:逻辑回归(Logistic Regression)

人工智能与世界模型# 系列文章目录

第一章 数学基础(一)导数、偏导数、方向导数与梯度
第二章 数学基础(二)向量、矩阵、行列式与线性变换
第三章 机器学习中的Hello World:线性回归(一)
第四章 机器学习中的Hello World:线性回归(二)
第五章 优化算法进阶:从梯度下降到随机梯度下降(SGD)与批量梯度下降(BGD)
第六章 分类问题的基石:逻辑回归(Logistic Regression)


文章目录

  • 人工智能与世界模型# 系列文章目录
  • 前言
  • 一、从线性回归到逻辑回归:引入非线性
    • 1.1 线性回归的局限性
    • 1.2 引入 Sigmoid 函数(激活函数)
    • 1.3 逻辑回归的模型
  • 二、逻辑回归的损失函数:交叉熵(Cross-Entropy)
    • 2.1 交叉熵损失的定义
    • 2.2 损失函数的几何意义(为什么是它?)
    • 2.3 整体损失函数
  • 三、梯度下降求解:神奇的巧合
    • 3.1 梯度的计算
    • 3.2 参数更新
  • 四、逻辑回归的工程实践与局限性
    • 4.1 实践:多分类问题(Softmax)
    • 4.2 局限性:线性决策边界
  • 五、代码实现
    • 5.1 手写逻辑回归
    • 5.2 sklearn实现
  • 总结:通往神经网络的桥梁


前言

在前面的章节中,我们已经掌握了:

  1. 数学基础:导数、梯度、向量、矩阵。
  2. 回归问题:使用线性回归预测连续值(如房价)。
  3. 优化方法:使用梯度下降及其变体(SGD/MBGD)来高效地求解模型参数。

然而,现实世界中的问题远不止“预测一个数值”这么简单。我们更常遇到的是分类问题

  • 判断一封邮件是垃圾邮件还是非垃圾邮件(二分类)。
  • 识别一张图片是还是(多分类)。
  • 预测用户是否会点击某个广告(二分类)。

本章,我们将介绍机器学习中处理分类问题的“Hello World”——逻辑回归(Logistic Regression)。它虽然名字里有“回归”,但本质上是一个强大的分类模型,更是通往神经网络世界的关键一步。


一、从线性回归到逻辑回归:引入非线性

1.1 线性回归的局限性

在线性回归中,我们的模型输出 y^\hat{y}y^ 是一个连续值:
y^=WTX+b\hat{y} = \mathbf{W}^T \mathbf{X} + b y^=WTX+b
这个输出 y^\hat{y}y^ 的范围是 (−∞,+∞)(-\infty, +\infty)(,+)。如果我们要用它来解决分类问题,比如预测“是否点击广告”(结果只有 0 或 1),就会遇到问题:

  1. 输出范围不匹配:我们希望输出是概率(0 到 1 之间),但线性回归的输出可能远超 1 或低于 0。
  2. 硬性分类困难:如果简单地设定 y^>0.5\hat{y} > 0.5y^>0.5 为 1,y^≤0.5\hat{y} \le 0.5y^0.5 为 0,那么一个极端的 y^=100\hat{y}=100y^=100 和一个 y^=0.6\hat{y}=0.6y^=0.6 在分类上没有区别,但在模型中却代表了巨大的误差,这会使得模型对异常值非常敏感。

1.2 引入 Sigmoid 函数(激活函数)

为了将线性模型的输出压缩到 (0,1)(0, 1)(0,1) 之间,使其具有概率意义,我们引入了一个特殊的非线性函数——Sigmoid 函数(也称逻辑函数)。

g(z)=11+e−zg(z) = \frac{1}{1 + e^{-z}} g(z)=1+ez1

其中,z=WTX+bz = \mathbf{W}^T \mathbf{X} + bz=WTX+b 是线性回归的输出。

Sigmoid 函数的特性:

  • 范围:将任意实数 zzz 映射到 (0,1)(0, 1)(0,1) 之间。
  • 非线性:引入了非线性因素,使得模型能够处理非线性决策边界。
  • 概率解释:输出 h(X)=g(z)h(\mathbf{X}) = g(z)h(X)=g(z) 可以被解释为样本 X\mathbf{X}X 属于正类别(y=1y=1y=1)的概率:
    P(y=1∣X;W,b)=h(X)P(y=1 | \mathbf{X}; \mathbf{W}, b) = h(\mathbf{X}) P(y=1∣X;W,b)=h(X)

1.3 逻辑回归的模型

逻辑回归的模型可以表示为:
h(X)=11+e−(WTX+b)h(\mathbf{X}) = \frac{1}{1 + e^{-(\mathbf{W}^T \mathbf{X} + b)}} h(X)=1+e(WTX+b)1
我们的目标是找到最优的参数 W\mathbf{W}Wbbb,使得这个概率 h(X)h(\mathbf{X})h(X) 能够最好地拟合训练数据中的真实标签 yyy


二、逻辑回归的损失函数:交叉熵(Cross-Entropy)

在线性回归中,我们使用均方误差(MSE)作为损失函数。但如果我们将 Sigmoid 函数的输出代入 MSE,得到的损失函数将是非凸的,这意味着它有很多局部最小值,梯度下降算法很容易陷入其中,无法找到全局最优解。

因此,我们需要为逻辑回归设计一个更合适的损失函数——交叉熵损失(Cross-Entropy Loss),也称为对数损失(Log Loss)

2.1 交叉熵损失的定义

对于单个样本 (X,y)(\mathbf{X}, y)(X,y),其损失函数 L(W)L(\mathbf{W})L(W) 定义为:

L(W)=−[ylog⁡(h(X))+(1−y)log⁡(1−h(X))]L(\mathbf{W}) = - [y \log(h(\mathbf{X})) + (1 - y) \log(1 - h(\mathbf{X}))] L(W)=[ylog(h(X))+(1y)log(1h(X))]

其中 yyy 是真实标签(0 或 1),h(X)h(\mathbf{X})h(X) 是模型预测的概率。

2.2 损失函数的几何意义(为什么是它?)

这个损失函数非常巧妙地利用了 yyy 只能取 0 或 1 的特性:

  1. 当真实标签 y=1y=1y=1
    L(W)=−[1⋅log⁡(h(X))+(1−1)⋅log⁡(1−h(X))]=−log⁡(h(X))L(\mathbf{W}) = - [1 \cdot \log(h(\mathbf{X})) + (1 - 1) \cdot \log(1 - h(\mathbf{X}))] = - \log(h(\mathbf{X})) L(W)=[1log(h(X))+(11)log(1h(X))]=log(h(X))

    • 如果模型预测 h(X)→1h(\mathbf{X}) \to 1h(X)1(正确),则 L(W)→−log⁡(1)=0L(\mathbf{W}) \to -\log(1) = 0L(W)log(1)=0(损失很小)。
    • 如果模型预测 h(X)→0h(\mathbf{X}) \to 0h(X)0(错误),则 L(W)→−log⁡(0)=∞L(\mathbf{W}) \to -\log(0) = \inftyL(W)log(0)=(损失巨大)。
  2. 当真实标签 y=0y=0y=0
    L(W)=−[0⋅log⁡(h(X))+(1−0)⋅log⁡(1−h(X))]=−log⁡(1−h(X))L(\mathbf{W}) = - [0 \cdot \log(h(\mathbf{X})) + (1 - 0) \cdot \log(1 - h(\mathbf{X}))] = - \log(1 - h(\mathbf{X})) L(W)=[0log(h(X))+(10)log(1h(X))]=log(1h(X))

    • 如果模型预测 h(X)→0h(\mathbf{X}) \to 0h(X)0(正确),则 L(W)→−log⁡(1)=0L(\mathbf{W}) \to -\log(1) = 0L(W)log(1)=0(损失很小)。
    • 如果模型预测 h(X)→1h(\mathbf{X}) \to 1h(X)1(错误),则 L(W)→−log⁡(0)=∞L(\mathbf{W}) \to -\log(0) = \inftyL(W)log(0)=(损失巨大)。

总结:交叉熵损失函数能够完美地惩罚错误的预测,并且它是一个凸函数(对于逻辑回归而言),保证了我们可以使用梯度下降法找到全局最优解。

2.3 整体损失函数

对于 mmm 个样本的训练集,整体损失函数(平均损失)为:
J(W)=−1m∑i=1m[y(i)log⁡(h(X(i)))+(1−y(i))log⁡(1−h(X(i)))]J(\mathbf{W}) = - \frac{1}{m} \sum_{i=1}^{m} [y^{(i)} \log(h(\mathbf{X}^{(i)})) + (1 - y^{(i)}) \log(1 - h(\mathbf{X}^{(i)}))] J(W)=m1i=1m[y(i)log(h(X(i)))+(1y(i))log(1h(X(i)))]


三、梯度下降求解:神奇的巧合

我们的优化目标是:
W∗=arg⁡min⁡WJ(W)\mathbf{W}^* = \arg \min_{\mathbf{W}} J(\mathbf{W}) W=argWminJ(W)
和线性回归一样,我们使用梯度下降法来求解。

3.1 梯度的计算

J(W)J(\mathbf{W})J(W) 求偏导,得到梯度 ∇J(W)\nabla J(\mathbf{W})J(W)

令人惊奇的是,尽管逻辑回归的模型和损失函数看起来比线性回归复杂得多,但最终推导出的梯度形式却出奇地简洁

∂J(W)∂W=1m∑i=1m(X(i)(h(X(i))−y(i)))\frac{\partial J(\mathbf{W})}{\partial \mathbf{W}} = \frac{1}{m} \sum_{i=1}^{m} (\mathbf{X}^{(i)} (h(\mathbf{X}^{(i)}) - y^{(i)})) WJ(W)=m1i=1m(X(i)(h(X(i))y(i)))

对比线性回归的梯度:
∂L(W)∂W=1m∑i=1m(X(i)(y^(i)−y(i)))\frac{\partial L(\mathbf{W})}{\partial \mathbf{W}} = \frac{1}{m} \sum_{i=1}^{m} (\mathbf{X}^{(i)} (\hat{y}^{(i)} - y^{(i)})) WL(W)=m1i=1m(X(i)(y^(i)y(i)))

你会发现,逻辑回归的梯度形式与线性回归的梯度形式是完全一样的! 唯一的区别在于:

  • 线性回归中的 y^(i)\hat{y}^{(i)}y^(i) 是线性输出 WTX(i)+b\mathbf{W}^T \mathbf{X}^{(i)} + bWTX(i)+b
  • 逻辑回归中的 h(X(i))h(\mathbf{X}^{(i)})h(X(i)) 是经过 Sigmoid 函数处理后的概率 11+e−(WTX(i)+b)\frac{1}{1 + e^{-(\mathbf{W}^T \mathbf{X}^{(i)} + b)}}1+e(WTX(i)+b)1

3.2 参数更新

有了梯度,我们就可以使用第五章学到的**小批量梯度下降(MBGD)**来更新参数:

Wnew=Wold−α∇J(W)\mathbf{W}_{\text{new}} = \mathbf{W}_{\text{old}} - \alpha \nabla J(\mathbf{W}) Wnew=WoldαJ(W)


四、逻辑回归的工程实践与局限性

4.1 实践:多分类问题(Softmax)

逻辑回归本身是二分类模型。如果我们需要处理多分类问题(如识别猫、狗、鸟),我们可以将 Sigmoid 函数替换为 Softmax 函数,并将交叉熵损失推广为多类别交叉熵损失

Softmax 函数将模型的输出转化为一个概率分布,即所有类别的概率之和为 1。

对于 KKK 个类别,模型会输出 KKK 个分数 z1,z2,…,zKz_1, z_2, \dots, z_Kz1,z2,,zK。Softmax 函数将这些分数转换为概率 pip_ipi
pi=ezi∑j=1Kezjp_i = \frac{e^{z_i}}{\sum_{j=1}^{K} e^{z_j}} pi=j=1Kezjezi
其中,分子 ezie^{z_i}ezi 确保了概率为正,分母 ∑j=1Kezj\sum_{j=1}^{K} e^{z_j}j=1Kezj 确保了所有概率之和为 1。Softmax 函数是多分类问题中,将线性输出转化为概率的标准激活函数

4.2 局限性:线性决策边界

逻辑回归的本质仍然是线性模型。它只能找到一个线性决策边界(一条直线或一个平面)来分隔不同类别的样本。

如果数据是线性可分的,逻辑回归表现优秀。
如果数据是线性不可分的,逻辑回归将无能为力。

如何解决线性不可分问题?

  1. 特征工程:手动创建非线性特征(如 x12,x1x2x_1^2, x_1x_2x12,x1x2),将数据映射到高维空间使其线性可分。
  2. 引入多层非线性结构:将多个逻辑回归模型堆叠起来,形成一个多层感知机(Multi-Layer Perceptron, MLP),也就是我们下一章要正式进入的神经网络

五、代码实现

5.1 手写逻辑回归

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split# ----------------------------------------------------------------------
# 1. 数据生成
# ----------------------------------------------------------------------
def create_data():# 生成一个线性可分的数据集X, y = make_classification(n_samples=100, n_features=2, n_informative=2, n_redundant=0, n_classes=2, n_clusters_per_class=1, flip_y=0.1, random_state=42)# 将 y 转换为 (m, 1) 的列向量y = y.reshape(-1, 1)return X, y# ----------------------------------------------------------------------
# 2. 逻辑回归模型 (手写实现)
# ----------------------------------------------------------------------
class LogisticRegressionHandwritten:def __init__(self, learning_rate=0.01, epochs=1000):self.learning_rate = learning_rateself.epochs = epochsself.W = None  # 权重 (n_features + 1, 1)self.loss_history = []def _sigmoid(self, z):# Sigmoid 激活函数return 1 / (1 + np.exp(-z))def _add_bias(self, X):# 在特征矩阵 X 的第一列添加偏置项 x0=1m = X.shape[0]return np.hstack((np.ones((m, 1)), X))def fit(self, X, y):# 准备数据X_b = self._add_bias(X)  # (m, n+1)m, n = X_b.shape# 初始化权重 W (n+1, 1)# 使用 Xavier/Glorot 初始化,防止梯度消失/爆炸,这里简化为小随机数self.W = np.random.randn(n, 1) * 0.01# 梯度下降训练for epoch in range(self.epochs):# 1. 线性输出 (m, 1)z = np.dot(X_b, self.W)# 2. 预测概率 (m, 1)h = self._sigmoid(z)# 3. 计算损失 (交叉熵损失)# J(W) = - (1/m) * sum[y*log(h) + (1-y)*log(1-h)]# 避免 log(0) 错误,使用极小值 epsilonepsilon = 1e-15loss = - (1/m) * np.sum(y * np.log(h + epsilon) + (1 - y) * np.log(1 - h + epsilon))self.loss_history.append(loss)# 4. 计算梯度 (n+1, 1)# 梯度形式与线性回归一致: (1/m) * X_b.T * (h - y)gradient = (1/m) * np.dot(X_b.T, (h - y))# 5. 更新权重self.W = self.W - self.learning_rate * gradient# 打印进度if (epoch + 1) % 100 == 0:print(f"Epoch {epoch+1}/{self.epochs}, Loss: {loss:.4f}")def predict_proba(self, X):# 预测概率X_b = self._add_bias(X)z = np.dot(X_b, self.W)return self._sigmoid(z)def predict(self, X, threshold=0.5):# 预测类别 (0 或 1)probabilities = self.predict_proba(X)return (probabilities >= threshold).astype(int)# ----------------------------------------------------------------------
# 3. 可视化函数
# ----------------------------------------------------------------------
def plot_results(model, X, y, title):# 绘制数据点和决策边界plt.figure(figsize=(10, 6))# 绘制数据点plt.scatter(X[:, 0], X[:, 1], c=y.flatten(), cmap=plt.cm.RdYlBu, marker='o', edgecolors='k')# 绘制决策边界x_min, x_max = X[:, 0].min() - 0.5, X[:, 0].max() + 0.5y_min, y_max = X[:, 1].min() - 0.5, X[:, 1].max() + 0.5xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02),np.arange(y_min, y_max, 0.02))# 预测网格点的类别Z = model.predict(np.c_[xx.ravel(), yy.ravel()])Z = Z.reshape(xx.shape)# 绘制等高线图plt.contourf(xx, yy, Z, alpha=0.3, cmap=plt.cm.RdYlBu)plt.title(title)plt.xlabel("Feature 1")plt.ylabel("Feature 2")plt.colorbar(label='Predicted Class')plt.grid(True, linestyle='--', alpha=0.6)# 保存决策边界图plt.savefig(f"{title.replace(' ', '_')}_decision_boundary.png")plt.close()def plot_loss(loss_history, title):# 绘制损失下降曲线plt.figure(figsize=(10, 6))plt.plot(loss_history, label='Loss (Cross-Entropy)')plt.title(title)plt.xlabel("Epoch")plt.ylabel("Loss")plt.grid(True, linestyle='--', alpha=0.6)plt.legend()# 保存损失曲线图plt.savefig(f"{title.replace(' ', '_')}_loss_curve.png")plt.close()# ----------------------------------------------------------------------
# 4. 运行手写模型
# ----------------------------------------------------------------------
if __name__ == "__main__":# 1. 准备数据X, y = create_data()X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)# 2. 训练模型lr_handwritten = LogisticRegressionHandwritten(learning_rate=0.1, epochs=1000)print("--- 开始训练手写逻辑回归模型 ---")lr_handwritten.fit(X_train, y_train)print("--- 训练完成 ---")# 3. 评估模型y_pred_test = lr_handwritten.predict(X_test)accuracy = np.mean(y_pred_test == y_test)print(f"测试集准确率: {accuracy * 100:.2f}%")# 4. 可视化结果plot_loss(lr_handwritten.loss_history, "Handwritten Logistic Regression Loss Curve")plot_results(lr_handwritten, X_test, y_test, "Handwritten Logistic Regression Decision Boundary (Test Set)")print("手写模型损失曲线图已保存为: Handwritten_Logistic_Regression_Loss_Curve_loss_curve.png")print("手写模型决策边界图已保存为: Handwritten_Logistic_Regression_Decision_Boundary_(Test_Set)_decision_boundary.png")

在这里插入图片描述

在这里插入图片描述

5.2 sklearn实现

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score# ----------------------------------------------------------------------
# 1. 数据生成
# ----------------------------------------------------------------------
def create_data():# 生成一个线性可分的数据集X, y = make_classification(n_samples=100, n_features=2, n_informative=2, n_redundant=0, n_classes=2, n_clusters_per_class=1, flip_y=0.1, random_state=42)return X, y# ----------------------------------------------------------------------
# 2. 可视化函数
# ----------------------------------------------------------------------
def plot_decision_boundary(model, X, y, title, filename):# 绘制数据点和决策边界plt.figure(figsize=(10, 6))# 绘制数据点plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.RdYlBu, marker='o', edgecolors='k')# 绘制决策边界x_min, x_max = X[:, 0].min() - 0.5, X[:, 0].max() + 0.5y_min, y_max = X[:, 1].min() - 0.5, X[:, 1].max() + 0.5xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02),np.arange(y_min, y_max, 0.02))# 预测网格点的类别Z = model.predict(np.c_[xx.ravel(), yy.ravel()])Z = Z.reshape(xx.shape)# 绘制等高线图plt.contourf(xx, yy, Z, alpha=0.3, cmap=plt.cm.RdYlBu)plt.title(title)plt.xlabel("Feature 1")plt.ylabel("Feature 2")plt.colorbar(label='Predicted Class')plt.grid(True, linestyle='--', alpha=0.6)# 保存决策边界图plt.savefig(filename)plt.close()# ----------------------------------------------------------------------
# 3. 运行 Sklearn 模型
# ----------------------------------------------------------------------
if __name__ == "__main__":# 1. 准备数据X, y = create_data()X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)# 2. 训练模型# solver='liblinear' 适用于小数据集,'lbfgs' 是默认且适用于大数据集# C=1.0 是正则化强度的倒数,这里使用默认值lr_sklearn = LogisticRegression(solver='liblinear', random_state=42)print("--- 开始训练 Sklearn 逻辑回归模型 ---")lr_sklearn.fit(X_train, y_train)print("--- 训练完成 ---")# 3. 评估模型y_pred_test = lr_sklearn.predict(X_test)accuracy = accuracy_score(y_test, y_pred_test)print(f"测试集准确率: {accuracy * 100:.2f}%")# 4. 可视化结果filename = "Sklearn_Logistic_Regression_Decision_Boundary_Test_Set_decision_boundary.png"plot_decision_boundary(lr_sklearn, X_test, y_test, "Sklearn Logistic Regression Decision Boundary (Test Set)", filename)print(f"Sklearn 模型决策边界图已保存为: {filename}")# 注意:Sklearn 的 LogisticRegression 默认不提供 Loss 历史记录,# 因此无法直接绘制 Loss 曲线,这是手写实现的一个优势。print("注意:Sklearn 默认不提供 Loss 历史记录,无法绘制 Loss 曲线。")

在这里插入图片描述


总结:通往神经网络的桥梁

逻辑回归是机器学习中最重要的模型之一,它完成了从回归分类的转变,并引入了两个对深度学习至关重要的概念:

  1. 激活函数(Sigmoid):引入非线性,是神经网络中每一层的基础。
  2. 交叉熵损失:分类问题最常用的损失函数,是神经网络训练的基石。

通过逻辑回归,我们已经掌握了构建一个单层非线性分类器的所有要素。下一章,我们将把这个“单层”结构推广到“多层”,正式开启神经网络的学习。

http://www.dtcms.com/a/577658.html

相关文章:

  • 机器学习实践项目(二)- 房价预测增强篇 - 特征工程二
  • Jenkins自动部署CI/CD
  • 【unity】PowerVR GE8320系列GPU渲染问题分析
  • 做网站设计需要哪些知识网页游戏排行榜回合制
  • 从理论到实践:深度解析昇腾CANN训练营中的Ascend C编程模型
  • Java TreeMap与HashTable深度解析:有序映射与线程安全映射
  • 什么是大数据,为什么它很重要?
  • asp网站配置伪静态做网站的
  • 顺序表vector--------杨辉三角
  • 阿里云 RDS PostgreSQL 可观测最佳实践
  • JVM堆的管理者——CodeCache
  • 目前哪个网站建设的最好wordpress 模板引入文件
  • Data+AI 时代,对象存储为 AI 应用注入全局动力
  • linux:io基础
  • WSL+openEuler云原生实践:Docker全流程部署与多容器编排深度评测
  • 个人笔记|单臂路由,子接口,VLAN标签
  • 罗湖商城网站设计推荐小程序服务开发公司
  • 赣州网站建设jx25网页开发用到的技术
  • 企业服务在产业平台领域的渗透率现状和发展未来
  • 【P27 回归算法及应用实践】有监督的机器学习、分类与回归、一元线性回归、最小二乘法、多元回归与梯度下降、学习率
  • Spring Boot 如何支持国际化
  • Excel斜线表头怎么做?合并单元格后添加对角线+两侧输入文字,新手也能秒会!
  • ara::core——Adaptive AUTOSAR
  • 大语言模型训推一体机:AI算力革命的“新引擎”,2031年市场规模突破123亿的黄金赛道
  • 百度网站降级的原因计算机一级考试网站怎么做
  • 复数的矩阵表示 | 欧拉恒等式的复数矩阵变换
  • Linux 系统调用在 ARM 上的实现与工作机制
  • 红松小课如何成为激活老年人生活的新引擎?从兴趣学习到价值重塑!
  • 怎么才能去定义自己的生活呢?
  • 嘉兴云建站模板重庆网站备案大厅