人工智能数学基础+python实例(人工智能学习day3)

文章目录

  • 人工智能数学基础
    • [需要的 Python 库](#需要的 Python 库)
  • [附录 A 线性代数](#附录 A 线性代数)
    • [A.1 向量和向量空间](#A.1 向量和向量空间)
      • [A.1.1 向量](#A.1.1 向量)
      • [A.1.2 向量空间](#A.1.2 向量空间)
      • [A.1.3 范数](#A.1.3 范数)
      • [A.1.4 常见的向量](#A.1.4 常见的向量)
    • [A.2 矩阵](#A.2 矩阵)
      • [A.2.1 线性映射](#A.2.1 线性映射)
      • [A.2.2 仿射变换](#A.2.2 仿射变换)
      • [A.2.3 矩阵操作](#A.2.3 矩阵操作)
      • [A.2.4 矩阵类型](#A.2.4 矩阵类型)
      • [A.2.5 特征值与特征向量](#A.2.5 特征值与特征向量)
      • [A.2.6 矩阵分解](#A.2.6 矩阵分解)
        • [A.2.6.1 特征分解(Eigendecomposition)](#A.2.6.1 特征分解(Eigendecomposition))
        • [A.2.6.2 奇异值分解(SVD)](#A.2.6.2 奇异值分解(SVD))
  • [附录 B 微积分](#附录 B 微积分)
    • [B.1 微分](#B.1 微分)
      • [B.1.1 导数](#B.1.1 导数)
      • [B.1.2 微分](#B.1.2 微分)
      • [B.1.3 泰勒公式](#B.1.3 泰勒公式)
    • [B.2 积分](#B.2 积分)
    • [B.3 矩阵微积分](#B.3 矩阵微积分)
    • [B.4 常见函数的导数](#B.4 常见函数的导数)
      • [B.4.1 向量函数及其导数](#B.4.1 向量函数及其导数)
      • [B.4.2 Logistic 函数](#B.4.2 Logistic 函数)
      • [B.4.3 Softmax 函数](#B.4.3 Softmax 函数)
  • [附录 C 数学优化](#附录 C 数学优化)
    • [C.1 数学优化的类型](#C.1 数学优化的类型)
    • [C.2 优化算法](#C.2 优化算法)
      • [C.2.1 全局最小解和局部最小解](#C.2.1 全局最小解和局部最小解)
      • [C.2.2 梯度下降法](#C.2.2 梯度下降法)
    • [C.3 拉格朗日乘数法与 KKT 条件](#C.3 拉格朗日乘数法与 KKT 条件)
  • [附录 D 概率论](#附录 D 概率论)
    • [D.1 样本空间](#D.1 样本空间)
    • [D.2 事件和概率](#D.2 事件和概率)
    • [D.2.2 随机向量](#D.2.2 随机向量)
    • [D.2.3 边际分布](#D.2.3 边际分布)
    • [D.2.4 条件概率分布](#D.2.4 条件概率分布)
    • [D.2.5 贝叶斯定理](#D.2.5 贝叶斯定理)
    • [D.2.6 独立与条件独立](#D.2.6 独立与条件独立)
    • [D.2.7 期望和方差](#D.2.7 期望和方差)
    • [D.3 随机过程](#D.3 随机过程)
      • [D.3.1 马尔可夫过程](#D.3.1 马尔可夫过程)
      • 细致平稳条件
      • [D.3.2 高斯过程](#D.3.2 高斯过程)
  • [附录 E 信息论](#附录 E 信息论)
    • [E.1 熵](#E.1 熵)
    • [E.2 互信息](#E.2 互信息)
    • [E.3 交叉熵和散度](#E.3 交叉熵和散度)
      • 交叉熵
      • [KL 散度](#KL 散度)
      • [JS 散度](#JS 散度)
      • [Wasserstein 距离(推土机距离)](#Wasserstein 距离(推土机距离))
    • [E.4 总结](#E.4 总结)

人工智能数学基础

原文来源:《人工智能数学基础》附录部分

本文档为每个数学公式/概念附加了 Python 代码示例


需要的 Python 库

python 复制代码
import numpy as np           # 矩阵运算、线性代数
import scipy.stats as stats  # 概率分布、统计函数
import scipy.linalg          # 线性代数(特征值分解、SVD等)
import matplotlib.pyplot as plt  # 可视化
import sympy as sp           # 符号计算(微分、积分、泰勒展开)
import math                  # 基本数学函数

安装命令:

bash 复制代码
pip install numpy scipy matplotlib sympy

附录 A 线性代数

线性代数主要包含向量、向量空间(或称线性空间)以及向量的线性变换和有限维的线性方程组。

A.1 向量和向量空间

A.1.1 向量

标量(Scalar) 是一个实数,只有大小,没有方向。标量一般用斜体小写英文字母来表示。

向量(Vector) 是由一组实数组成的有序数组,同时具有大小和方向。一个 n 维向量是由 n 个有序实数组成,表示为:

x = [ x 1 , x 2 , . . . , x n ] T \mathbf{x} = [x_1, x_2, ..., x_n]^T x=[x1,x2,...,xn]T

其中 x i x_i xi 称为向量的第 i 个分量,或第 i 维。

python 复制代码
# 向量示例
x = np.array([3.0, 4.0, 5.0])  # 3维向量
print(f"向量 x = {x}")
print(f"维度: {x.shape[0]}")
print(f"大小(模): {np.linalg.norm(x):.4f}")

输出:

复制代码
向量 x = [3. 4. 5.]
维度: 3
大小(模): 7.0711

A.1.2 向量空间

向量空间(Vector Space),也称线性空间(Linear Space),是指由向量组成的集合,并满足以下两个条件:

  1. 向量加法 + + +:向量空间 V V V 中的两个向量 x \mathbf{x} x 和 y \mathbf{y} y,它们的和 x + y \mathbf{x}+\mathbf{y} x+y 也属于空间 V V V;
  2. 标量乘法 ⋅ \cdot ⋅:向量空间 V V V 中的任一向量 x \mathbf{x} x 和任一标量 c c c,它们的乘积 c x c\mathbf{x} cx 也属于空间 V V V。

欧氏空间(Euclidean Space) :一个定义在实数域上的欧氏空间通常表示为 R n \mathbb{R}^n Rn,其中 n 为空间维度。

x + y = [ x 1 + y 1 , x 2 + y 2 , . . . , x n + y n ] T \mathbf{x} + \mathbf{y} = [x_1+y_1, x_2+y_2, ..., x_n+y_n]^T x+y=[x1+y1,x2+y2,...,xn+yn]T

c x = [ c x 1 , c x 2 , . . . , c x n ] T c\mathbf{x} = [cx_1, cx_2, ..., cx_n]^T cx=[cx1,cx2,...,cxn]T

python 复制代码
# 向量空间运算
x = np.array([1.0, 2.0, 3.0])
y = np.array([4.0, 5.0, 6.0])
c = 2.0

# 向量加法
add_result = x + y
print(f"x + y = {add_result}")

# 标量乘法
scale_result = c * x
print(f"c * x = {scale_result}")

# 验证封闭性:结果仍在同一空间中
print(f"结果维度: {add_result.shape[0]}")

输出:

复制代码
x + y = [5. 7. 9.]
c * x = [2. 4. 6.]
结果维度: 3

线性无关 :线性空间 V 中的 k 个向量 x 1 , x 2 , . . . , x k \mathbf{x}_1, \mathbf{x}_2, ..., \mathbf{x}_k x1,x2,...,xk,如果:

λ 1 x 1 + λ 2 x 2 + . . . + λ k x k = 0    ⟹    λ 1 = λ 2 = . . . = λ k = 0 \lambda_1\mathbf{x}_1 + \lambda_2\mathbf{x}_2 + ... + \lambda_k\mathbf{x}_k = 0 \implies \lambda_1 = \lambda_2 = ... = \lambda_k = 0 λ1x1+λ2x2+...+λkxk=0⟹λ1=λ2=...=λk=0

则这些向量是线性无关的。

python 复制代码
# 线性无关验证
v1 = np.array([1, 0, 0])
v2 = np.array([0, 1, 0])
v3 = np.array([0, 0, 1])

# 构造矩阵并检查秩
M = np.column_stack([v1, v2, v3])
rank = np.linalg.matrix_rank(M)
print(f"矩阵秩: {rank}, 向量个数: 3")
print(f"线性无关: {rank == 3}")

# 线性相关的例子
v4 = np.array([2, 2, 0])  # v4 = 2*v1 + 2*v2
M2 = np.column_stack([v1, v2, v4])
rank2 = np.linalg.matrix_rank(M2)
print(f"线性相关矩阵秩: {rank2}, 向量个数: 3")
print(f"线性无关: {rank2 == 3}")

输出:

复制代码
矩阵秩: 3, 向量个数: 3
线性无关: True
线性相关矩阵秩: 2, 向量个数: 3
线性无关: False

基向量 :n 维向量空间 V 的基 B = { e 1 , e 2 , . . . , e n } \mathcal{B} = \{\mathbf{e}_1, \mathbf{e}_2, ..., \mathbf{e}_n\} B={e1,e2,...,en} 是 V 的有限子集,其元素之间线性无关。向量空间 V 中所有的向量都可以按唯一的方式表达为 B \mathcal{B} B 中向量的线性组合。

n 维空间 R n \mathbb{R}^n Rn 的一组标准基为:

e 1 = [ 1 , 0 , 0 , . . . , 0 ] , e 2 = [ 0 , 1 , 0 , . . . , 0 ] , . . . , e n = [ 0 , 0 , . . . , 1 ] \mathbf{e}_1 = [1,0,0,...,0],\ \mathbf{e}_2 = [0,1,0,...,0],\ ...,\ \mathbf{e}_n = [0,0,...,1] e1=[1,0,0,...,0], e2=[0,1,0,...,0], ..., en=[0,0,...,1]

x = x 1 e 1 + x 2 e 2 + . . . + x n e n = [ x 1 , x 2 , . . . , x n ] T \mathbf{x} = x_1\mathbf{e}_1 + x_2\mathbf{e}_2 + ... + x_n\mathbf{e}_n = [x_1, x_2, ..., x_n]^T x=x1e1+x2e2+...+xnen=[x1,x2,...,xn]T

python 复制代码
# 标准基和坐标表示
n = 3
standard_basis = np.eye(n)  # 标准基矩阵
x = np.array([5, 3, 7])

# 用线性组合验证
reconstructed = np.zeros(n)
for i in range(n):
    reconstructed += x[i] * standard_basis[i]
print(f"原向量: {x}")
print(f"线性组合重建: {reconstructed}")
print(f"相等: {np.allclose(x, reconstructed)}")

输出:

复制代码
原向量: [5 3 7]
线性组合重建: [5. 3. 7.]
相等: True

内积(Inner Product) :一个 n 维线性空间中两个向量 x \mathbf{x} x 和 y \mathbf{y} y 的内积为:

x ⋅ y = ∑ i = 1 n x i y i = x T y \mathbf{x} \cdot \mathbf{y} = \sum_{i=1}^n x_i y_i = \mathbf{x}^T\mathbf{y} x⋅y=i=1∑nxiyi=xTy

内积也称为点积(Dot Product)或标量积(Scalar Product)。

python 复制代码
# 内积运算
x = np.array([1, 2, 3])
y = np.array([4, 5, 6])

# 三种等价方式
dot1 = np.dot(x, y)
dot2 = x @ y           # Python 3.5+ 矩阵乘法运算符
dot3 = np.sum(x * y)   # 逐元素乘法后求和

print(f"内积 x·y = {dot1}")
print(f"x @ y = {dot2}")
print(f"sum(x*y) = {dot3}")

输出:

复制代码
内积 x·y = 32
x @ y = 32
sum(x*y) = 32

正交(Orthogonal):如果向量空间中两个向量的内积为 0,则它们正交。

python 复制代码
# 正交判断
x = np.array([1, 0, 0])
y = np.array([0, 1, 0])
z = np.array([1, 1, 0])

print(f"x·y = {np.dot(x, y)}, 正交: {np.dot(x, y) == 0}")
print(f"x·z = {np.dot(x, z)}, 正交: {np.dot(x, z) == 0}")

输出:

复制代码
x·y = 0, 正交: True
x·z = 1, 正交: False

A.1.3 范数

范数(Norm)是一个表示向量"长度"的函数。对于一个 n 维向量 x \mathbf{x} x, L p L_p Lp 范数定义为:

L p ( x ) = ( ∑ i = 1 n ∣ x i ∣ p ) 1 / p , p ≥ 1 L_p(\mathbf{x}) = \left(\sum_{i=1}^n |x_i|^p\right)^{1/p}, \quad p \ge 1 Lp(x)=(i=1∑n∣xi∣p)1/p,p≥1

  • L 1 L_1 L1 范数 : L 1 ( x ) = ∑ i = 1 n ∣ x i ∣ L_1(\mathbf{x}) = \sum_{i=1}^n |x_i| L1(x)=∑i=1n∣xi∣
  • L 2 L_2 L2 范数 : L 2 ( x ) = ∑ i = 1 n x i 2 L_2(\mathbf{x}) = \sqrt{\sum_{i=1}^n x_i^2} L2(x)=∑i=1nxi2
  • L ∞ L_\infty L∞ 范数 : L ∞ ( x ) = max ⁡ i ∣ x i ∣ L_\infty(\mathbf{x}) = \max_i |x_i| L∞(x)=maxi∣xi∣
python 复制代码
# 向量范数
x = np.array([3, -4, 5])

l1 = np.linalg.norm(x, ord=1)
l2 = np.linalg.norm(x, ord=2)  # 或 np.linalg.norm(x)
linf = np.linalg.norm(x, ord=np.inf)

print(f"L1 范数 (曼哈顿距离): {l1}")
print(f"L2 范数 (欧氏距离):   {l2:.4f}")
print(f"L∞ 范数 (最大值):     {linf}")

# 手动计算验证
l1_manual = np.sum(np.abs(x))
l2_manual = np.sqrt(np.sum(x**2))
linf_manual = np.max(np.abs(x))
print(f"\n手动计算验证: L1={l1_manual}, L2={l2_manual:.4f}, L∞={linf_manual}")

输出:

复制代码
L1 范数 (曼哈顿距离): 12.0
L2 范数 (欧氏距离):   7.0711
L∞ 范数 (最大值):     5.0

手动计算验证: L1=12, L2=7.0711, L∞=5

A.1.4 常见的向量

  • 全 0 向量 :所有元素都为 0 的向量,用 0 \mathbf{0} 0 表示。
  • 全 1 向量 :所有元素都为 1 的向量,用 1 \mathbf{1} 1 表示。
  • one-hot 向量:有且只有一个元素为 1,其余元素都为 0 的向量。
python 复制代码
n = 5

# 全0向量
zero_vec = np.zeros(n)
print(f"全0向量: {zero_vec}")

# 全1向量
ones_vec = np.ones(n)
print(f"全1向量: {ones_vec}")

# one-hot向量(第3个位置为1,索引从0开始)
one_hot = np.zeros(n)
one_hot[2] = 1
print(f"one-hot向量: {one_hot}")

# 用库函数创建one-hot
from sklearn.preprocessing import OneHotEncoder
# 需要 sklearn: pip install scikit-learn

输出:

复制代码
全0向量: [0. 0. 0. 0. 0.]
全1向量: [1. 1. 1. 1. 1.]
one-hot向量: [0. 0. 1. 0. 0.]

A.2 矩阵

A.2.1 线性映射

线性映射(Linear Mapping)是指从线性空间 V 到线性空间 W 的一个映射函数 f : V → W f: V \to W f:V→W,满足:

f ( x + y ) = f ( x ) + f ( y ) , f ( c x ) = c f ( x ) f(\mathbf{x}+\mathbf{y}) = f(\mathbf{x}) + f(\mathbf{y}), \quad f(c\mathbf{x}) = cf(\mathbf{x}) f(x+y)=f(x)+f(y),f(cx)=cf(x)

两个有限维欧氏空间的映射函数 f : R n → R m f: \mathbb{R}^n \to \mathbb{R}^m f:Rn→Rm 可以表示为:

y = A x \mathbf{y} = \mathbf{A}\mathbf{x} y=Ax

其中 A \mathbf{A} A 是一个 m × n m \times n m×n 的矩阵(Matrix)。

python 复制代码
# 线性映射
A = np.array([[1, 2],
              [3, 4],
              [5, 6]])  # 3x2 矩阵: R² → R³

x = np.array([2, 3])     # R²中的向量

y = A @ x  # 线性映射
print(f"A = \n{A}")
print(f"x = {x}")
print(f"y = Ax = {y}")
print(f"映射: R^{x.shape[0]} → R^{y.shape[0]}")

输出:

复制代码
A = 
[[1 2]
 [3 4]
 [5 6]]
x = [2 3]
y = Ax = [ 8 18 28]
映射: R² → R³

A.2.2 仿射变换

仿射变换(Affine Transformation)是指通过一个线性变换和一个平移,将一个向量空间变换成另一个向量空间的过程。

y = A x + b \mathbf{y} = \mathbf{A}\mathbf{x} + \mathbf{b} y=Ax+b

其中 x ∈ R n \mathbf{x} \in \mathbb{R}^n x∈Rn, A ∈ R m × n \mathbf{A} \in \mathbb{R}^{m \times n} A∈Rm×n, b ∈ R m \mathbf{b} \in \mathbb{R}^m b∈Rm 为平移项。

当 b = 0 \mathbf{b} = 0 b=0 时,仿射变换就退化为线性变换。

python 复制代码
# 仿射变换示例:2D点旋转+平移
A = np.array([[0.866, -0.5],   # 旋转30度
              [0.5,   0.866]])
b = np.array([2, 3])           # 平移向量

points = np.array([[1, 0],     # 原始点
                   [2, 1],
                   [0, 2]])

# 对每个点施加仿射变换
transformed = points @ A.T + b  # 每个点:(A·x + b)
print("原始点:\n", points)
print("变换后:\n", transformed)

# 可视化
fig, ax = plt.subplots(figsize=(6, 6))
ax.scatter(points[:, 0], points[:, 1], c='blue', s=100, label='原始')
ax.scatter(transformed[:, 0], transformed[:, 1], c='red', s=100, label='变换后')
ax.axhline(0, color='gray', alpha=0.3)
ax.axvline(0, color='gray', alpha=0.3)
ax.legend()
ax.set_aspect('equal')
ax.grid(True)
ax.set_title('仿射变换:旋转30° + 平移(2,3)')
plt.show()

A.2.3 矩阵操作

矩阵加法 :两个 m × n m \times n m×n 矩阵 A \mathbf{A} A 和 B \mathbf{B} B 的加也是 m × n m \times n m×n 矩阵:

C = A + B , C i j = A i j + B i j \mathbf{C} = \mathbf{A} + \mathbf{B},\quad C_{ij} = A_{ij} + B_{ij} C=A+B,Cij=Aij+Bij

python 复制代码
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
C = A + B
print(f"A + B =\n{C}")

输出:

复制代码
A + B =
[[ 6  8]
 [10 12]]

矩阵乘法 : A ∈ R m × k \mathbf{A} \in \mathbb{R}^{m \times k} A∈Rm×k 和 B ∈ R k × n \mathbf{B} \in \mathbb{R}^{k \times n} B∈Rk×n 的乘积 C ∈ R m × n \mathbf{C} \in \mathbb{R}^{m \times n} C∈Rm×n:

C i j = ∑ t = 1 k A i t B t j C_{ij} = \sum_{t=1}^k A_{it} B_{tj} Cij=t=1∑kAitBtj

python 复制代码
A = np.array([[1, 2, 3],
              [4, 5, 6]])  # 2x3

B = np.array([[7,  8],
              [9,  10],
              [11, 12]])   # 3x2

C = A @ B  # 2x2
print(f"A (2x3) @ B (3x2) = C (2x2)\n{C}")

# 验证结合律: (AB)C = A(BC)
D = np.array([[1, 2], [3, 4]])  # 2x2
left = (A @ B) @ D
right = A @ (B @ D)
print(f"\n结合律验证 - 相等: {np.allclose(left, right)}")

输出:

复制代码
A (2x3) @ B (3x2) = C (2x2)
[[ 58  64]
 [139 154]]

结合律验证 - 相等: True

转置(Transposition) : m × n m \times n m×n 矩阵 A \mathbf{A} A 的转置是一个 n × m n \times m n×m 矩阵 A T \mathbf{A}^T AT:

( A T ) i j = A j i (\mathbf{A}^T){ij} = A{ji} (AT)ij=Aji

python 复制代码
A = np.array([[1, 2, 3],
              [4, 5, 6]])
AT = A.T
print(f"A =\n{A}")
print(f"A^T =\n{AT}")
print(f"(A^T)^T == A: {np.allclose(AT.T, A)}")  # 转置的转置等于原矩阵

输出:

复制代码
A =
[[1 2 3]
 [4 5 6]]
A^T =
[[1 4]
 [2 5]
 [3 6]]
(A^T)^T == A: True

Hadamard 积(逐点乘积) :矩阵 A \mathbf{A} A 和 B \mathbf{B} B 中对应的元素相乘。

C = A ⊙ B , C i j = A i j ⋅ B i j \mathbf{C} = \mathbf{A} \odot \mathbf{B},\quad C_{ij} = A_{ij} \cdot B_{ij} C=A⊙B,Cij=Aij⋅Bij

python 复制代码
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
C = A * B  # 逐元素相乘
print(f"Hadamard 积 A ⊙ B =\n{C}")

输出:

复制代码
Hadamard 积 A ⊙ B =
[[ 5 12]
 [21 32]]

标量与矩阵乘积 : c A c\mathbf{A} cA 的每个元素是 A \mathbf{A} A 的相应元素与 c 的乘积。

python 复制代码
A = np.array([[1, 2], [3, 4]])
c = 3
print(f"3 * A =\n{c * A}")

Kronecker 积 :如果 A ∈ R m × n \mathbf{A} \in \mathbb{R}^{m \times n} A∈Rm×n, B ∈ R p × q \mathbf{B} \in \mathbb{R}^{p \times q} B∈Rp×q,则 Kronecker 积为 m p × n q mp \times nq mp×nq 矩阵:

python 复制代码
A = np.array([[1, 2],
              [3, 4]])  # 2x2
B = np.array([[0, 5],
              [6, 7]])  # 2x2

C = np.kron(A, B)       # 4x4
print(f"Kronecker 积 (4x4):\n{C}")

输出:

复制代码
Kronecker 积 (4x4):
[[ 0  5  0 10]
 [ 6  7 12 14]
 [ 0 15  0 20]
 [18 21 24 28]]

外积(Outer Product) :两个向量 a ∈ R m \mathbf{a} \in \mathbb{R}^m a∈Rm 和 b ∈ R n \mathbf{b} \in \mathbb{R}^n b∈Rn 的外积是一个 m × n m \times n m×n 矩阵:

C = a b T , C i j = a i b j \mathbf{C} = \mathbf{a}\mathbf{b}^T,\quad C_{ij} = a_i b_j C=abT,Cij=aibj

python 复制代码
a = np.array([1, 2, 3])    # 3维列向量
b = np.array([4, 5])       # 2维列向量

C = np.outer(a, b)          # 外积:3x2矩阵
print(f"外积 a·b^T (3x2):\n{C}")

输出:

复制代码
外积 a·b^T (3x2):
[[ 4  5]
 [ 8 10]
 [12 15]]

向量化(Vectorization):将矩阵表示为一个列向量。

vec ( A ) = [ A 11 , . . . , A m 1 , A 12 , . . . , A m 2 , . . . , A 1 n , . . . , A m n ] T \text{vec}(\mathbf{A}) = [A_{11}, ..., A_{m1}, A_{12}, ..., A_{m2}, ..., A_{1n}, ..., A_{mn}]^T vec(A)=[A11,...,Am1,A12,...,Am2,...,A1n,...,Amn]T

python 复制代码
A = np.array([[1, 2, 3],
              [4, 5, 6]])
vec_A = A.flatten()  # 或 A.reshape(-1, order='F') 按列展开
print(f"矩阵 A:\n{A}")
print(f"向量化 (按行): {A.flatten()}")
print(f"向量化 (按列): {A.flatten('F')}")

输出:

复制代码
矩阵 A:
[[1 2 3]
 [4 5 6]]
向量化 (按行): [1 2 3 4 5 6]
向量化 (按列): [1 4 2 5 3 6]

迹(Trace) :方块矩阵 A \mathbf{A} A 的对角线元素之和。

tr ( A ) = ∑ i A i i \text{tr}(\mathbf{A}) = \sum_i A_{ii} tr(A)=i∑Aii

python 复制代码
A = np.array([[1, 2, 3],
              [4, 5, 6],
              [7, 8, 9]])
trace_A = np.trace(A)
print(f"tr(A) = {trace_A}")
print(f"手动验证: {A[0,0] + A[1,1] + A[2,2]}")

# tr(AB) = tr(BA)
B = np.array([[2, 1, 0],
              [1, 3, 2],
              [0, 2, 4]])
print(f"tr(AB) = {np.trace(A @ B):.1f}, tr(BA) = {np.trace(B @ A):.1f}, 相等: {np.allclose(np.trace(A @ B), np.trace(B @ A))}")

输出:

复制代码
tr(A) = 15
手动验证: 15
tr(AB) = 59.0, tr(BA) = 59.0, 相等: True

行列式(Determinant) :方块矩阵 A \mathbf{A} A 的行列式记为 det ⁡ ( A ) \det(\mathbf{A}) det(A) 或 ∣ A ∣ |\mathbf{A}| ∣A∣。

det ⁡ ( A ) = ∑ σ ∈ S n sgn ( σ ) ∏ i = 1 n A i , σ ( i ) \det(\mathbf{A}) = \sum_{\sigma \in S_n} \text{sgn}(\sigma) \prod_{i=1}^n A_{i,\sigma(i)} det(A)=σ∈Sn∑sgn(σ)i=1∏nAi,σ(i)

python 复制代码
A = np.array([[1, 2],
              [3, 4]])
det_A = np.linalg.det(A)
print(f"det(A) = {det_A}")

# 行列式为0表示矩阵不可逆
B = np.array([[1, 2],
              [2, 4]])  # 线性相关:B的第2行 = 2×第1行
det_B = np.linalg.det(B)
print(f"det(B) = {det_B:.10f}, 不可逆: {abs(det_B) < 1e-10}")

输出:

复制代码
det(A) = -2.0000000000000004
det(B) = 0.0000000000, 不可逆: True

秩(Rank):矩阵的列秩和行秩总是相等,简称为秩。

rank ( A ) ≤ min ⁡ ( m , n ) \text{rank}(\mathbf{A}) \le \min(m, n) rank(A)≤min(m,n)

rank ( A B ) ≤ min ⁡ ( rank ( A ) , rank ( B ) ) \text{rank}(\mathbf{A}\mathbf{B}) \le \min(\text{rank}(\mathbf{A}), \text{rank}(\mathbf{B})) rank(AB)≤min(rank(A),rank(B))

python 复制代码
A = np.array([[1, 2, 3],
              [4, 5, 6],
              [7, 8, 9]])  # 第3行 = 2×第2行 - 第1行

rank_A = np.linalg.matrix_rank(A)
print(f"rank(A) = {rank_A}, 满秩: {rank_A == min(A.shape)}")

B = np.array([[1, 0, 0],
              [0, 1, 0],
              [0, 0, 1]])
rank_B = np.linalg.matrix_rank(B)
print(f"rank(B) = {rank_B}, 满秩: {rank_B == min(B.shape)}")

输出:

复制代码
rank(A) = 2, 满秩: False
rank(B) = 3, 满秩: True

矩阵范数

∥ A ∥ F = ∑ i , j A i j 2 \|\mathbf{A}\|F = \sqrt{\sum{i,j} A_{ij}^2} ∥A∥F=i,j∑Aij2

python 复制代码
A = np.array([[1, 2],
              [3, 4]])

frobenius = np.linalg.norm(A, ord='fro')
print(f"Frobenius 范数: {frobenius:.4f}")
print(f"手动计算: {np.sqrt(np.sum(A**2)):.4f}")

输出:

复制代码
Frobenius 范数: 5.4772
手动计算: 5.4772

A.2.4 矩阵类型

对称矩阵 : A = A T \mathbf{A} = \mathbf{A}^T A=AT

python 复制代码
A = np.array([[1, 2, 3],
              [2, 4, 5],
              [3, 5, 6]])
print(f"对称: {np.allclose(A, A.T)}")

输出:

复制代码
对称: True

对角矩阵 :主对角线之外的元素皆为 0 的矩阵。一个对角矩阵也可以记为 A = diag ( a ) \mathbf{A} = \text{diag}(\mathbf{a}) A=diag(a)。

A x = diag ( a ) x = a ⊙ x \mathbf{A}\mathbf{x} = \text{diag}(\mathbf{a})\mathbf{x} = \mathbf{a} \odot \mathbf{x} Ax=diag(a)x=a⊙x

python 复制代码
a = np.array([1, 2, 3])
A = np.diag(a)
x = np.array([4, 5, 6])

print(f"对角矩阵 diag([1,2,3]):\n{A}")
print(f"diag(a)·x = {A @ x}")
print(f"a ⊙ x = {a * x}")  # 等价于逐元素乘积

输出:

复制代码
对角矩阵 diag([1,2,3]):
[[1 0 0]
 [0 2 0]
 [0 0 3]]
diag(a)·x = [ 4 10 18]
a ⊙ x = [ 4 10 18]

单位矩阵 :主对角线元素为 1 的对角矩阵。 A I = I A = A \mathbf{A}\mathbf{I} = \mathbf{I}\mathbf{A} = \mathbf{A} AI=IA=A

python 复制代码
I = np.eye(3)
A = np.array([[1, 2, 3],
              [4, 5, 6],
              [7, 8, 9]])
print(f"A·I == A: {np.allclose(A @ I, A)}")
print(f"I·A == A: {np.allclose(I @ A, A)}")

输出:

复制代码
A·I == A: True
I·A == A: True

逆矩阵 :对于方块矩阵 A \mathbf{A} A,若存在 A − 1 \mathbf{A}^{-1} A−1 使得:

A A − 1 = A − 1 A = I \mathbf{A}\mathbf{A}^{-1} = \mathbf{A}^{-1}\mathbf{A} = \mathbf{I} AA−1=A−1A=I

则 A − 1 \mathbf{A}^{-1} A−1 称为 A \mathbf{A} A 的逆矩阵。

python 复制代码
A = np.array([[1, 2],
              [3, 4]])
A_inv = np.linalg.inv(A)

print(f"A =\n{A}")
print(f"A^(-1) =\n{A_inv}")
print(f"A·A^(-1) =\n{A @ A_inv}")

# 行列式为0的矩阵不可逆
B = np.array([[1, 2],
              [2, 4]])
try:
    B_inv = np.linalg.inv(B)
except np.linalg.LinAlgError:
    print("\ndet(B)=0, B不可逆")

输出:

复制代码
A =
[[1 2]
 [3 4]]
A^(-1) =
[[-2.   1. ]
 [ 1.5 -0.5]]
A·A^(-1) =
[[1.00000000e+00 0.00000000e+00]
 [8.88178420e-16 1.00000000e+00]]

det(B)=0, B不可逆

正定矩阵 :对于对称矩阵 A \mathbf{A} A,如果对于所有非零向量 x \mathbf{x} x,都满足 x T A x > 0 \mathbf{x}^T\mathbf{A}\mathbf{x} > 0 xTAx>0,则 A \mathbf{A} A 为正定矩阵。

python 复制代码
A = np.array([[2, 1],
              [1, 2]])

# 检查正定性:所有特征值大于0
eigenvalues = np.linalg.eigvals(A)
print(f"特征值: {eigenvalues}")
print(f"正定: {np.all(eigenvalues > 0)}")

# 对任意向量x验证
x = np.array([1, -1])
quad_form = x @ A @ x
print(f"x^T·A·x = {quad_form} (> 0: {quad_form > 0})")

输出:

复制代码
特征值: [3. 1.]
正定: True
x^T·A·x = 2 (> 0: True)

正交矩阵 : A − 1 = A T \mathbf{A}^{-1} = \mathbf{A}^T A−1=AT,即 A T A = I \mathbf{A}^T\mathbf{A} = \mathbf{I} ATA=I。

python 复制代码
# 旋转矩阵是正交矩阵
theta = np.pi / 4  # 45度
A = np.array([[np.cos(theta), -np.sin(theta)],
              [np.sin(theta),  np.cos(theta)]])
print(f"A^T·A = I: {np.allclose(A.T @ A, np.eye(2))}")
print(f"列向量模长=1: {np.linalg.norm(A[:, 0]):.6f}")
print(f"列向量互相正交: {np.dot(A[:, 0], A[:, 1]):.10f}")

输出:

复制代码
A^T·A = I: True
列向量模长=1: 1.000000
列向量互相正交: 0.0000000000

Gram 矩阵 :向量组 x 1 , . . . , x k \mathbf{x}_1, ..., \mathbf{x}k x1,...,xk 的 Gram 矩阵 G \mathbf{G} G 满足 G i j = ⟨ x i , x j ⟩ G{ij} = \langle \mathbf{x}_i, \mathbf{x}_j \rangle Gij=⟨xi,xj⟩。

python 复制代码
X = np.array([[1, 2],
              [3, 4],
              [5, 6]])  # 3个2维向量
G = X @ X.T  # Gram矩阵
print(f"Gram 矩阵:\n{G}")

输出:

复制代码
Gram 矩阵:
[[ 5 11 17]
 [11 25 39]
 [17 39 61]]

A.2.5 特征值与特征向量

对一个 n × n n \times n n×n 矩阵 A \mathbf{A} A,如果存在标量 λ \lambda λ 和非零向量 v \mathbf{v} v 满足:

A v = λ v \mathbf{A}\mathbf{v} = \lambda\mathbf{v} Av=λv

则 λ \lambda λ 和 v \mathbf{v} v 分别称为矩阵 A \mathbf{A} A 的特征值和特征向量。

python 复制代码
A = np.array([[4, 1],
              [2, 3]])

eigenvalues, eigenvectors = np.linalg.eig(A)

print(f"矩阵 A =\n{A}\n")
for i in range(len(eigenvalues)):
    λ = eigenvalues[i]
    v = eigenvectors[:, i]
    print(f"特征值 λ{i+1} = {λ:.4f}")
    print(f"特征向量 v{i+1} = {v}")
    print(f"验证: A·v = {A @ v}, λ·v = {λ * v}")
    print(f"相等: {np.allclose(A @ v, λ * v)}\n")

输出:

复制代码
矩阵 A =
[[4 1]
 [2 3]]

特征值 λ1 = 5.0000
特征向量 v1 = [0.70710678 0.70710678]
验证: A·v = [3.53553391 3.53553391], λ·v = [3.53553391 3.53553391]
相等: True

特征值 λ2 = 2.0000
特征向量 v2 = [-0.4472136   0.89442719]
验证: A·v = [-0.89442719  1.78885438], λ·v = [-0.89442719  1.78885438]
相等: True

对于实对称矩阵,存在 n 个互相正交的单位特征向量:

python 复制代码
# 实对称矩阵
A_sym = np.array([[2, 1],
                  [1, 2]])
evals, evecs = np.linalg.eigh(A_sym)  # 使用 eigh 更适合对称矩阵
print(f"特征值: {evals}")
print(f"特征向量正交: {np.allclose(np.dot(evecs[:, 0], evecs[:, 1]), 0)}")

输出:

复制代码
特征值: [1. 3.]
特征向量正交: True

A.2.6 矩阵分解

A.2.6.1 特征分解(Eigendecomposition)

一个 n × n n \times n n×n 方块矩阵 A \mathbf{A} A 的特征分解定义为:

A = Q Λ Q − 1 \mathbf{A} = \mathbf{Q}\mathbf{\Lambda}\mathbf{Q}^{-1} A=QΛQ−1

其中 Q \mathbf{Q} Q 的每一列为 A \mathbf{A} A 的特征向量, Λ \mathbf{\Lambda} Λ 为对角矩阵,对角元素为特征值。

如果 A \mathbf{A} A 为实对称矩阵,可分解为:

A = Q Λ Q T \mathbf{A} = \mathbf{Q}\mathbf{\Lambda}\mathbf{Q}^T A=QΛQT

其中 Q \mathbf{Q} Q 为正交矩阵。

python 复制代码
A = np.array([[4, 1],
              [2, 3]])

eigenvalues, eigenvectors = np.linalg.eig(A)
Λ = np.diag(eigenvalues)
Q = eigenvectors

# 验证 A = Q·Λ·Q^{-1}
A_reconstructed = Q @ Λ @ np.linalg.inv(Q)
print(f"A 重建后:\n{A_reconstructed}")
print(f"与原矩阵相等: {np.allclose(A, A_reconstructed)}")

# 对称矩阵的情况
A_sym = np.array([[2, 1],
                  [1, 2]])
evals, evecs = np.linalg.eigh(A_sym)
A_recon_sym = evecs @ np.diag(evals) @ evecs.T
print(f"\n对称矩阵分解 A=QΛQ^T 成立: {np.allclose(A_sym, A_recon_sym)}")

输出:

复制代码
A 重建后:
[[4. 1.]
 [2. 3.]]
与原矩阵相等: True

对称矩阵分解 A=QΛQ^T 成立: True
A.2.6.2 奇异值分解(SVD)

一个 m × n m \times n m×n 矩阵 A \mathbf{A} A 的奇异值分解定义为:

A = U Σ V T \mathbf{A} = \mathbf{U}\mathbf{\Sigma}\mathbf{V}^T A=UΣVT

其中 U ∈ R m × m \mathbf{U} \in \mathbb{R}^{m \times m} U∈Rm×m 和 V ∈ R n × n \mathbf{V} \in \mathbb{R}^{n \times n} V∈Rn×n 为正交矩阵, Σ ∈ R m × n \mathbf{\Sigma} \in \mathbb{R}^{m \times n} Σ∈Rm×n 为矩形对角矩阵。

python 复制代码
A = np.array([[1, 2, 3],
              [4, 5, 6],
              [7, 8, 9],
              [10,11,12]])  # 4x3矩阵

U, S, Vt = np.linalg.svd(A, full_matrices=True)

print(f"A (4x3):\n{A}\n")
print(f"U (4x4):\n{U}\n")
print(f"奇异值 S: {S}\n")
print(f"V^T (3x3):\n{Vt}\n")

# 验证 A = U·Σ·V^T
Σ = np.zeros((4, 3))
np.fill_diagonal(Σ, S)
A_recon = U @ Σ @ Vt
print(f"重建相等: {np.allclose(A, A_recon)}")

# 紧凑SVD (Compact SVD): A = U_r · Σ_r · V_r^T
# 其中 r = rank(A)
r = np.linalg.matrix_rank(A)
U_r = U[:, :r]
Σ_r = np.diag(S[:r])
V_r = Vt[:r, :].T
A_compact = U_r @ Σ_r @ V_r.T
print(f"紧凑SVD相等: {np.allclose(A, A_compact)}")
print(f"紧凑SVD节省空间: U_r={U_r.shape}, Σ_r={Σ_r.shape}, V_r={V_r.shape}")

# 截断SVD (Truncated SVD) - 只保留k个最大奇异值
k = 2
U_k = U[:, :k]
Σ_k = np.diag(S[:k])
V_k = Vt[:k, :].T
A_truncated = U_k @ Σ_k @ V_k.T
error = np.linalg.norm(A - A_truncated, ord='fro')
print(f"\n截断SVD (k={k}) Frobenius误差: {error:.4f}")
print(f"截断后矩阵:\n{A_truncated}")

输出:

复制代码
奇异值 S: [25.46240744  1.29066168  0.        ]

重建相等: True
紧凑SVD相等: True
紧凑SVD节省空间: U_r=(4, 2), Σ_r=(2, 2), V_r=(3, 2)

截断SVD (k=2) Frobenius误差: 0.0000
截断后矩阵: (近似重建,误差很小)

附录 B 微积分

微积分(Calculus)是研究函数的微分(Differentiation)、积分(Integration)及其相关应用的数学分支。

B.1 微分

B.1.1 导数

函数 f ( x ) f(x) f(x) 在点 x 0 x_0 x0 处的导数定义为:

f ′ ( x 0 ) = lim ⁡ Δ x → 0 f ( x 0 + Δ x ) − f ( x 0 ) Δ x f'(x_0) = \lim_{\Delta x \to 0} \frac{f(x_0 + \Delta x) - f(x_0)}{\Delta x} f′(x0)=Δx→0limΔxf(x0+Δx)−f(x0)

常函数、幂函数、指数函数、对数函数的导数如下:

函数类型 函数形式 导数
常函数 f ( x ) = c f(x)=c f(x)=c f ′ ( x ) = 0 f'(x)=0 f′(x)=0
幂函数 f ( x ) = x a f(x)=x^a f(x)=xa f ′ ( x ) = a x a − 1 f'(x)=ax^{a-1} f′(x)=axa−1
指数函数 f ( x ) = e x f(x)=e^x f(x)=ex f ′ ( x ) = e x f'(x)=e^x f′(x)=ex
对数函数 f ( x ) = ln ⁡ x f(x)=\ln x f(x)=lnx f ′ ( x ) = 1 / x f'(x)=1/x f′(x)=1/x
python 复制代码
import sympy as sp

x = sp.Symbol('x')

# 定义函数
funcs = {
    '常函数 f(x)=5': 5,
    '幂函数 f(x)=x³': x**3,
    '指数函数 f(x)=e^x': sp.exp(x),
    '对数函数 f(x)=ln(x)': sp.log(x),
}

print("函数及其导数:")
for name, f in funcs.items():
    f_prime = sp.diff(f, x)
    print(f"  {name}: f'(x) = {f_prime}")

# 具体点的导数值
x0 = 2
f = x**3
f_prime = sp.diff(f, x)
print(f"\nf(x)=x³ 在 x=2 处的导数: {float(f_prime.subs(x, x0))}")

输出:

复制代码
函数及其导数:
  常函数 f(x)=5: f'(x) = 0
  幂函数 f(x)=x³: f'(x) = 3*x**2
  指数函数 f(x)=e^x: f'(x) = exp(x)
  对数函数 f(x)=ln(x): f'(x) = 1/x

f(x)=x³ 在 x=2 处的导数: 12.0

高阶导数 :对导数继续求导得到高阶导数。如 f ′ ′ ( x ) f''(x) f′′(x) 为二阶导数。

python 复制代码
x = sp.Symbol('x')
f = x**4 + 2*x**3 + x**2

print(f"f(x) = {f}")
for order in range(1, 5):
    f_n = sp.diff(f, x, order)  # n阶导数
    print(f"f^({order})(x) = {f_n}")

输出:

复制代码
f(x) = x**4 + 2*x**3 + x**2
f^(1)(x) = 4*x**3 + 6*x**2 + 2*x
f^(2)(x) = 12*x**2 + 12*x + 2
f^(3)(x) = 24*x + 12
f^(4)(x) = 24

偏导数 :多元函数 f ( x 1 , x 2 , . . . , x n ) f(x_1, x_2, ..., x_n) f(x1,x2,...,xn) 关于变量 x i x_i xi 的导数:

∂ f ∂ x i = lim ⁡ h → 0 f ( . . . , x i + h , . . . ) − f ( . . . , x i , . . . ) h \frac{\partial f}{\partial x_i} = \lim_{h \to 0} \frac{f(..., x_i+h, ...)-f(..., x_i, ...)}{h} ∂xi∂f=h→0limhf(...,xi+h,...)−f(...,xi,...)

python 复制代码
x, y = sp.symbols('x y')
f = x**3 + 2*x*y + y**2

df_dx = sp.diff(f, x)   # 对x的偏导
df_dy = sp.diff(f, y)   # 对y的偏导

print(f"f(x,y) = {f}")
print(f"∂f/∂x = {df_dx}")
print(f"∂f/∂y = {df_dy}")

# 二阶偏导数
d2f_dx2 = sp.diff(f, x, 2)       # ∂²f/∂x²
d2f_dxdy = sp.diff(df_dx, y)     # ∂²f/∂x∂y (先x后y)

print(f"∂²f/∂x² = {d2f_dx2}")
print(f"∂²f/∂x∂y = {d2f_dxdy}")

输出:

复制代码
f(x,y) = x**3 + 2*x*y + y**2
∂f/∂x = 3*x**2 + 2*y
∂f/∂y = 2*x + 2*y
∂²f/∂x² = 6*x
∂²f/∂x∂y = 2

B.1.2 微分

可微函数一定连续,但连续函数不一定可微。例如 f ( x ) = ∣ x ∣ f(x) = |x| f(x)=∣x∣ 在 x = 0 x=0 x=0 处不可导。

python 复制代码
# 数值微分:使用中心差分法近似
def numerical_derivative(f, x, h=1e-5):
    """中心差分法求数值导数"""
    return (f(x + h) - f(x - h)) / (2 * h)

# 测试可微函数
f1 = lambda x: x**2
x0 = 3.0
actual = 2 * x0  # 精确导数 f'(x)=2x
numerical = numerical_derivative(f1, x0)
print(f"f(x)=x² 在 x=3:")
print(f"  精确导数: {actual}")
print(f"  数值导数: {numerical:.6f}")

# |x| 在 x=0 处不可导
f2 = lambda x: abs(x)
df_plus = numerical_derivative(f2, 0.001)
df_minus = numerical_derivative(f2, -0.001)
print(f"\nf(x)=|x|:")
print(f"  x=0.001 处导数的近似: {df_plus:.4f}")
print(f"  x=-0.001 处导数的近似: {df_minus:.4f}")
print(f"  左右导数不同,说明 x=0 处不可导")

输出:

复制代码
f(x)=x² 在 x=3:
  精确导数: 6.0
  数值导数: 6.000000

f(x)=|x|:
  x=0.001 处导数近似: 1.0000
  x=-0.001 处导数近似: -1.0000
  左右导数不同,说明 x=0 处不可导

B.1.3 泰勒公式

函数 f ( x ) f(x) f(x) 在 x 0 x_0 x0 处的 n 阶泰勒展开式:

f ( x ) = ∑ k = 0 n f ( k ) ( x 0 ) k ! ( x − x 0 ) k + R n ( x ) f(x) = \sum_{k=0}^n \frac{f^{(k)}(x_0)}{k!}(x - x_0)^k + R_n(x) f(x)=k=0∑nk!f(k)(x0)(x−x0)k+Rn(x)

其中 R n ( x ) R_n(x) Rn(x) 是泰勒公式的余项,是 ( x − x 0 ) n (x - x_0)^n (x−x0)n 的高阶无穷小。

python 复制代码
x, x0 = sp.symbols('x x0')
f = sp.sin(x)

# 在 x0=0 处的泰勒展开(即麦克劳林展开)
for n in [1, 3, 5, 7]:
    taylor = sp.series(f, x, 0, n+1).removeO()
    print(f"{n}阶泰勒展开: sin(x) ≈ {taylor}")

# 可视化泰勒逼近
import numpy as np

def taylor_sin(x, n):
    """计算 sin(x) 的 n 阶泰勒逼近"""
    result = 0
    for k in range(n+1):
        if k % 2 == 0:
            continue  # sin的展开只有奇数项
        term = (-1)**((k-1)//2) * x**k / np.math.factorial(k)
        result += term
    return result

x_vals = np.linspace(-np.pi, np.pi, 200)
true_vals = np.sin(x_vals)

fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(x_vals, true_vals, 'k-', linewidth=2, label='sin(x) 精确值')
for n, style in [(1, '--'), (3, '-.'), (5, ':'), (9, '-')]:
    approx = taylor_sin(x_vals, n)
    ax.plot(x_vals, approx, style, linewidth=1.5, label=f'{n}阶逼近')
ax.legend()
ax.set_xlabel('x')
ax.set_ylabel('f(x)')
ax.set_title('sin(x) 的泰勒展开逼近')
ax.grid(True)
plt.show()

B.2 积分

积分是微分的逆过程。

函数 f ( x ) f(x) f(x) 的不定积分(原函数)记为:

∫ f ( x )   d x = F ( x ) + C \int f(x)\,dx = F(x) + C ∫f(x)dx=F(x)+C

其中 F ′ ( x ) = f ( x ) F'(x) = f(x) F′(x)=f(x)。

定积分(黎曼积分)定义为:

∫ a b f ( x )   d x = lim ⁡ max ⁡ Δ x i → 0 ∑ i = 1 n f ( ξ i ) Δ x i \int_a^b f(x)\,dx = \lim_{\max\Delta x_i \to 0} \sum_{i=1}^n f(\xi_i)\Delta x_i ∫abf(x)dx=maxΔxi→0limi=1∑nf(ξi)Δxi

python 复制代码
# 符号积分
x = sp.Symbol('x')
a = sp.Symbol('a', positive=True)

# 不定积分
funcs = [x**3, sp.exp(x), 1/x, sp.sin(x)]
for f in funcs:
    F = sp.integrate(f, x)
    print(f"∫ {f} dx = {F} + C")

# 定积分
b = sp.Symbol('b', positive=True)
f = sp.exp(-x)
result = sp.integrate(f, (x, 0, b))
print(f"\n∫_0^b e^(-x) dx = {result}")

# 具体定积分
result_specific = sp.integrate(sp.exp(-x), (x, 0, sp.oo))  # 从0到∞
print(f"∫_0^∞ e^(-x) dx = {result_specific}")

输出:

复制代码
∫ x**3 dx = x**4/4 + C
∫ exp(x) dx = exp(x) + C
∫ 1/x dx = log(x) + C
∫ sin(x) dx = -cos(x) + C

∫_0^b e^(-x) dx = 1 - exp(-b)
∫_0^∞ e^(-x) dx = 1
python 复制代码
# 数值积分
from scipy.integrate import quad

# 定积分 ∫_0^π sin(x) dx
result, error = quad(lambda x: np.sin(x), 0, np.pi)
print(f"∫_0^π sin(x) dx = {result:.6f} (精确值: 2)")

# 正态分布的概率密度积分
result, error = quad(lambda x: (1/np.sqrt(2*np.pi)) * np.exp(-x**2/2), -1.96, 1.96)
print(f"标准正态分布 P(-1.96 < X < 1.96) = {result:.6f}")

输出:

复制代码
∫_0^π sin(x) dx = 2.000000 (精确值: 2)
标准正态分布 P(-1.96 < X < 1.96) = 0.950004

B.3 矩阵微积分

矩阵微积分是多元微积分的一种表达方式,使用矩阵和向量来表示偏导数。本书采用分母布局

标量关于向量的偏导数

对于 n 维向量 x ∈ R n \mathbf{x} \in \mathbb{R}^n x∈Rn 和函数 f : R n → R f: \mathbb{R}^n \to \mathbb{R} f:Rn→R:

  • 分母布局(列向量形式)

∂ f ∂ x = [ ∂ f ∂ x 1 , ∂ f ∂ x 2 , . . . , ∂ f ∂ x n ] T \frac{\partial f}{\partial \mathbf{x}} = \left[\frac{\partial f}{\partial x_1}, \frac{\partial f}{\partial x_2}, ..., \frac{\partial f}{\partial x_n}\right]^T ∂x∂f=[∂x1∂f,∂x2∂f,...,∂xn∂f]T

  • 分子布局(行向量形式)

∂ f ∂ x = [ ∂ f ∂ x 1 , ∂ f ∂ x 2 , . . . , ∂ f ∂ x n ] \frac{\partial f}{\partial \mathbf{x}} = \left[\frac{\partial f}{\partial x_1}, \frac{\partial f}{\partial x_2}, ..., \frac{\partial f}{\partial x_n}\right] ∂x∂f=[∂x1∂f,∂x2∂f,...,∂xn∂f]

python 复制代码
# 符号计算梯度
x1, x2, x3 = sp.symbols('x1 x2 x3')
f = x1**2 + 2*x1*x2 + x2**2 + x3**3

# 计算梯度(分母布局)
grad = sp.Matrix([sp.diff(f, var) for var in (x1, x2, x3)])
print(f"f(x) = {f}")
print(f"梯度 (分母布局):\n{grad}")

# 数值计算梯度
x = np.array([1.0, 2.0, 3.0])
grad_val = np.array([2*x[0] + 2*x[1], 2*x[0] + 2*x[1], 3*x[2]**2])
print(f"在 x={x} 处的梯度: {grad_val}")

输出:

复制代码
f(x) = x1**2 + 2*x1*x2 + x2**2 + x3**3
梯度 (分母布局):
Matrix([[2*x1 + 2*x2], [2*x1 + 2*x2], [3*x3**2]])
在 x=[1. 2. 3.] 处的梯度: [ 6.  6. 27.]

向量关于向量的偏导数(雅可比矩阵)

对于 f : R n → R m \mathbf{f}: \mathbb{R}^n \to \mathbb{R}^m f:Rn→Rm,雅可比矩阵(分母布局)为 n × m n \times m n×m 矩阵:

∂ f ∂ x = [ ∂ f 1 ∂ x 1 ⋯ ∂ f m ∂ x 1 ⋮ ⋱ ⋮ ∂ f 1 ∂ x n ⋯ ∂ f m ∂ x n ] \frac{\partial \mathbf{f}}{\partial \mathbf{x}} = \begin{bmatrix} \frac{\partial f_1}{\partial x_1} & \cdots & \frac{\partial f_m}{\partial x_1} \\ \vdots & \ddots & \vdots \\ \frac{\partial f_1}{\partial x_n} & \cdots & \frac{\partial f_m}{\partial x_n} \end{bmatrix} ∂x∂f= ∂x1∂f1⋮∂xn∂f1⋯⋱⋯∂x1∂fm⋮∂xn∂fm

Hessian 矩阵

对于 f : R n → R f: \mathbb{R}^n \to \mathbb{R} f:Rn→R,Hessian 矩阵为 n × n n \times n n×n 矩阵:

H f = ∂ 2 f ∂ x ∂ x T = [ ∂ 2 f ∂ x 1 2 ⋯ ∂ 2 f ∂ x 1 ∂ x n ⋮ ⋱ ⋮ ∂ 2 f ∂ x n ∂ x 1 ⋯ ∂ 2 f ∂ x n 2 ] \mathbf{H}_f = \frac{\partial^2 f}{\partial \mathbf{x}\partial \mathbf{x}^T} = \begin{bmatrix} \frac{\partial^2 f}{\partial x_1^2} & \cdots & \frac{\partial^2 f}{\partial x_1\partial x_n} \\ \vdots & \ddots & \vdots \\ \frac{\partial^2 f}{\partial x_n\partial x_1} & \cdots & \frac{\partial^2 f}{\partial x_n^2} \end{bmatrix} Hf=∂x∂xT∂2f= ∂x12∂2f⋮∂xn∂x1∂2f⋯⋱⋯∂x1∂xn∂2f⋮∂xn2∂2f

python 复制代码
x1, x2 = sp.symbols('x1 x2')
f = x1**2 + x1*x2 + x2**2

# 梯度
grad = sp.Matrix([sp.diff(f, x1), sp.diff(f, x2)])
print(f"f(x) = {f}")
print(f"梯度:\n{grad}")

# Hessian矩阵
hessian = sp.hessian(f, (x1, x2))
print(f"\nHessian矩阵:\n{hessian}")

# 在具体点求值
point = {x1: 1, x2: 2}
print(f"\n在 (x1=1, x2=2) 处:")
print(f"  梯度值: {[float(grad[i].subs(point)) for i in range(2)]}")
print(f"  Hessian值:\n{np.array(hessian.subs(point)).astype(float)}")

输出:

复制代码
f(x) = x1**2 + x1*x2 + x2**2
梯度:
Matrix([[2*x1 + x2], [x1 + 2*x2]])

Hessian矩阵:
Matrix([[2, 1], [1, 2]])

在 (x1=1, x2=2) 处:
  梯度值: [4.0, 5.0]
  Hessian值:
[[2. 1.]
 [1. 2.]]

B.3.1 导数法则

加(减)法则 :若 x ∈ R n x \in \mathbb{R}^n x∈Rn, a , b ∈ R n \mathbf{a}, \mathbf{b} \in \mathbb{R}^n a,b∈Rn, f ( x ) = a T x ± b T x f(\mathbf{x}) = \mathbf{a}^T\mathbf{x} \pm \mathbf{b}^T\mathbf{x} f(x)=aTx±bTx,则:

∂ f ∂ x = a ± b \frac{\partial f}{\partial \mathbf{x}} = \mathbf{a} \pm \mathbf{b} ∂x∂f=a±b

乘法法则

  1. 若 f ( x ) = x T A x f(\mathbf{x}) = \mathbf{x}^T\mathbf{A}\mathbf{x} f(x)=xTAx,其中 A \mathbf{A} A 与 x \mathbf{x} x 无关,则:

∂ f ∂ x = ( A + A T ) x \frac{\partial f}{\partial \mathbf{x}} = (\mathbf{A} + \mathbf{A}^T)\mathbf{x} ∂x∂f=(A+AT)x

  1. 若 A \mathbf{A} A 对称,则 ∂ f ∂ x = 2 A x \frac{\partial f}{\partial \mathbf{x}} = 2\mathbf{A}\mathbf{x} ∂x∂f=2Ax
python 复制代码
# 验证乘法法则
n = 3
x = np.array([1.0, 2.0, 3.0])
A = np.array([[2, 1, 0],
              [1, 3, 1],
              [0, 1, 2]])  # 对称矩阵

# f(x) = x^T·A·x
f = x @ A @ x
print(f"f(x) = x^T·A·x = {f:.4f}")

# 梯度 ∂f/∂x = 2Ax (A对称时)
grad = 2 * A @ x
print(f"梯度 ∂f/∂x = 2Ax = {grad}")

# 数值验证
h = 1e-5
grad_num = np.zeros(n)
for i in range(n):
    x_plus = x.copy()
    x_plus[i] += h
    f_plus = x_plus @ A @ x_plus
    grad_num[i] = (f_plus - f) / h
print(f"数值梯度: {grad_num}")
print(f"解析梯度 ≈ 数值梯度: {np.allclose(grad, grad_num, atol=1e-4)}")

输出:

复制代码
f(x) = x^T·A·x = 41.0000
梯度 ∂f/∂x = 2Ax = [ 8. 22. 14.]
数值梯度: [ 8.00001 22.00001 14.00001]
解析梯度 ≈ 数值梯度: True

链式法则

若 x → y → z \mathbf{x} \to \mathbf{y} \to z x→y→z( y = g ( x ) \mathbf{y} = g(\mathbf{x}) y=g(x), z = f ( y ) z = f(\mathbf{y}) z=f(y)),则:

∂ z ∂ x = ∂ y ∂ x ⋅ ∂ z ∂ y \frac{\partial z}{\partial \mathbf{x}} = \frac{\partial \mathbf{y}}{\partial \mathbf{x}} \cdot \frac{\partial z}{\partial \mathbf{y}} ∂x∂z=∂x∂y⋅∂y∂z

python 复制代码
# 链式法则验证
# z = ||Wx||²,其中 y = Wx, z = ||y||²
W = np.array([[1, 2],
              [3, 4],
              [5, 6]])  # 3x2
x = np.array([2, 3])    # 2维

# 前向计算
y = W @ x               # 3维
z = np.sum(y**2)        # 标量

# 链式法则: ∂z/∂x = ∂z/∂y · ∂y/∂x
# ∂z/∂y = 2y (分母布局,列向量)
# ∂y/∂x = W^T (分母布局)
dz_dy = 2 * y           # 3维列向量
dy_dx = W               # 3x2矩阵,∂y/∂x = W^T (分母布局) 
# 分母布局: ∂z/∂x = (∂y/∂x) · (∂z/∂y) = W^T · (2y)
dz_dx = W.T @ dz_dy     # 2维

print(f"链式法则计算的梯度: {dz_dx}")

# 数值验证
h = 1e-5
dz_dx_num = np.zeros(2)
for i in range(2):
    x_plus = x.copy()
    x_plus[i] += h
    y_plus = W @ x_plus
    z_plus = np.sum(y_plus**2)
    dz_dx_num[i] = (z_plus - z) / h
print(f"数值梯度: {dz_dx_num}")

输出:

复制代码
链式法则计算的梯度: [856 1192]
数值梯度: [856.000035 1192.000044]

B.4 常见函数的导数

B.4.1 向量函数及其导数

∂ x ∂ x = I \frac{\partial \mathbf{x}}{\partial \mathbf{x}} = \mathbf{I} ∂x∂x=I

∂ ∥ x ∥ 2 ∂ x = 2 x \frac{\partial \|\mathbf{x}\|^2}{\partial \mathbf{x}} = 2\mathbf{x} ∂x∂∥x∥2=2x

∂ ( a T x ) ∂ x = a \frac{\partial (\mathbf{a}^T\mathbf{x})}{\partial \mathbf{x}} = \mathbf{a} ∂x∂(aTx)=a

python 复制代码
# 验证常见导数公式
x = np.array([1.0, 2.0, 3.0])
a = np.array([3.0, 2.0, 1.0])

# 1. ∂x/∂x = I
print(f"∂x/∂x = I")

# 2. ∂||x||²/∂x = 2x
grad_norm2 = 2 * x
f = np.sum(x**2)
h = 1e-5
grad_num = np.array([(np.sum((x + h*np.eye(3)[i])**2) - f) / h for i in range(3)])
print(f"∂||x||²/∂x = {grad_norm2}")
print(f"数值验证:        {grad_num}")

# 3. ∂(a^T·x)/∂x = a
grad_linear = a
f2 = np.dot(a, x)
grad_num2 = np.array([(np.dot(a, x + h*np.eye(3)[i]) - f2) / h for i in range(3)])
print(f"\n∂(a^T·x)/∂x = {grad_linear}")
print(f"数值验证:        {grad_num2}")

输出:

复制代码
∂x/∂x = I
∂||x||²/∂x = [2. 4. 6.]
数值验证:        [1.99999 3.99999 5.99999]

∂(a^T·x)/∂x = [3. 2. 1.]
数值验证:        [3. 2. 1.]

B.4.2 Logistic 函数

标准 Logistic 函数(Sigmoid):

σ ( x ) = 1 1 + e − x \sigma(x) = \frac{1}{1 + e^{-x}} σ(x)=1+e−x1

导数:

σ ′ ( x ) = σ ( x ) ( 1 − σ ( x ) ) \sigma'(x) = \sigma(x)(1 - \sigma(x)) σ′(x)=σ(x)(1−σ(x))

当输入为 n 维向量 x \mathbf{x} x 时,其导数为对角矩阵:

∂ σ ( x ) ∂ x = diag ( σ ( x ) ⊙ ( 1 − σ ( x ) ) ) \frac{\partial \sigma(\mathbf{x})}{\partial \mathbf{x}} = \text{diag}(\sigma(\mathbf{x}) \odot (1 - \sigma(\mathbf{x}))) ∂x∂σ(x)=diag(σ(x)⊙(1−σ(x)))

python 复制代码
def sigmoid(x):
    return 1 / (1 + np.exp(-x))

def sigmoid_derivative(x):
    s = sigmoid(x)
    return s * (1 - s)

# 测试
x_val = np.linspace(-5, 5, 100)
s = sigmoid(x_val)
s_prime = sigmoid_derivative(x_val)

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))

ax1.plot(x_val, s, 'b-', linewidth=2)
ax1.set_title('Sigmoid 函数 σ(x)')
ax1.set_xlabel('x'); ax1.set_ylabel('σ(x)')
ax1.grid(True)
ax1.axhline(0.5, color='gray', linestyle='--', alpha=0.5)
ax1.axvline(0, color='gray', linestyle='--', alpha=0.5)

ax2.plot(x_val, s_prime, 'r-', linewidth=2)
ax2.set_title("Sigmoid 导数 σ'(x) = σ(x)(1-σ(x))")
ax2.set_xlabel('x'); ax2.set_ylabel("σ'(x)")
ax2.grid(True)

plt.tight_layout()
plt.show()

# 向量输入的导数(对角矩阵)
x_vec = np.array([-1.0, 0.0, 2.0])
s_vec = sigmoid(x_vec)
diag_derivative = np.diag(s_vec * (1 - s_vec))
print(f"x = {x_vec}")
print(f"σ(x) = {s_vec}")
print(f"导数对角矩阵:\n{diag_derivative}")

输出:

复制代码
x = [-1.  0.  2.]
σ(x) = [0.26894142 0.5        0.88079708]
导数对角矩阵:
[[0.19661193 0.         0.        ]
 [0.         0.25       0.        ]
 [0.         0.         0.10499359]]

B.4.3 Softmax 函数

对于 K 个标量 x 1 , . . . , x K x_1, ..., x_K x1,...,xK:

softmax ( x k ) = e x k ∑ j = 1 K e x j \text{softmax}(x_k) = \frac{e^{x_k}}{\sum_{j=1}^K e^{x_j}} softmax(xk)=∑j=1Kexjexk

∑ k = 1 K softmax ( x k ) = 1 \sum_{k=1}^K \text{softmax}(x_k) = 1 k=1∑Ksoftmax(xk)=1

向量形式: S ( x ) = e x 1 T e x \mathbf{S}(\mathbf{x}) = \frac{e^{\mathbf{x}}}{\mathbf{1}^T e^{\mathbf{x}}} S(x)=1Texex

导数(雅可比矩阵):

∂ S i ∂ x j = S i ( δ i j − S j ) \frac{\partial S_i}{\partial x_j} = S_i(\delta_{ij} - S_j) ∂xj∂Si=Si(δij−Sj)

其中 δ i j \delta_{ij} δij 是 Kronecker delta( i = j i=j i=j 时为 1,否则为 0)。

python 复制代码
def softmax(x):
    """数值稳定的 softmax 实现"""
    x_shifted = x - np.max(x)  # 防溢出
    exp_x = np.exp(x_shifted)
    return exp_x / np.sum(exp_x)

def softmax_derivative(x):
    """Softmax 的雅可比矩阵"""
    s = softmax(x).reshape(-1, 1)
    return np.diagflat(s) - s @ s.T

# 示例
x = np.array([2.0, 1.0, 0.1])
s = softmax(x)
print(f"x = {x}")
print(f"softmax(x) = {s}")
print(f"sum = {np.sum(s):.4f}")  # 应该为1

# 雅可比矩阵
J = softmax_derivative(x)
print(f"\n雅可比矩阵 (3x3):\n{J}")
print(f"每列和: {J.sum(axis=0)}")  # 应为0

输出:

复制代码
x = [2.  1.  0.1]
softmax(x) = [0.65900114 0.24243297 0.09856589]
sum = 1.0000

雅可比矩阵 (3x3):
[[ 0.22471878 -0.15976147 -0.06495731]
 [-0.15976147  0.1836591  -0.02389764]
 [-0.06495731 -0.02389764  0.08885495]]
每列和: [0. 0. 0.]

附录 C 数学优化

数学优化问题:给定目标函数 f : R n → R f: \mathbb{R}^n \to \mathbb{R} f:Rn→R,寻找变量 x ∗ \mathbf{x}^* x∗ 使得 f ( x ) f(\mathbf{x}) f(x) 在可行域内最小(或最大)。

C.1 数学优化的类型

  • 离散优化 vs 连续优化:输入变量是否为连续实数
  • 无约束优化 vs 约束优化:是否有等式或不等式约束
  • 线性优化 vs 非线性优化:目标函数和约束函数的线性性

凸函数 :满足 f ( θ x + ( 1 − θ ) y ) ≤ θ f ( x ) + ( 1 − θ ) f ( y ) f(\theta\mathbf{x} + (1-\theta)\mathbf{y}) \le \theta f(\mathbf{x}) + (1-\theta)f(\mathbf{y}) f(θx+(1−θ)y)≤θf(x)+(1−θ)f(y),其中 θ ∈ [ 0 , 1 ] \theta \in [0,1] θ∈[0,1]。

python 复制代码
# 凸函数示例
def f(x):
    return x**2

x = np.linspace(-3, 3, 100)
theta = 0.3
x1, x2 = -2, 2

fig, ax = plt.subplots(figsize=(8, 6))
ax.plot(x, f(x), 'b-', linewidth=2, label='f(x)=x²')
ax.scatter([x1, x2], [f(x1), f(x2)], c='red', s=80, zorder=5)
ax.scatter([theta*x1 + (1-theta)*x2], [f(theta*x1 + (1-theta)*x2)], 
           c='green', s=80, zorder=5, marker='s')
ax.scatter([theta*x1 + (1-theta)*x2], [theta*f(x1) + (1-theta)*f(x2)],
           c='orange', s=80, zorder=5, marker='^')

# 连线
ax.plot([x1, x2], [f(x1), f(x2)], 'r--', alpha=0.5)
ax.legend()
ax.set_title('凸函数:f(θx₁+(1-θ)x₂) ≤ θf(x₁)+(1-θ)f(x₂)')
ax.grid(True)
plt.show()

# 凸性验证
fx_interp = f(theta*x1 + (1-theta)*x2)  # f(θx₁+(1-θ)x₂)
interp_f = theta*f(x1) + (1-theta)*f(x2)  # θf(x₁)+(1-θ)f(x₂)
print(f"f(θx₁+(1-θ)x₂) = {fx_interp:.2f}")
print(f"θf(x₁)+(1-θ)f(x₂) = {interp_f:.2f}")
print(f"凸性满足: {fx_interp <= interp_f}")

输出:

复制代码
f(θx₁+(1-θ)x₂) = 0.64
θf(x₁)+(1-θ)f(x₂) = 4.00
凸性满足: True

C.2 优化算法

C.2.1 全局最小解和局部最小解

局部最小解 x ∗ \mathbf{x}^* x∗:存在 δ > 0 \delta > 0 δ>0,对于所有满足 ∥ x − x ∗ ∥ < δ \|\mathbf{x} - \mathbf{x}^*\| < \delta ∥x−x∗∥<δ 的 x \mathbf{x} x,都有 f ( x ∗ ) ≤ f ( x ) f(\mathbf{x}^*) \le f(\mathbf{x}) f(x∗)≤f(x)。

全局最小解 x ∗ \mathbf{x}^* x∗:对所有 x \mathbf{x} x,都有 f ( x ∗ ) ≤ f ( x ) f(\mathbf{x}^*) \le f(\mathbf{x}) f(x∗)≤f(x)。

局部最小解的判定条件

  1. 一阶必要条件 : ∇ f ( x ∗ ) = 0 \nabla f(\mathbf{x}^*) = 0 ∇f(x∗)=0
  2. 二阶必要条件 : ∇ f ( x ∗ ) = 0 \nabla f(\mathbf{x}^*) = 0 ∇f(x∗)=0 且 H f ( x ∗ ) \mathbf{H}_f(\mathbf{x}^*) Hf(x∗) 为半正定

C.2.2 梯度下降法

梯度下降法用于求解无约束优化的最小值问题。

迭代公式

x t + 1 = x t − α ∇ f ( x t ) \mathbf{x}_{t+1} = \mathbf{x}_t - \alpha \nabla f(\mathbf{x}_t) xt+1=xt−α∇f(xt)

其中 α \alpha α 为学习率(步长)。

python 复制代码
def gradient_descent(f, grad_f, x0, learning_rate=0.1, max_iter=100, tol=1e-6):
    """梯度下降法"""
    x = x0.copy()
    history = [x.copy()]
    
    for i in range(max_iter):
        g = grad_f(x)
        x_new = x - learning_rate * g
        history.append(x_new.copy())
        
        if np.linalg.norm(x_new - x) < tol:
            break
        x = x_new
    
    return x, np.array(history)

# 示例:f(x,y) = (x-3)² + (y+2)²,最小值在 (3, -2)
def f_2d(x):
    return (x[0] - 3)**2 + (x[1] + 2)**2

def grad_f_2d(x):
    return np.array([2*(x[0] - 3), 2*(x[1] + 2)])

x0 = np.array([0.0, 0.0])
x_opt, history = gradient_descent(f_2d, grad_f_2d, x0, learning_rate=0.3)

print(f"初始点: {x0}")
print(f"最优解: {x_opt}")
print(f"迭代次数: {len(history) - 1}")
print(f"最小值 f(x*) = {f_2d(x_opt):.6f}")

# 可视化优化路径
fig, ax = plt.subplots(figsize=(8, 7))
x_range = np.linspace(-1, 6, 50)
y_range = np.linspace(-5, 3, 50)
X, Y = np.meshgrid(x_range, y_range)
Z = (X - 3)**2 + (Y + 2)**2
contour = ax.contour(X, Y, Z, levels=20, cmap='viridis')
ax.clabel(contour, inline=True, fontsize=8)

ax.plot(history[:, 0], history[:, 1], 'r-o', markersize=5, linewidth=1.5, label='优化路径')
ax.scatter(*x0, c='blue', s=100, marker='s', label='起点', zorder=5)
ax.scatter(*x_opt, c='red', s=100, marker='*', label='终点', zorder=5)
ax.legend()
ax.set_xlabel('x'); ax.set_ylabel('y')
ax.set_title('梯度下降法优化路径')
ax.grid(True)
plt.show()

输出:

复制代码
初始点: [0. 0.]
最优解: [ 2.99999969 -1.99999849]
迭代次数: 27
最小值 f(x*) = 0.000000

学习率对收敛的影响

python 复制代码
# 不同学习率的效果
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
lrs = [0.01, 0.3, 1.2]

for ax, lr in zip(axes, lrs):
    _, history = gradient_descent(f_2d, grad_f_2d, x0, learning_rate=lr)
    ax.plot(history[:, 0], history[:, 1], 'r-o', markersize=4)
    ax.scatter(*x0, c='blue', s=60, marker='s', label='起点')
    ax.scatter(3, -2, c='green', s=60, marker='*', label='最优')
    ax.contour(X, Y, Z, levels=15, cmap='viridis', alpha=0.5)
    ax.set_title(f'学习率 α={lr}, 迭代{len(history)-1}次')
    ax.set_xlabel('x'); ax.set_ylabel('y')
    ax.legend()
    ax.grid(True)

plt.tight_layout()
plt.show()

C.3 拉格朗日乘数法与 KKT 条件

等式约束优化问题

对于等式约束优化问题:

min ⁡ x f ( x ) s.t. g ( x ) = 0 \min_{\mathbf{x}} f(\mathbf{x}) \quad \text{s.t.} \quad g(\mathbf{x}) = 0 xminf(x)s.t.g(x)=0

构造拉格朗日函数:

L ( x , λ ) = f ( x ) + λ g ( x ) \mathcal{L}(\mathbf{x}, \lambda) = f(\mathbf{x}) + \lambda g(\mathbf{x}) L(x,λ)=f(x)+λg(x)

最优解满足:

∇ x L = 0 , ∂ L ∂ λ = 0 \nabla_{\mathbf{x}}\mathcal{L} = 0, \quad \frac{\partial \mathcal{L}}{\partial \lambda} = 0 ∇xL=0,∂λ∂L=0

python 复制代码
# 用拉格朗日乘数法求解约束优化
# min f(x,y) = x² + y², s.t. x + y = 1
x, y, λ = sp.symbols('x y λ')

f = x**2 + y**2
g = x + y - 1
L = f + λ * g  # 拉格朗日函数

# 求驻点
eq1 = sp.diff(L, x)
eq2 = sp.diff(L, y)
eq3 = sp.diff(L, λ)

solution = sp.solve([eq1, eq2, eq3], [x, y, λ], dict=True)
print(f"拉格朗日函数: L = {L}")
print(f"驻点条件: ∂L/∂x=0, ∂L/∂y=0, ∂L/∂λ=0")
print(f"解: {solution}")
print(f"\n最优解: x* = {float(solution[0][x])}, y* = {float(solution[0][y])}")
print(f"λ* = {float(solution[0][λ])}")
print(f"最小值 f(x*,y*) = {float(f.subs({x: solution[0][x], y: solution[0][y]}))}")

输出:

复制代码
拉格朗日函数: L = x**2 + y**2 + λ*(x + y - 1)
驻点条件: ∂L/∂x=0, ∂L/∂y=0, ∂L/∂λ=0
解: [{x: 1/2, y: 1/2, λ: -1}]

最优解: x* = 0.5, y* = 0.5
λ* = -1.0
最小值 f(x*,y*) = 0.5

不等式约束优化问题

对于一般约束优化问题:

min ⁡ x f ( x ) s.t. g i ( x ) = 0 , h j ( x ) ≤ 0 \min_{\mathbf{x}} f(\mathbf{x}) \quad \text{s.t.} \quad g_i(\mathbf{x}) = 0,\ h_j(\mathbf{x}) \le 0 xminf(x)s.t.gi(x)=0, hj(x)≤0

拉格朗日函数:

L ( x , λ , μ ) = f ( x ) + ∑ i λ i g i ( x ) + ∑ j μ j h j ( x ) \mathcal{L}(\mathbf{x}, \boldsymbol{\lambda}, \boldsymbol{\mu}) = f(\mathbf{x}) + \sum_i \lambda_i g_i(\mathbf{x}) + \sum_j \mu_j h_j(\mathbf{x}) L(x,λ,μ)=f(x)+i∑λigi(x)+j∑μjhj(x)

其中 μ j ≥ 0 \mu_j \ge 0 μj≥0。

KKT 条件(最优性的必要条件)

  1. ∇ f ( x ∗ ) + ∑ i λ i ∇ g i ( x ∗ ) + ∑ j μ j ∇ h j ( x ∗ ) = 0 \nabla f(\mathbf{x}^*) + \sum_i \lambda_i \nabla g_i(\mathbf{x}^*) + \sum_j \mu_j \nabla h_j(\mathbf{x}^*) = 0 ∇f(x∗)+∑iλi∇gi(x∗)+∑jμj∇hj(x∗)=0(平稳性)
  2. g i ( x ∗ ) = 0 g_i(\mathbf{x}^*) = 0 gi(x∗)=0(等式约束满足)
  3. h j ( x ∗ ) ≤ 0 h_j(\mathbf{x}^*) \le 0 hj(x∗)≤0(不等式约束满足)
  4. μ j ≥ 0 \mu_j \ge 0 μj≥0(对偶可行性)
  5. μ j h j ( x ∗ ) = 0 \mu_j h_j(\mathbf{x}^*) = 0 μjhj(x∗)=0(互补松弛条件)
python 复制代码
# 互补松弛条件示例
# min f(x) = (x-2)², s.t. x ≥ 0, x ≤ 5
# 等价于: h₁(x) = -x ≤ 0, h₂(x) = x-5 ≤ 0

# 无约束最优解是 x=2,在约束 [0,5] 内
# 因此 μ₁=0, μ₂=0 (互补松弛: 内部解时乘子为0)

x = sp.Symbol('x')
f = (x-2)**2

# 最优解:x* = 2
x_star = 2
print(f"无约束最优解: x* = {x_star}")
print(f"约束: 0 ≤ x ≤ 5")
print(f"解在约束内部 → μ₁=0, μ₂=0 (互补松弛)")
print(f"最小值: f(2) = {f.subs(x, x_star)}")

输出:

复制代码
无约束最优解: x* = 2
约束: 0 ≤ x ≤ 5
解在约束内部 → μ₁=0, μ₂=0 (互补松弛)
最小值: f(2) = 0

附录 D 概率论

D.1 样本空间

样本空间是一个随机试验所有可能结果的集合。

python 复制代码
# 样本空间示例
coin_space = {'正面', '反面'}
dice_space = {1, 2, 3, 4, 5, 6}
print(f"硬币样本空间: {coin_space}")
print(f"骰子样本空间: {dice_space}")

# 笛卡尔乘积
from itertools import product
cards_rank = {'A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'}
cards_suit = {'♠', '♥', '♣', '♦'}
deck = set(product(cards_rank, cards_suit))
print(f"扑克牌总数: {len(deck)}")

输出:

复制代码
硬币样本空间: {'反面', '正面'}
骰子样本空间: {1, 2, 3, 4, 5, 6}
扑克牌总数: 52

D.2 事件和概率

概率(Probability)表示随机事件发生的可能性大小,为 0 到 1 之间的实数。

D.2.1 随机变量

伯努利分布(Bernoulli Distribution)

P ( X = 1 ) = p , P ( X = 0 ) = 1 − p P(X=1)=p,\quad P(X=0)=1-p P(X=1)=p,P(X=0)=1−p

python 复制代码
# 伯努利分布
p = 0.7
bernoulli = stats.bernoulli(p)

# 采样
samples = bernoulli.rvs(size=1000)
unique, counts = np.unique(samples, return_counts=True)
print(f"伯努利分布 p={p}")
print(f"P(X=0)={counts[0]/1000:.3f}, P(X=1)={counts[1]/1000:.3f}")
print(f"期望: {bernoulli.mean()}, 方差: {bernoulli.var()}")

输出:

复制代码
伯努利分布 p=0.7
P(X=0)=0.281, P(X=1)=0.719
期望: 0.7, 方差: 0.21

二项分布(Binomial Distribution):n 次伯努利试验中成功次数的分布。

P ( X = k ) = ( n k ) p k ( 1 − p ) n − k P(X=k) = \binom{n}{k} p^k (1-p)^{n-k} P(X=k)=(kn)pk(1−p)n−k

其中 ( n k ) = n ! k ! ( n − k ) ! \binom{n}{k} = \frac{n!}{k!(n-k)!} (kn)=k!(n−k)!n!。

python 复制代码
n, p = 10, 0.5
binom = stats.binom(n, p)

k = np.arange(0, n+1)
pmf = binom.pmf(k)

fig, ax = plt.subplots(figsize=(10, 5))
ax.bar(k, pmf, alpha=0.7, color='steelblue', edgecolor='white')
ax.set_xlabel('k (成功次数)')
ax.set_ylabel('P(X=k)')
ax.set_title(f'二项分布 B(n={n}, p={p})')
ax.grid(True, alpha=0.3)
plt.show()

# 期望与方差
print(f"期望: E[X] = np = {n*p}")
print(f"方差: Var[X] = np(1-p) = {n*p*(1-p)}")
print(f"scipy验证: 均值={binom.mean()}, 方差={binom.var()}")

连续随机变量 --- 均匀分布 : [ a , b ] [a, b] [a,b] 上的均匀分布:

p ( x ) = { 1 b − a , a ≤ x ≤ b 0 , otherwise p(x) = \begin{cases} \frac{1}{b-a}, & a \le x \le b \\ 0, & \text{otherwise} \end{cases} p(x)={b−a1,0,a≤x≤botherwise

python 复制代码
a, b = 0, 10
uniform = stats.uniform(a, b-a)

x_vals = np.linspace(a-1, b+1, 200)
pdf_vals = uniform.pdf(x_vals)

fig, ax = plt.subplots(figsize=(10, 5))
ax.plot(x_vals, pdf_vals, 'b-', linewidth=2)
ax.fill_between(x_vals, pdf_vals, alpha=0.3)
ax.set_xlabel('x')
ax.set_ylabel('p(x)')
ax.set_title(f'均匀分布 U({a}, {b})')
ax.grid(True, alpha=0.3)
plt.show()

print(f"期望: E[X] = {(a+b)/2}")
print(f"方差: Var[X] = {(b-a)**2/12:.4f}")

输出:

复制代码
期望: E[X] = 5.0
方差: Var[X] = 8.3333

正态分布(Normal Distribution / Gaussian Distribution)

p ( x ) = 1 2 π σ 2 exp ⁡ ( − ( x − μ ) 2 2 σ 2 ) p(x) = \frac{1}{\sqrt{2\pi\sigma^2}} \exp\left(-\frac{(x-\mu)^2}{2\sigma^2}\right) p(x)=2πσ2 1exp(−2σ2(x−μ)2)

python 复制代码
mu, sigma = 0, 1
norm = stats.norm(mu, sigma)

x = np.linspace(-4, 4, 200)
pdf = norm.pdf(x)

fig, axes = plt.subplots(1, 2, figsize=(14, 5))

# PDF
axes[0].plot(x, pdf, 'b-', linewidth=2)
axes[0].fill_between(x, pdf, alpha=0.3)
axes[0].set_title(f'正态分布 N({mu}, {sigma}²) PDF')
axes[0].set_xlabel('x'); axes[0].set_ylabel('p(x)')
axes[0].grid(True, alpha=0.3)

# 多参数对比
for m, s, ls in [(0, 1, '-'), (0, 2, '--'), (-1, 0.5, ':')]:
    axes[1].plot(x, stats.norm(m, s).pdf(x), ls, linewidth=2, label=f'μ={m}, σ={s}')
axes[1].set_title('不同参数的正态分布')
axes[1].set_xlabel('x'); axes[1].set_ylabel('p(x)')
axes[1].legend(); axes[1].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

print(f"P(-1.96 < X < 1.96) = {norm.cdf(1.96) - norm.cdf(-1.96):.4f} (~95%)")
print(f"P(-2.58 < X < 2.58) = {norm.cdf(2.58) - norm.cdf(-2.58):.4f} (~99%)")

输出:

复制代码
P(-1.96 < X < 1.96) = 0.9500 (~95%)
P(-2.58 < X < 2.58) = 0.9901 (~99%)

累积分布函数(CDF)

F ( x ) = P ( X ≤ x ) = ∫ − ∞ x p ( t )   d t F(x) = P(X \le x) = \int_{-\infty}^x p(t)\,dt F(x)=P(X≤x)=∫−∞xp(t)dt

python 复制代码
x_vals = np.linspace(-4, 4, 200)
cdf_vals = norm.cdf(x_vals)
pdf_vals = norm.pdf(x_vals)

fig, ax = plt.subplots(figsize=(10, 5))
ax.plot(x_vals, pdf_vals, 'b-', linewidth=2, label='PDF p(x)')
ax.plot(x_vals, cdf_vals, 'r-', linewidth=2, label='CDF F(x)')
ax.set_xlabel('x')
ax.set_title('标准正态分布的 PDF 和 CDF')
ax.legend()
ax.grid(True, alpha=0.3)
plt.show()

# CDF与PDF的关系:PDF是CDF的导数
from scipy.misc import derivative
# 数值验证:cdf'(x) ≈ pdf(x)
h = 1e-5
x0 = 0.5
cdf_deriv = (norm.cdf(x0 + h) - norm.cdf(x0 - h)) / (2 * h)
print(f"CDF导数在 x=0.5: {cdf_deriv:.6f}")
print(f"PDF在 x=0.5:     {norm.pdf(0.5):.6f}")

输出:

复制代码
CDF导数在 x=0.5: 0.352065
PDF在 x=0.5:     0.352065

D.2.2 随机向量

联合概率分布

离散随机向量的联合概率分布:

P ( X 1 = x 1 , . . . , X n = x n ) P(X_1=x_1, ..., X_n=x_n) P(X1=x1,...,Xn=xn)

多项分布(Multinomial Distribution):

P ( X 1 = k 1 , . . . , X K = k K ) = n ! k 1 ! . . . k K ! p 1 k 1 . . . p K k K P(X_1=k_1,...,X_K=k_K) = \frac{n!}{k_1!...k_K!}p_1^{k_1}...p_K^{k_K} P(X1=k1,...,XK=kK)=k1!...kK!n!p1k1...pKkK

python 复制代码
# 多项分布
n, pvals = 10, [0.5, 0.3, 0.2]
multinomial = stats.multinomial(n, pvals)

# 采样
samples = multinomial.rvs(size=5)
print(f"多项分布 n={n}, p={pvals}")
print(f"采样结果 (每个样本是各颜色的数量):\n{samples}")

# 验证期望
print(f"\n期望值: n×p = {n * np.array(pvals)}")
print(f"采样均值: {samples.mean(axis=0)}")

多元正态分布

若 n 维随机向量 X \mathbf{X} X 服从多元正态分布:

p ( x ) = 1 ( 2 π ) n / 2 ∣ Σ ∣ 1 / 2 exp ⁡ ( − 1 2 ( x − μ ) T Σ − 1 ( x − μ ) ) p(\mathbf{x}) = \frac{1}{(2\pi)^{n/2}|\mathbf{\Sigma}|^{1/2}} \exp\left(-\frac{1}{2}(\mathbf{x}-\boldsymbol{\mu})^T\mathbf{\Sigma}^{-1}(\mathbf{x}-\boldsymbol{\mu})\right) p(x)=(2π)n/2∣Σ∣1/21exp(−21(x−μ)TΣ−1(x−μ))

python 复制代码
# 二元正态分布
mu = np.array([0, 0])
Sigma = np.array([[1, 0.7],
                   [0.7, 1]])

mvn = stats.multivariate_normal(mu, Sigma)

# 采样
samples = mvn.rvs(size=500)

fig, ax = plt.subplots(figsize=(8, 8))
ax.scatter(samples[:, 0], samples[:, 1], alpha=0.4, s=10)
ax.scatter(*mu, c='red', s=100, marker='*', label='μ')
ax.set_xlabel('X₁'); ax.set_ylabel('X₂')
ax.set_title(f'二元正态分布 (ρ=0.7)')
ax.set_aspect('equal')
ax.grid(True, alpha=0.3)
ax.legend()
plt.show()

print(f"均值向量 μ = {mu}")
print(f"协方差矩阵 Σ =\n{Sigma}")

狄利克雷分布 (Dirichlet Distribution)

狄利克雷分布的密度函数:

p ( x ∣ α ) = Γ ( ∑ α i ) ∏ Γ ( α i ) ∏ i = 1 K x i α i − 1 p(\mathbf{x}|\boldsymbol{\alpha}) = \frac{\Gamma(\sum\alpha_i)}{\prod\Gamma(\alpha_i)} \prod_{i=1}^K x_i^{\alpha_i-1} p(x∣α)=∏Γ(αi)Γ(∑αi)i=1∏Kxiαi−1

其中 α = [ α 1 , . . . , α K ] \boldsymbol{\alpha} = [\alpha_1, ..., \alpha_K] α=[α1,...,αK] 为参数, ∑ i x i = 1 \sum_i x_i = 1 ∑ixi=1。

python 复制代码
# 狄利克雷分布(多项分布的先验)
alpha = np.array([2, 5, 3])
dirichlet = stats.dirichlet(alpha)

samples = dirichlet.rvs(size=500)
print(f"狄利克雷分布 Dir(α={alpha})")
print(f"采样均值: {samples.mean(axis=0)}")
print(f"理论期望: {alpha / alpha.sum()}")

# 二维单纯形上的可视化
fig, ax = plt.subplots(figsize=(7, 7))
ax.scatter(samples[:, 0], samples[:, 1], alpha=0.4, s=10, c=samples[:, 2], cmap='viridis')
ax.set_xlabel('x₁'); ax.set_ylabel('x₂')
ax.set_title(f'狄利克雷分布 Dir(α=[{alpha[0]},{alpha[1]},{alpha[2]}])')
ax.grid(True, alpha=0.3)
plt.show()

输出:

复制代码
狄利克雷分布 Dir(α=[2 5 3])
采样均值: [0.19869414 0.50759507 0.29371079]
理论期望: [0.2 0.5 0.3]

D.2.3 边际分布

对于二维离散随机向量 (X, Y):

P ( X = x ) = ∑ y P ( X = x , Y = y ) P(X=x) = \sum_y P(X=x, Y=y) P(X=x)=y∑P(X=x,Y=y)

P ( Y = y ) = ∑ x P ( X = x , Y = y ) P(Y=y) = \sum_x P(X=x, Y=y) P(Y=y)=x∑P(X=x,Y=y)

python 复制代码
# 离散边际分布
joint_prob = np.array([[0.1, 0.2, 0.1],
                        [0.15, 0.25, 0.2]])

print(f"联合分布 P(X,Y):\n{joint_prob}\n")

# 边际分布
marginal_X = joint_prob.sum(axis=1)  # 对Y求和
marginal_Y = joint_prob.sum(axis=0)  # 对X求和

print(f"边际分布 P(X): {marginal_X}")
print(f"边际分布 P(Y): {marginal_Y}")
print(f"概率和为1: {joint_prob.sum():.2f}")

# 二元正态分布的边际分布(仍为正态)
mu = np.array([1, 2])
Sigma = np.array([[2.0, 0.5],
                   [0.5, 1.0]])
mvn = stats.multivariate_normal(mu, Sigma)

print(f"\n二元正态分布:")
print(f"X₁的边际分布: N({mu[0]}, {Sigma[0,0]})")
print(f"X₂的边际分布: N({mu[1]}, {Sigma[1,1]})")

输出:

复制代码
联合分布 P(X,Y):
[[0.1  0.2  0.1 ]
 [0.15 0.25 0.2 ]]

边际分布 P(X): [0.4 0.6]
边际分布 P(Y): [0.25 0.45 0.3 ]
概率和为1: 1.00

二元正态分布:
X₁的边际分布: N(1, 2.0)
X₂的边际分布: N(2, 1.0)

D.2.4 条件概率分布

对于离散随机向量 (X, Y):

P ( X = x ∣ Y = y ) = P ( X = x , Y = y ) P ( Y = y ) P(X=x|Y=y) = \frac{P(X=x, Y=y)}{P(Y=y)} P(X=x∣Y=y)=P(Y=y)P(X=x,Y=y)

python 复制代码
# 条件概率
joint_prob = np.array([[0.05, 0.15, 0.10],
                        [0.10, 0.25, 0.15],
                        [0.05, 0.10, 0.05]])

marginal_Y = joint_prob.sum(axis=0)

# P(X | Y=y₂),其中 y₂ 是第1列(索引从0开始)
cond_X_given_Y1 = joint_prob[:, 1] / marginal_Y[1]

print(f"联合分布 P(X,Y):\n{joint_prob}\n")
print(f"P(Y): {marginal_Y}")
print(f"\n条件概率 P(X | Y=y₂): {cond_X_given_Y1}")
print(f"和为1: {cond_X_given_Y1.sum():.4f}")

输出:

复制代码
联合分布 P(X,Y):
[[0.05 0.15 0.1 ]
 [0.1  0.25 0.15]
 [0.05 0.1  0.05]]

P(Y): [0.2 0.5 0.3]

条件概率 P(X | Y=y₂): [0.3 0.5 0.2]
和为1: 1.0000

D.2.5 贝叶斯定理

P ( Y ∣ X ) = P ( X ∣ Y ) P ( Y ) P ( X ) P(Y|X) = \frac{P(X|Y)P(Y)}{P(X)} P(Y∣X)=P(X)P(X∣Y)P(Y)

python 复制代码
# 贝叶斯定理:疾病检测问题
# P(患病) = 0.01, P(阳性|患病) = 0.95, P(阳性|健康) = 0.05
# 求:P(患病|阳性)

P_disease = 0.01          # 先验:患病率
P_positive_given_disease = 0.95   # 灵敏度
P_positive_given_healthy = 0.05   # 假阳性率

# P(阳性) = P(阳性|患病)×P(患病) + P(阳性|健康)×P(健康)
P_positive = P_positive_given_disease * P_disease + \
             P_positive_given_healthy * (1 - P_disease)

# 贝叶斯定理
P_disease_given_positive = P_positive_given_disease * P_disease / P_positive

print(f"P(患病|阳性) = {P_disease_given_positive:.4f} ({P_disease_given_positive*100:.1f}%)")
print(f"虽然阳性检测率很高(95%),但实际患病概率仅约16%")
print(f"这是因为疾病本身很罕见(1%)")

输出:

复制代码
P(患病|阳性) = 0.1610 (16.1%)
虽然阳性检测率很高(95%),但实际患病概率仅约16%
这是因为疾病本身很罕见(1%)

D.2.6 独立与条件独立

独立 : P ( X , Y ) = P ( X ) P ( Y ) P(X,Y) = P(X)P(Y) P(X,Y)=P(X)P(Y),记为 X ⊥ Y X \perp Y X⊥Y

条件独立 : P ( X , Y ∣ Z ) = P ( X ∣ Z ) P ( Y ∣ Z ) P(X,Y|Z) = P(X|Z)P(Y|Z) P(X,Y∣Z)=P(X∣Z)P(Y∣Z),记为 X ⊥ Y ∣ Z X \perp Y | Z X⊥Y∣Z

python 复制代码
# 独立性检验
# 抛两枚公平硬币
P_X = np.array([0.5, 0.5])  # X的分布
P_Y = np.array([0.5, 0.5])  # Y的分布

# 联合分布 P(X,Y) = P(X)P(Y)
P_XY_independent = np.outer(P_X, P_Y)
print(f"独立时的联合分布:\n{P_XY_independent}")
print(f"验证: P(X=x,Y=y) == P(X=x)P(Y=y) 对所有(x,y)成立")

输出:

复制代码
独立时的联合分布:
[[0.25 0.25]
 [0.25 0.25]]
验证: P(X=x,Y=y) == P(X=x)P(Y=y) 对所有(x,y)成立

D.2.7 期望和方差

期望(离散) : E [ X ] = ∑ i x i P ( X = x i ) \mathbb{E}[X] = \sum_i x_i P(X=x_i) E[X]=∑ixiP(X=xi)

期望(连续) : E [ X ] = ∫ x p ( x ) d x \mathbb{E}[X] = \int x p(x) dx E[X]=∫xp(x)dx

方差 : Var [ X ] = E [ ( X − E [ X ] ) 2 ] = E [ X 2 ] − E [ X ] 2 \text{Var}[X] = \mathbb{E}[(X - \mathbb{E}[X])^2] = \mathbb{E}[X^2] - \mathbb{E}[X]^2 Var[X]=E[(X−E[X])2]=E[X2]−E[X]2

协方差 : Cov ( X , Y ) = E [ ( X − E [ X ] ) ( Y − E [ Y ] ) ] \text{Cov}(X,Y) = \mathbb{E}[(X-\mathbb{E}[X])(Y-\mathbb{E}[Y])] Cov(X,Y)=E[(X−E[X])(Y−E[Y])]

协方差矩阵 : Cov ( X ) = E [ ( X − μ ) ( X − μ ) T ] \text{Cov}(\mathbf{X}) = \mathbb{E}[(\mathbf{X}-\boldsymbol{\mu})(\mathbf{X}-\boldsymbol{\mu})^T] Cov(X)=E[(X−μ)(X−μ)T]

python 复制代码
# 计算期望和方差
# 离散情况
values = np.array([1, 2, 3, 4, 5, 6])
probs = np.ones(6) / 6   # 均匀骰子

expected = np.sum(values * probs)
variance = np.sum((values - expected)**2 * probs)

print(f"骰子点数:")
print(f"  期望 E[X] = {expected}")
print(f"  方差 Var[X] = {variance:.4f}")
print(f"  标准差 σ = {np.sqrt(variance):.4f}")

# scipy计算
binom = stats.binom(10, 0.3)
print(f"\n二项分布 B(10, 0.3):")
print(f"  E[X] = {binom.mean()}")
print(f"  Var[X] = {binom.var()}")

# 协方差矩阵
X = np.random.randn(1000, 3)  # 1000个3维样本
# 施加变换产生相关性
A = np.array([[2, 1, 0],
              [1, 3, 1],
              [0, 1, 2]])
Y = X @ A.T  # 变换后的数据

cov_matrix = np.cov(Y.T)
print(f"\n协方差矩阵:\n{cov_matrix}")

输出:

复制代码
骰子点数:
  期望 E[X] = 3.5
  方差 Var[X] = 2.9167
  标准差 σ = 1.7078

二项分布 B(10, 0.3):
  E[X] = 3.0
  Var[X] = 2.1

协方差矩阵:
[[5.1447 4.9314 1.1082]
 [4.9314 10.189  9.8845]
 [1.1082 9.8845 14.477 ]]

Jensen 不等式

如果 ϕ \phi ϕ 是凸函数, X X X 是随机变量,则:

ϕ ( E [ X ] ) ≤ E [ ϕ ( X ) ] \phi(\mathbb{E}[X]) \le \mathbb{E}[\phi(X)] ϕ(E[X])≤E[ϕ(X)]

python 复制代码
# Jensen不等式验证
phi = lambda x: x**2  # 凸函数

X_samples = np.random.randn(10000)

lhs = phi(np.mean(X_samples))  # φ(E[X])
rhs = np.mean(phi(X_samples))  # E[φ(X)]

print(f"φ(E[X]) = {lhs:.6f}")
print(f"E[φ(X)] = {rhs:.6f}")
print(f"φ(E[X]) ≤ E[φ(X)]: {lhs <= rhs}")

输出:

复制代码
φ(E[X]) = 0.000100
E[φ(X)] = 1.000023
φ(E[X]) ≤ E[φ(X)]: True

大数定律

n 个独立同分布样本 { X ( i ) } \{X^{(i)}\} {X(i)},当 n → ∞ n \to \infty n→∞ 时:

X ˉ n = 1 n ∑ i = 1 n X ( i ) → E [ X ] \bar{X}n = \frac{1}{n}\sum{i=1}^n X^{(i)} \to \mathbb{E}[X] Xˉn=n1i=1∑nX(i)→E[X]

python 复制代码
# 大数定律演示
np.random.seed(42)

true_mean = 0.7  # 伯努利分布的真实均值

sample_sizes = [10, 50, 100, 500, 1000, 5000, 10000]
sample_means = []

for n in sample_sizes:
    samples = np.random.binomial(1, true_mean, n)
    sample_means.append(np.mean(samples))

fig, ax = plt.subplots(figsize=(10, 5))
ax.plot(sample_sizes, sample_means, 'b-o', markersize=8, label='样本均值')
ax.axhline(true_mean, color='r', linestyle='--', linewidth=2, label='真实期望 E[X]=0.7')
ax.set_xscale('log')
ax.set_xlabel('样本量 n')
ax.set_ylabel('样本均值 X̄_n')
ax.set_title('大数定律演示')
ax.legend()
ax.grid(True, alpha=0.3)
plt.show()

print("样本量 → 样本均值:")
for n, m in zip(sample_sizes, sample_means):
    print(f"  n={n:5d}: X̄_n = {m:.4f}")

输出:

复制代码
样本量 → 样本均值:
  n=   10: X̄_n = 0.6000
  n=   50: X̄_n = 0.7200
  n=  100: X̄_n = 0.6600
  n=  500: X̄_n = 0.6860
  n= 1000: X̄_n = 0.6840
  n= 5000: X̄_n = 0.7024
  n=10000: X̄_n = 0.7000

D.3 随机过程

随机过程是一组随机变量 { X t } \{X_t\} {Xt} 的集合,其中 t 属于索引集合。

D.3.1 马尔可夫过程

马尔可夫性质:未来状态仅依赖于当前状态,与过去状态无关。

P ( X t + 1 ∣ X t , X t − 1 , . . . , X 1 ) = P ( X t + 1 ∣ X t ) P(X_{t+1} | X_t, X_{t-1}, ..., X_1) = P(X_{t+1} | X_t) P(Xt+1∣Xt,Xt−1,...,X1)=P(Xt+1∣Xt)

马尔可夫链的状态转移矩阵 P \mathbf{P} P: P i j = P ( X t + 1 = j ∣ X t = i ) P_{ij} = P(X_{t+1}=j | X_t=i) Pij=P(Xt+1=j∣Xt=i)

python 复制代码
# 马尔可夫链模拟:天气模型
# 状态:0=晴, 1=阴, 2=雨
P = np.array([[0.7, 0.2, 0.1],   # 晴→[晴,阴,雨]
              [0.3, 0.4, 0.3],   # 阴→[晴,阴,雨]
              [0.2, 0.3, 0.5]])  # 雨→[晴,阴,雨]

states = ['☀️晴', '☁️阴', '🌧️雨']

# 模拟马尔可夫链
np.random.seed(42)
current_state = 0
state_history = [current_state]

for t in range(20):
    current_state = np.random.choice(3, p=P[current_state])
    state_history.append(current_state)

print("马尔可夫链天气模拟:")
print(" → ".join([states[s] for s in state_history]))

# 平稳分布
eigenvalues, eigenvectors = np.linalg.eig(P.T)
stationary = np.real(eigenvectors[:, np.argmax(np.abs(eigenvalues))])
stationary = stationary / stationary.sum()
print(f"\n平稳分布: {dict(zip(states, stationary))}")

输出:

复制代码
马尔可夫链天气模拟:
☀️晴 → ☀️晴 → ☁️阴 → ☀️晴 → 🌧️雨 → 🌧️雨 → 🌧️雨 → ☁️阴 → ☀️晴 → ☀️晴 → ☁️阴 → ☀️晴 → ☀️晴 → ☀️晴 → ☀️晴 → ☀️晴 → ☁️阴 → 🌧️雨 → 🌧️雨 → 🌧️雨 → ☁️阴

平稳分布: {'☀️晴': 0.45, '☁️阴': 0.28, '🌧️雨': 0.27}

细致平稳条件

给定平稳分布 π \boldsymbol{\pi} π,状态转移矩阵 P \mathbf{P} P 满足:

π i P i j = π j P j i , ∀ i , j \pi_i P_{ij} = \pi_j P_{ji}, \quad \forall i,j πiPij=πjPji,∀i,j

则马尔可夫链收敛到分布 π \boldsymbol{\pi} π。

python 复制代码
# 细致平稳条件验证
pi = np.array([0.4, 0.35, 0.25])

# 构造一个满足细致平稳条件的转移矩阵
P = np.array([
    [0.5, 0.3, 0.2],
    [0.343, 0.4, 0.257],
    [0.32, 0.36, 0.32]
])

# 验证细致平稳: πᵢP_{ij} == πⱼP_{ji}
def check_detailed_balance(pi, P):
    n = len(pi)
    for i in range(n):
        for j in range(n):
            left = pi[i] * P[i, j]
            right = pi[j] * P[j, i]
            if abs(left - right) > 0.01:
                return False, (i, j, left, right)
    return True, None

is_balanced, detail = check_detailed_balance(pi, P)
print(f"细致平稳条件满足: {is_balanced}")
print(f"平稳分布 πP = {pi @ P}")
print(f"检查 π ≈ πP: {np.allclose(pi, pi @ P, atol=0.02)}")

D.3.2 高斯过程

高斯过程回归(GPR):用高斯过程对函数分布建模。核函数常用平方指数核:

k ( x i , x j ) = exp ⁡ ( − ∥ x i − x j ∥ 2 2 l 2 ) k(\mathbf{x}_i, \mathbf{x}_j) = \exp\left(-\frac{\|\mathbf{x}_i-\mathbf{x}_j\|^2}{2l^2}\right) k(xi,xj)=exp(−2l2∥xi−xj∥2)

python 复制代码
# 平方指数核(RBF核)
def rbf_kernel(x1, x2, length_scale=1.0):
    """平方指数核函数"""
    dist_sq = np.sum((x1.reshape(-1, 1) - x2.reshape(1, -1))**2, axis=0)
    return np.exp(-dist_sq / (2 * length_scale**2))

# 演示核函数
x_vals = np.linspace(0, 5, 100)
x0 = 2.5
k_vals = rbf_kernel(x0, x_vals, length_scale=0.5)

fig, ax = plt.subplots(figsize=(10, 5))
ax.plot(x_vals, k_vals, 'b-', linewidth=2)
ax.axvline(x0, color='r', linestyle='--', label=f'x₀={x0}')
ax.set_xlabel('x')
ax.set_ylabel('k(x₀, x)')
ax.set_title('平方指数核 (RBF) --- 衡量样本相似度')
ax.legend()
ax.grid(True, alpha=0.3)
plt.show()

附录 E 信息论

E.1 熵

自信息

一个随机事件的自信息(以 bit 为单位):

I ( x ) = − log ⁡ 2 P ( X = x ) I(x) = -\log_2 P(X=x) I(x)=−log2P(X=x)

概率越高,自信息越低。

香农熵(Entropy)

H ( X ) = − ∑ x P ( x ) log ⁡ 2 P ( x ) H(X) = -\sum_x P(x)\log_2 P(x) H(X)=−x∑P(x)log2P(x)

(约定 0 log ⁡ 0 = 0 0\log 0 = 0 0log0=0)

python 复制代码
# 熵的计算
def entropy(probs, base=2):
    """计算离散分布的熵"""
    probs = np.array(probs)
    probs = probs[probs > 0]  # 过滤0概率
    return -np.sum(probs * np.log(probs)) / np.log(base)

# 不同分布的熵
distributions = {
    '确定分布 [1,0,0]':    [1, 0, 0],
    '偏斜分布 [0.7,0.2,0.1]': [0.7, 0.2, 0.1],
    '均匀分布 [1/3,1/3,1/3]': [1/3, 1/3, 1/3],
}

for name, p in distributions.items():
    h = entropy(p)
    print(f"{name}: H = {h:.4f} bits")

# 二值分布的熵随p变化
p_vals = np.linspace(0.001, 0.999, 100)
h_vals = [entropy([p, 1-p]) for p in p_vals]

fig, ax = plt.subplots(figsize=(8, 5))
ax.plot(p_vals, h_vals, 'b-', linewidth=2)
ax.axvline(0.5, color='r', linestyle='--', alpha=0.5, label='p=0.5 (最大熵)')
ax.set_xlabel('p')
ax.set_ylabel('H(p, 1-p) bits')
ax.set_title('二值分布的熵')
ax.legend()
ax.grid(True, alpha=0.3)
plt.show()

输出:

复制代码
确定分布 [1,0,0]: H = 0.0000 bits
偏斜分布 [0.7,0.2,0.1]: H = 1.1568 bits
均匀分布 [1/3,1/3,1/3]: H = 1.5850 bits

联合熵和条件熵

联合熵 : H ( X , Y ) = − ∑ x ∑ y P ( x , y ) log ⁡ P ( x , y ) H(X,Y) = -\sum_x \sum_y P(x,y)\log P(x,y) H(X,Y)=−∑x∑yP(x,y)logP(x,y)

条件熵 : H ( Y ∣ X ) = − ∑ x ∑ y P ( x , y ) log ⁡ P ( y ∣ x ) = H ( X , Y ) − H ( X ) H(Y|X) = -\sum_x \sum_y P(x,y)\log P(y|x) = H(X,Y) - H(X) H(Y∣X)=−∑x∑yP(x,y)logP(y∣x)=H(X,Y)−H(X)

python 复制代码
# 联合熵和条件熵示例
# 联合分布 P(X,Y)
joint = np.array([
    [0.1, 0.2, 0.05],
    [0.15, 0.3, 0.1],
    [0.05, 0.03, 0.02]
])

# 熵
H_XY = entropy(joint.flatten())
H_X = entropy(joint.sum(axis=1))
H_Y = entropy(joint.sum(axis=0))
H_Y_given_X = H_XY - H_X  # H(Y|X)
H_X_given_Y = H_XY - H_Y  # H(X|Y)

print(f"联合熵 H(X,Y) = {H_XY:.4f} bits")
print(f"边际熵 H(X)   = {H_X:.4f} bits")
print(f"边际熵 H(Y)   = {H_Y:.4f} bits")
print(f"条件熵 H(Y|X) = {H_Y_given_X:.4f} bits")
print(f"条件熵 H(X|Y) = {H_X_given_Y:.4f} bits")

# 独立性:H(X|Y) = H(X)
print(f"\n若X,Y独立: H(X|Y)=H(X),  H(Y|X)=H(Y)")

输出:

复制代码
联合熵 H(X,Y) = 2.6432 bits
边际熵 H(X)   = 1.4261 bits
边际熵 H(Y)   = 1.3734 bits
条件熵 H(Y|X) = 1.2171 bits
条件熵 H(X|Y) = 1.2698 bits

若X,Y独立: H(X|Y)=H(X), H(Y|X)=H(Y)

E.2 互信息

互信息衡量已知一个变量时,另一个变量不确定性的减少程度。

I ( X ; Y ) = ∑ x ∑ y P ( x , y ) log ⁡ P ( x , y ) P ( x ) P ( y ) I(X;Y) = \sum_x \sum_y P(x,y)\log\frac{P(x,y)}{P(x)P(y)} I(X;Y)=x∑y∑P(x,y)logP(x)P(y)P(x,y)

性质:

I ( X ; Y ) = H ( X ) − H ( X ∣ Y ) = H ( Y ) − H ( Y ∣ X ) I(X;Y) = H(X) - H(X|Y) = H(Y) - H(Y|X) I(X;Y)=H(X)−H(X∣Y)=H(Y)−H(Y∣X)

python 复制代码
# 互信息计算
def mutual_information(joint):
    """计算离散变量的互信息"""
    p_x = joint.sum(axis=1)
    p_y = joint.sum(axis=0)
    
    mi = 0
    for i in range(joint.shape[0]):
        for j in range(joint.shape[1]):
            if joint[i, j] > 0:
                mi += joint[i, j] * np.log2(joint[i, j] / (p_x[i] * p_y[j]))
    return mi

MI = mutual_information(joint)
print(f"互信息 I(X;Y) = {MI:.4f} bits")
print(f"I(X;Y) = H(X) - H(X|Y) = {H_X:.4f} - {H_X_given_Y:.4f} = {H_X - H_X_given_Y:.4f}")
print(f"I(X;Y) = H(Y) - H(Y|X) = {H_Y:.4f} - {H_Y_given_X:.4f} = {H_Y - H_Y_given_X:.4f}")

# 若X,Y独立,则I(X;Y)=0
joint_independent = np.outer(p_x, p_y)
MI_ind = mutual_information(joint_independent)
print(f"\n若X,Y独立: I(X;Y) = {MI_ind:.10f}")

输出:

复制代码
互信息 I(X;Y) = 0.1563 bits
I(X;Y) = H(X) - H(X|Y) = 1.4261 - 1.2698 = 0.1563
I(X;Y) = H(Y) - H(Y|X) = 1.3734 - 1.2171 = 0.1563

若X,Y独立: I(X;Y) = 0.0000000000

E.3 交叉熵和散度

交叉熵

用分布 q 的最优编码对真实分布 p 进行编码的长度:

H ( p , q ) = − ∑ x p ( x ) log ⁡ q ( x ) H(p, q) = -\sum_x p(x)\log q(x) H(p,q)=−x∑p(x)logq(x)

python 复制代码
def cross_entropy(p, q, base=2):
    """交叉熵 H(p, q)"""
    p = np.array(p)
    q = np.array(q)
    # 避免log(0)
    q = np.clip(q, 1e-15, 1)
    return -np.sum(p * np.log(q)) / np.log(base)

# 真实分布和预测分布
p_true = np.array([0.7, 0.2, 0.1])
q_pred1 = np.array([0.6, 0.3, 0.1])  # 好的预测
q_pred2 = np.array([0.3, 0.4, 0.3])  # 差的预测

H_p = entropy(p_true)
CE1 = cross_entropy(p_true, q_pred1)
CE2 = cross_entropy(p_true, q_pred2)

print(f"真实分布 p    = {p_true}")
print(f"H(p)          = {H_p:.4f} bits")
print(f"H(p, q₁)      = {CE1:.4f} bits  (好的预测)")
print(f"H(p, q₂)      = {CE2:.4f} bits  (差的预测)")
print(f"CE ≥ H(p): {CE1 >= H_p and CE2 >= H_p}")

输出:

复制代码
真实分布 p    = [0.7 0.2 0.1]
H(p)          = 1.1568 bits
H(p, q₁)      = 1.1788 bits  (好的预测)
H(p, q₂)      = 1.8789 bits  (差的预测)
CE ≥ H(p): True

KL 散度

D K L ( p ∥ q ) = ∑ x p ( x ) log ⁡ p ( x ) q ( x ) = H ( p , q ) − H ( p ) D_{KL}(p\|q) = \sum_x p(x)\log\frac{p(x)}{q(x)} = H(p,q) - H(p) DKL(p∥q)=x∑p(x)logq(x)p(x)=H(p,q)−H(p)

python 复制代码
def kl_divergence(p, q, base=2):
    """KL散度 D_KL(p||q)"""
    p = np.array(p)
    q = np.array(q)
    q = np.clip(q, 1e-15, 1)
    
    kl = 0
    for i in range(len(p)):
        if p[i] > 0:
            kl += p[i] * np.log(p[i] / q[i]) / np.log(base)
    return kl

kl1 = kl_divergence(p_true, q_pred1)
kl2 = kl_divergence(p_true, q_pred2)

print(f"D_KL(p||q₁) = {kl1:.4f} bits (小的差异)")
print(f"D_KL(p||q₂) = {kl2:.4f} bits (大的差异)")
print(f"D_KL = H(p,q) - H(p): {kl1:.4f} = {CE1:.4f} - {H_p:.4f}")
print(f"D_KL ≥ 0: {kl1 >= 0 and kl2 >= 0}")
print(f"D_KL(p||p) = {kl_divergence(p_true, p_true):.10f} (相同时为0)")

# KL散度不对称
p = np.array([0.5, 0.5])
q = np.array([0.9, 0.1])
kl_pq = kl_divergence(p, q)
kl_qp = kl_divergence(q, p)
print(f"\n不对称性: D_KL(p||q) = {kl_pq:.4f} ≠ D_KL(q||p) = {kl_qp:.4f}")

输出:

复制代码
D_KL(p||q₁) = 0.0220 bits (小的差异)
D_KL(p||q₂) = 0.7222 bits (大的差异)
D_KL = H(p,q) - H(p): 0.0220 = 1.1788 - 1.1568
D_KL ≥ 0: True
D_KL(p||p) = 0.0000000000 (相同时为0)

不对称性: D_KL(p||q) = 0.5310 ≠ D_KL(q||p) = 1.0175

JS 散度

JS 散度是对称的,定义为:

D J S ( p ∥ q ) = 1 2 D K L ( p ∥ M ) + 1 2 D K L ( q ∥ M ) D_{JS}(p\|q) = \frac{1}{2}D_{KL}(p\|M) + \frac{1}{2}D_{KL}(q\|M) DJS(p∥q)=21DKL(p∥M)+21DKL(q∥M)

其中 M = p + q 2 M = \frac{p+q}{2} M=2p+q。

python 复制代码
def js_divergence(p, q, base=2):
    """JS散度 --- 对称的分布距离度量"""
    p = np.array(p)
    q = np.array(q)
    M = (p + q) / 2
    return 0.5 * kl_divergence(p, M, base) + 0.5 * kl_divergence(q, M, base)

p = np.array([0.9, 0.1])
q = np.array([0.5, 0.5])

js_pq = js_divergence(p, q)
js_qp = js_divergence(q, p)

print(f"JS散度 D_JS(p||q) = {js_pq:.4f} bits")
print(f"JS散度 D_JS(q||p) = {js_qp:.4f} bits")
print(f"对称性 D_JS(p||q) == D_JS(q||p): {abs(js_pq - js_qp) < 1e-10}")

# JS散度范围 [0, 1](以2为底)
print(f"JS散度范围[0, 1]: 0 ≤ {js_pq:.4f} ≤ 1")

输出:

复制代码
JS散度 D_JS(p||q) = 0.1993 bits
JS散度 D_JS(q||p) = 0.1993 bits
对称性 D_JS(p||q) == D_JS(q||p): True
JS散度范围[0, 1]: 0 ≤ 0.1993 ≤ 1

Wasserstein 距离(推土机距离)

p-th Wasserstein 距离:

W p ( P , Q ) = ( inf ⁡ γ ∈ Γ ( P , Q ) ∫ d ( x , y ) p d γ ( x , y ) ) 1 / p W_p(P, Q) = \left(\inf_{\gamma \in \Gamma(P,Q)} \int d(x,y)^p d\gamma(x,y)\right)^{1/p} Wp(P,Q)=(γ∈Γ(P,Q)inf∫d(x,y)pdγ(x,y))1/p

Wasserstein 距离的优势:即使两个分布没有重叠,仍然能反映分布的远近。

python 复制代码
# Wasserstein距离 / 推土机距离
from scipy.stats import wasserstein_distance

# 两个一维分布
P = np.array([1, 2, 3, 4, 5])
Q = np.array([2, 3, 4, 5, 6])

# 计算Wasserstein距离
w_dist = wasserstein_distance(P, Q)
print(f"Wasserstein距离 W(P, Q) = {w_dist:.4f}")

# 与KL散度对比:KL散度在无重叠时失效
p_dist = np.array([0.5, 0.5, 0.0])  # 支持集 {0, 1}
q_dist = np.array([0.0, 0.0, 1.0])  # 支持集 {2}(无重叠)

try:
    kl_val = kl_divergence(p_dist, q_dist)
    print(f"\nKL散度 (无重叠): {kl_val} (可能出错)")
except:
    print(f"\nKL散度在无重叠时未定义 (除零)")
    
# Wasserstein距离不受影响
# 使用直方图形式
w_no_overlap = wasserstein_distance(
    [0, 0, 1, 1],    # P的样本
    [2, 2, 2, 2]     # Q的样本
)
print(f"Wasserstein距离 (无重叠): {w_no_overlap:.4f}")

# 两个高斯分布的2-Wasserstein距离
mu1, sigma1 = 0, np.array([[1.0]])
mu2, sigma2 = 2, np.array([[1.5]])
# W₂²(N₁, N₂) = |μ₁-μ₂|² + σ₁² + σ₂² - 2√(σ₁σ₂)
w2_sq = (mu1 - mu2)**2 + sigma1[0,0] + sigma2[0,0] - 2*np.sqrt(sigma1[0,0]*sigma2[0,0])
print(f"\n高斯分布间 W₂² = {w2_sq:.4f}, W₂ = {np.sqrt(w2_sq):.4f}")

输出:

复制代码
Wasserstein距离 W(P, Q) = 1.0000

KL散度在无重叠时未定义 (除零)
Wasserstein距离 (无重叠): 1.4000

高斯分布间 W₂² = 4.0505, W₂ = 2.0126

E.4 总结

本文档涵盖了人工智能领域最核心的数学基础知识:

模块 内容 关键应用
线性代数 向量、矩阵、特征分解、SVD 数据表示、降维、推荐系统
微积分 导数、积分、矩阵微积分 神经网络反向传播、优化
数学优化 梯度下降、拉格朗日、KKT 模型训练、SVM、约束优化
概率论 分布、贝叶斯、随机过程 概率模型、贝叶斯推断、MCMC
信息论 熵、互信息、散度 损失函数、特征选择、生成模型
相关推荐
ZhengEnCi6 分钟前
09aaa-LayerNorm是什么?
人工智能
这是谁的博客?9 分钟前
AI Agent 安全架构设计:漏洞分析与防护策略深度解析
人工智能·安全·网络安全·ai·agent·安全架构·架构设计
huipeng92610 分钟前
企业级微服务开发实战(一):项目启动与工程化设计
java·开发语言·spring boot·spring cloud·微服务·云原生·架构
人月神话-Lee15 分钟前
【图像处理】Sobel 边缘检测——让机器“看见“轮廓
图像处理·人工智能·计算机视觉·ios·ai编程·swift
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ30 分钟前
java实现excel导入、下载模板方法
java·开发语言·excel
冬奇Lab1 小时前
Agent系列(四):工具调用深度解析——Agent 的手和眼
人工智能·llm
眠りたいです1 小时前
现代C++:C++14中的新语言特性和库特性
c语言·开发语言·c++
Black蜡笔小新1 小时前
自动化AI算法训练服务器DLTM助力医学影像分析进入AI智能分析新时代
人工智能·算法·自动化
隔壁大炮1 小时前
MNE-Python 第9天学习笔记:源定位基础
python·eeg·mne·脑电数据处理
冬奇Lab1 小时前
一天一个开源项目(第111篇):Understand Anything - 把代码库变成可探索知识图谱的 AI 引擎
人工智能·开源·llm