专题:Python机器学习系统学习
关键词:Python, 机器学习, 线性代数, 矩阵运算, 特征值, SVD, 向量空间, NumPy, 矩阵分解
一、向量与空间
1.1 向量的定义与表示
向量是线性代数中最基本的元素,可以理解为一组有序排列的数值。在机器学习中,一个样本(如一张图片、一个用户特征)通常被表示为一个向量。例如,一个房价预测样本可能包含面积、卧室数量、楼层等特征,这些特征共同构成一个特征向量。
在数学上,向量通常用粗体小写字母表示,如 v = [v₁, v₂, ..., vₙ]ᵀ。在 Python 中,向量可以用 NumPy 的 ndarray 或一维数组表示。
1.2 向量的基本运算
加法:对应位置元素相加,要求两个向量维度相同。几何意义是向量的平移组合。
数乘:每个元素乘以一个标量,几何意义是向量的缩放。
点积(内积):对应位置元素相乘再求和,结果是一个标量。点积衡量两个向量的方向相似度,在机器学习中广泛用于计算相似度和线性变换。
叉积:仅适用于三维向量,结果是一个垂直于原向量所构成平面的新向量。
1.3 向量的模长与单位向量
向量的模长(L2范数)定义为各元素平方和的平方根:||v|| = √(∑vᵢ²)。将向量除以它的模长得到单位向量,这在机器学习中常用于特征归一化,使不同量纲的特征具有可比性。
1.4 向量空间与子空间
向量空间是满足加法和数乘封闭性的向量集合。子空间是向量空间中同样满足封闭性的子集。在机器学习中,理解向量空间有助于把握数据分布的本质——高维数据往往存在于低维子空间中,这正是降维算法的理论基础。
1.5 Python实现:NumPy向量操作
import numpy as np
# 创建向量
v = np.array([1, 2, 3])
w = np.array([4, 5, 6])
# 向量加法
print("加法:", v + w)
# 数乘
print("数乘:", 3 * v)
# 点积
print("点积:", np.dot(v, w))
print("点积:", v @ w)
# 模长
norm = np.linalg.norm(v)
print("模长:", norm)
# 单位向量
unit_v = v / norm
print("单位向量:", unit_v)
# 叉积(仅3维)
print("叉积:", np.cross(v, w))
二、矩阵运算
2.1 矩阵的定义与表示
矩阵是按行和列排列的数值矩形阵列,通常用粗体大写字母表示,如 A ∈ ℝᵐˣⁿ 表示一个 m 行 n 列的矩阵。在机器学习中,整个数据集通常表示为一个矩阵,每行是一个样本,每列是一个特征。
2.2 矩阵基本运算
加法:对应位置元素相加,要求两个矩阵维度相同。
数乘:每个元素乘以一个标量。
转置:行列互换,记作 Aᵀ。对于对称矩阵有 A = Aᵀ。
2.3 矩阵乘法
矩阵点乘(矩阵乘法):A(m×n) 与 B(n×p) 相乘得到 C(m×p),其中 Cᵢⱼ = ∑ₖ Aᵢₖ Bₖⱼ。矩阵乘法不满足交换律(AB ≠ BA),但满足结合律和分配律。
Hadamard积(逐元素乘法):对应位置元素直接相乘,要求两个矩阵维度相同。
2.4 逆矩阵与伪逆
对于方阵 A,若存在 B 使得 AB = BA = I,则 B 是 A 的逆矩阵,记作 A⁻¹。只有方阵且行列式不为零时才存在逆矩阵。
伪逆(Moore-Penrose伪逆)是逆矩阵的推广,适用于任意形状的矩阵,记作 A⁺。在最小二乘线性回归中,伪逆用于求解正规方程。
2.5 矩阵的秩
矩阵的秩是线性无关的行(或列)的最大数目。满秩矩阵表示所有行(列)都线性无关。低秩矩阵意味着数据存在冗余,可以压缩表示——这是矩阵分解和降维的基本思想。
2.6 NumPy矩阵操作
import numpy as np
# 创建矩阵
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
# 矩阵乘法
C = A @ B
print("矩阵乘法:\n", C)
# 转置
print("转置:\n", A.T)
# 逆矩阵
A_inv = np.linalg.inv(A)
print("逆矩阵:\n", A_inv)
# 伪逆
A_pinv = np.linalg.pinv(A)
# 矩阵的秩
rank = np.linalg.matrix_rank(A)
print("秩:", rank)
# Hadamard积
print("Hadamard:\n", A * B)
2.7 应用:线性回归中的正规方程
线性回归的目标是找到权重 w 使得预测值 y = Xw 尽可能接近真实值。正规方程的闭式解为:w = (XᵀX)⁻¹Xᵀy。当 XᵀX 不可逆时(特征数大于样本数),可以在损失函数中添加正则化项,或改用伪逆求解:w = X⁺y。
import numpy as np
# 生成示例数据
X = np.random.randn(100, 3) # 100个样本,3个特征
true_w = np.array([2.5, -1.3, 0.8])
y = X @ true_w + 0.1 * np.random.randn(100) # y = Xw + 噪声
# 正规方程求解
w_hat = np.linalg.inv(X.T @ X) @ X.T @ y
print("估计的权重:", w_hat)
print("真实权重:", true_w)
# 用伪逆求解
w_pinv = np.linalg.pinv(X) @ y
print("伪逆求解:", w_pinv)
三、特征值与特征向量
3.1 特征值与特征向量的定义
对于方阵 A,若存在非零向量 v 和标量 λ 满足 Av = λv,则 λ 是 A 的特征值,v 是对应的特征向量。特征向量表示矩阵变换中方向不变的向量,特征值表示在该方向上的缩放因子。
3.2 特征分解
若矩阵 A 是实对称矩阵(在机器学习中常见,如协方差矩阵),则可以分解为 A = QΛQᵀ,其中 Q 是正交特征向量矩阵,Λ 是对角特征值矩阵。特征值的大小反映了对应特征向量方向上的方差贡献。
3.3 几何意义
特征向量指明了矩阵变换的主要方向,特征值指明了变换在该方向上的缩放倍率。最大的特征值对应的特征向量是数据方差最大的方向,次大的特征值对应次大方差方向,以此类推。这正是 PCA 的核心思想。
3.4 应用:PCA主成分分析
PCA通过特征分解找到数据方差最大的方向,将数据投影到这些方向上实现降维。步骤如下:
- 数据中心化(每个特征减去均值)
- 计算协方差矩阵
- 对协方差矩阵进行特征分解
- 选择最大的 k 个特征值对应的特征向量作为主成分
- 将数据投影到这些主成分上
import numpy as np
# 生成二维数据
np.random.seed(42)
X = np.random.randn(100, 2)
# 拉伸数据,使一个方向方差更大
X = X @ np.array([[3, 0], [0, 1]])
# 中心化
X_centered = X - X.mean(axis=0)
# 协方差矩阵
cov = X_centered.T @ X_centered / (X.shape[0] - 1)
# 特征分解
eigvals, eigvecs = np.linalg.eig(cov)
print("特征值:", eigvals)
print("特征向量:\n", eigvecs)
# 降到1维
k = 1
top_k_eigvecs = eigvecs[:, np.argsort(eigvals)[::-1][:k]]
X_pca = X_centered @ top_k_eigvecs
print("降维后形状:", X_pca.shape)
3.5 谱聚类
谱聚类利用数据的拉普拉斯矩阵的特征向量进行聚类。它比 K-Means 更能处理非线性分布的数据。核心步骤包括:构造相似度图、计算拉普拉斯矩阵、对拉普拉斯矩阵进行特征分解、用前 k 个特征向量做 K-Means 聚类。
3.6 NumPy计算特征值
import numpy as np
A = np.array([[4, -2], [1, 1]])
# 计算特征值和特征向量
eigvals, eigvecs = np.linalg.eig(A)
print("特征值:", eigvals)
print("特征向量:\n", eigvecs)
# 验证 Av = λv
v = eigvecs[:, 0]
lam = eigvals[0]
print("Av:", A @ v)
print("λv:", lam * v)
四、奇异值分解SVD
4.1 SVD的定义
奇异值分解(Singular Value Decomposition)是线性代数中最重要的矩阵分解之一。任意矩阵 A ∈ ℝᵐˣⁿ 都可以分解为三个矩阵的乘积:
A = UΣVᵀ
其中:
- U ∈ ℝᵐˣᵐ 是左奇异向量矩阵(正交矩阵)
- Σ ∈ ℝᵐˣⁿ 是对角矩阵,对角线元素为奇异值(从大到小排列)
- Vᵀ ∈ ℝⁿˣⁿ 是右奇异向量矩阵的转置(正交矩阵)
SVD 的优美之处在于它对任意形状的矩阵都适用(不要求方阵、不要求对称)。
4.2 与特征分解的关系
SVD 与特征分解紧密相关:
- AᵀA 的特征向量是 V 的列,特征值是奇异值的平方(σᵢ²)
- AAᵀ 的特征向量是 U 的列,特征值也是奇异值的平方
- 当 A 是实对称矩阵时,SVD 退化为特征分解
4.3 应用:矩阵降维
通过保留最大的 k 个奇异值及其对应的奇异向量,可以得到 A 的低秩近似 Aₖ = UₖΣₖVₖᵀ。这是信息压缩的理论基础——保留的奇异值占比决定了保留的信息量。
4.4 应用:图像压缩
一张灰度图像可以看作一个矩阵。通过 SVD 保留前 k 个奇异值,可以用更少的存储空间近似原始图像。例如,一张 1000×800 的图像,保留前 50 个奇异值,存储量从 800,000 降至 50×(1000+800+1) ≈ 90,050,压缩比接近 9 倍。
4.5 应用:推荐系统中的协同过滤
在推荐系统中,用户-物品评分矩阵通常非常稀疏且低秩。SVD(或 FunkSVD)将用户和物品映射到共享的隐空间,用户 i 对物品 j 的预测评分可表示为:r̂ᵢⱼ = uᵢᵀ vⱼ,其中 uᵢ 是用户隐向量,vⱼ 是物品隐向量。这正是矩阵分解推荐算法的核心。
4.6 Python实现
import numpy as np
from numpy.linalg import svd
# 创建矩阵
A = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]], dtype=float)
# SVD分解
U, s, Vt = svd(A)
print("U形状:", U.shape)
print("奇异值:", s)
print("Vt形状:", Vt.shape)
# 重建矩阵(满秩)
Sigma = np.zeros((3, 3))
np.fill_diagonal(Sigma, s)
A_reconstructed = U @ Sigma @ Vt
print("重建误差:", np.linalg.norm(A - A_reconstructed))
# 低秩近似(只保留前k个奇异值)
k = 2
U_k = U[:, :k]
s_k = s[:k]
Vt_k = Vt[:k, :]
Sigma_k = np.diag(s_k)
A_k = U_k @ Sigma_k @ Vt_k
print("低秩近似误差:", np.linalg.norm(A - A_k))
# 图像压缩示意
def compress_ratio(s, k):
"""计算SVD压缩比"""
m, n = 100, 100 # 假设图像尺寸
original = m * n
compressed = k * (m + n + 1)
return original / compressed
print("k=10压缩比:", compress_ratio(s, 10))
五、常见矩阵分解
5.1 LU分解
LU 分解将矩阵 A 分解为下三角矩阵 L 和上三角矩阵 U 的乘积:A = LU。它是高斯消元法的矩阵形式,主要用于求解线性方程组和计算行列式。在机器学习中,当需要多次求解具有相同系数矩阵的线性方程组时(如贝叶斯推断中的多次采样),LU 分解的预计算可以大幅提升效率。
5.2 QR分解
QR 分解将矩阵 A 分解为正交矩阵 Q 和上三角矩阵 R 的乘积:A = QR。QR 分解比 LU 分解数值稳定性更好,常用于最小二乘问题的求解。在机器学习中,QR 分解被用于线性回归的参数估计和特征选择算法(如 QR 分解用于找到线性无关的特征子集)。
5.3 Cholesky分解
Cholesky 分解适用于对称正定矩阵,将其分解为 A = LLᵀ,其中 L 是下三角矩阵。Cholesky 分解是 LU 分解的两倍效率,在以下场景广泛应用:
- 高斯过程回归:求解核矩阵的逆和计算对数边际似然
- 多元正态分布采样:通过 Cholesky 分解生成相关随机变量
- 优化算法:牛顿法中的海森矩阵求逆
5.4 各分解对比
| 分解 | 适用范围 | 主要应用 | 计算复杂度 |
| LU | 任意方阵 | 解线性方程组、求行列式 | O(n³) |
| QR | 任意矩阵 | 最小二乘、数值稳定求解 | O(mn²) |
| Cholesky | 对称正定矩阵 | 高斯过程、多元采样 | O(n³/3) |
| SVD | 任意矩阵 | 降维、压缩、推荐系统 | O(mn²) |
import numpy as np
from scipy import linalg
A = np.array([[3, 1, 1],
[1, 3, 1],
[1, 1, 3]], dtype=float)
# LU分解
P, L, U = linalg.lu(A)
print("L:\n", L)
print("U:\n", U)
# QR分解
Q, R = np.linalg.qr(A)
print("Q正交性:", Q.T @ Q)
# Cholesky分解
L_chol = np.linalg.cholesky(A)
print("Cholesky L:\n", L_chol)
print("验证 LL^T:\n", L_chol @ L_chol.T)
六、机器学习中的线性代数
6.1 数据表示(矩阵形式)
机器学习中,整个数据集通常用矩阵 X ∈ ℝⁿˣᵈ 表示,其中 n 是样本数,d 是特征数。标签向量 y ∈ ℝⁿ。这种统一的矩阵表示使得所有算法都可以用线性代数语言描述和实现。
在深度学习中,一张 RGB 图像可以表示为三维张量(高度×宽度×通道),一个批次的数据集则是四维张量(批次×高度×宽度×通道)。张量运算正是线性代数的推广。
6.2 线性变换
线性变换是机器学习中最基本的操作。一个神经网络层本质上就是一个线性变换(矩阵乘法)加上一个非线性激活函数。形式化地:z = Wx + b,其中 W 是权重矩阵,x 是输入向量,b 是偏置向量。多个线性变换的复合本质上仍然是一个线性变换,这就是为什么需要非线性激活函数来增强网络的表达能力。
6.3 内积与相似度度量
向量的内积(点积)直接衡量两个向量的相似度。在机器学习中广泛应用:
- 余弦相似度:cos(θ) = (a·b) / (||a|| ||b||),衡量方向相似度,忽略量级
- 注意机制:Transformer 中的自注意力计算 Query 和 Key 的点积
- 核方法:核函数隐式计算高维空间中的内积
- 线性判别分析:最大化类间散度与类内散度的比值
6.4 正则化中的范数
正则化通过在损失函数中添加参数的范数惩罚项来防止过拟合:
L1范数(曼哈顿范数):||w||₁ = ∑|wᵢ|。L1 正则化(Lasso)产生稀疏解——许多参数被压缩为 0,实现特征选择。
L2范数(欧几里得范数):||w||₂ = √(∑wᵢ²)。L2 正则化(Ridge)使参数均匀缩小但不产生严格的 0,对异常值更鲁棒。
弹性网络:同时使用 L1 和 L2 范数,兼顾特征选择和稳定性。
import numpy as np
w = np.array([3.0, -1.5, 0.0, 2.0, 0.5])
# L1范数
l1 = np.sum(np.abs(w))
print("L1范数:", l1)
# L2范数
l2 = np.linalg.norm(w)
print("L2范数:", l2)
# L1正则化损失(λ=0.1)
lambda_val = 0.1
loss_l1 = lambda_val * l1
# L2正则化损失
loss_l2 = lambda_val * 0.5 * l2**2
print("L1惩罚项:", loss_l1)
print("L2惩罚项:", loss_l2)
6.5 协方差矩阵
协方差矩阵是机器学习中的核心概念,它编码了特征之间的线性关系。对于数据矩阵 X(已中心化),协方差矩阵为 Σ = (1/(n-1))XᵀX。
协方差矩阵具有以下重要性质:
- 是对称半正定矩阵(所有特征值非负)
- 对角线元素是各特征的方差
- 非对角线元素是特征间的协方差(线性相关程度)
- 特征向量指向数据方差最大的方向 —— 这正是 PCA 的理论基础
在实际应用中,协方差矩阵的特征值分解揭示了数据的内在结构:大的特征值对应重要模式,小的特征值往往对应噪声。这就是为什么可以通过截断小的特征值来实现降噪和降维。
import numpy as np
# 生成相关数据
np.random.seed(42)
X = np.random.randn(100, 3)
# 人为引入相关性
X[:, 1] = 0.7 * X[:, 0] + 0.3 * X[:, 1]
X[:, 2] = 0.3 * X[:, 0] + 0.5 * X[:, 1] + 0.2 * X[:, 2]
# 中心化
X_centered = X - X.mean(axis=0)
# 协方差矩阵
cov = X_centered.T @ X_centered / (X.shape[0] - 1)
print("协方差矩阵:\n", cov)
# 相关系数矩阵
std = np.std(X_centered, axis=0)
corr = cov / np.outer(std, std)
print("相关系数矩阵:\n", corr)
# 特征分解
eigvals, eigvecs = np.linalg.eigh(cov)
print("特征值:", eigvals)
print("方差解释率:", eigvals / eigvals.sum())
七、核心要点总结
1. 向量是数据的基本单元:每个样本都是一个特征向量,向量运算构成了机器学习操作的基础。
2. 矩阵是数据集的自然表示:矩阵乘法、转置、求逆等操作贯穿所有机器学习算法。
3. 特征值分解揭示了数据的主方向:PCA、谱聚类等算法本质上都在寻找数据的"主方向"。
4. SVD是最通用的矩阵分解工具:适用于任意矩阵,在降维、压缩、推荐系统中都有重要应用。
5. 矩阵分解是高效计算的核心:LU、QR、Cholesky等分解为大规模计算提供了数值稳定的基础。
6. 范数构建了模型的复杂度约束:L1、L2正则化通过范数惩罚控制模型复杂度,防止过拟合。
7. 协方差矩阵刻画了特征关系:理解协方差矩阵的结构是掌握数据分布和降维算法的关键。
8. Python(NumPy/SciPy)提供了完整的线性代数工具链:所有理论都可以通过简洁的代码实现和验证。
八、进一步思考
线性代数是机器学习的数学语言。掌握线性代数不仅仅是会计算矩阵乘法或特征值,更重要的是建立以下思维模式:
从几何视角理解数据:将高维数据想象为向量空间中的点分布,降维就是寻找合适的投影方向,分类就是寻找分隔超平面。
从代数视角理解算法:所有机器学习算法最终都可以表示为矩阵运算的组合,理解这些运算的数学性质对算法调优和故障排查至关重要。
从计算视角理解效率:直接计算逆矩阵的复杂度是 O(n³),而通过矩阵分解(如 Cholesky)可以将计算复杂度降低数倍。在大数据时代,高效的线性代数计算是算法落地的关键。
推荐进一步学习资源:
- Gilbert Strang 教授的《线性代数及其应用》——经典教材,侧重直观理解
- 《Matrix Methods in Data Mining and Pattern Recognition》——侧重机器学习应用
- 动手练习:尝试用 NumPy 从零实现 PCA、线性回归、K-Means 聚类等经典算法,深入理解每一步的线性代数本质
线性代数是机器学习大厦的地基。地基越深,大厦才能建得越高。—— 学习心得