Skip to main content

线性代数的几何意义 - 任广千/谢聪/胡翠芳

wt3bos

本书使用向量的概念对国内高校工科"线性代数"的课程内容进行了较全面的几何分析,把上百个概念和定理的几何意义串在一起。

关于作者

任广千、谢聪、胡翠芳 是线性代数教育领域的实践者:

  • 高校教师:长期从事线性代数教学与研究
  • 教育创新者:致力于将抽象的代数概念几何化、直观化
  • 技术作家:希望通过通俗的方式让更多人理解线性代数的本质

核心内容

1. 向量的几何意义

import numpy as np
import matplotlib.pyplot as plt

# 向量:既有大小又有方向的量
# 几何表示:从原点出发的有向线段

# 二维向量
v1 = np.array([3, 2])
v2 = np.array([-1, 4])

# 向量加法:平行四边形法则
v_add = v1 + v2 # [2, 6]

# 向量减法:三角形法则
v_sub = v1 - v2 # [4, -2]

# 数乘:缩放或反向
v_scaled = 2 * v1 # [6, 4]
v_negated = -v1 # [-3, -2]

# 向量的模(长度)
norm = np.linalg.norm(v1) # √(3² + 2²) = √13

# 单位向量(方向不变,长度为 1)
v_unit = v1 / np.linalg.norm(v1)

# 点积(内积):衡量两个向量的"相似程度"
# a · b = |a||b|cos(θ) = a₁b₁ + a₂b₂
dot_product = np.dot(v1, v2)

# 夹角
cos_theta = np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2))
theta = np.arccos(np.clip(cos_theta, -1, 1))

# 应用:
# - 投影:一个向量在另一个向量上的投影
# - 正交:点积为 0 表示垂直
# - 相似度:余弦相似度 = cos(θ)

2. 矩阵的几何意义

# 矩阵:线性变换的表示
# 矩阵 × 向量 = 对向量进行变换

A = np.array([[2, 0],
[0, 1]])

v = np.array([1, 1])

# 矩阵变换
v_transformed = A @ v # [2, 1]
# 这个矩阵表示 x 方向拉伸 2 倍

# 常见变换矩阵
# 1. 缩放变换
scale_x = np.array([[2, 0],
[0, 1]]) # x 方向拉伸 2 倍

scale_y = np.array([[1, 0],
[0, 0.5]]) # y 方向压缩 2 倍

# 2. 旋转变换(逆时针θ角)
theta = np.pi / 4 # 45 度
rotation = np.array([
[np.cos(theta), -np.sin(theta)],
[np.sin(theta), np.cos(theta)]
])

# 3. 剪切变换
shear_x = np.array([[1, 1],
[0, 1]]) # x 方向剪切

shear_y = np.array([[1, 0],
[1, 1]]) # y 方向剪切

# 4. 反射变换
reflect_x = np.array([[1, 0],
[0, -1]]) # 关于 x 轴反射

reflect_y = np.array([[-1, 0],
[0, 1]]) # 关于 y 轴反射

# 矩阵乘法:复合变换
# C = AB 表示先进行 B 变换,再进行 A 变换
combined = rotation @ scale_x # 先缩放,再旋转

3. 行列式的几何意义

# 行列式:线性变换的"缩放因子"
# |det(A)| > 1: 面积/体积放大
# |det(A)| < 1: 面积/体积缩小
# det(A) = 0: 降维(不可逆)
# det(A) < 0: 方向翻转

A = np.array([[2, 0],
[0, 3]])

det_A = np.linalg.det(A) # 6
# 表示面积放大了 6 倍

B = np.array([[1, 2],
[3, 4]])

det_B = np.linalg.det(B) # -2
# 负号表示方向翻转(如镜像)

# 几何应用
# 1. 平行四边形面积 = |det([a, b])|
# 其中 a, b 是相邻两边的向量

# 2. 平行六面体体积 = |det([a, b, c])|

# 3. 判断矩阵是否可逆
if np.isclose(det_A, 0):
print("矩阵不可逆(降维)")
else:
print("矩阵可逆")

# 4. 判断线性方程组解的情况
# det(A) ≠ 0: 唯一解
# det(A) = 0: 无解或无穷多解

4. 特征值与特征向量

# 定义:Av = λv
# 特征向量 v: 经过变换 A 后,方向不变的向量
# 特征值λ: 特征向量的缩放倍数

A = np.array([[3, 1],
[0, 2]])

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

# λ₁ = 3, v₁ = [1, 0]
# λ₂ = 2, v₂ = [-0.707, 0.707]

# 几何意义
# 1. 特征向量是变换的"主轴"方向
# 2. 特征值是该方向上的缩放因子

# 应用:主成分分析 (PCA)
from sklearn.decomposition import PCA

pca = PCA(n_components=2)
X_pca = pca.fit_transform(X)

# 协方差矩阵的特征值 = 各主成分的方差
# 特征向量 = 主成分方向

# 应用:矩阵对角化
# A = PDP^(-1)
# 其中 D 是对角矩阵(对角线是特征值)
# P 的列是特征向量

# 应用:马尔可夫链稳态
# 稳态分布是转移矩阵特征值为 1 的特征向量

# 应用:Google PageRank
# 网页重要性是链接矩阵的主特征向量

5. 线性方程组的几何意义

# 方程组 Ax = b 的几何解释

# 行观点:每个方程表示一个平面(或直线)
# 解是这些平面的交点

# 列观点:b 是 A 的列向量的线性组合
# 解是组合系数

A = np.array([[2, 1],
[1, -1]])
b = np.array([5, 1])

# 解法 1:直接求解
x = np.linalg.solve(A, b) # [2, 1]

# 解法 2:逆矩阵
A_inv = np.linalg.inv(A)
x = A_inv @ b

# 解的存在性
# rank(A) = rank([A|b]) = n: 唯一解
# rank(A) = rank([A|b]) < n: 无穷多解
# rank(A) ≠ rank([A|b]): 无解

# 齐次方程组 Ax = 0
# 总有零解
# det(A) ≠ 0: 只有零解
# det(A) = 0: 有非零解(无穷多解)

# 最小二乘解(当无解时)
# 找到使 ||Ax - b||² 最小的 x
x_ls = np.linalg.lstsq(A, b, rcond=None)[0]

6. 向量空间与基

# 向量空间:对加法和数乘封闭的集合

# 基 (Basis): 线性无关的生成集
# 维数:基中向量的个数

# R² 的标准基
e1 = np.array([1, 0])
e2 = np.array([0, 1])

# 任意向量都可表示为基的线性组合
v = np.array([3, 4])
v = 3 * e1 + 4 * e2

# 非标准基
b1 = np.array([1, 1])
b2 = np.array([1, -1])

# v 在新基下的坐标
B = np.column_stack([b1, b2])
v_new_coords = np.linalg.solve(B, v) # [3.5, -0.5]

# 验证
v_reconstructed = v_new_coords[0] * b1 + v_new_coords[1] * b2

# 基变换矩阵(过渡矩阵)
# 从旧基到新基的变换

# 应用:坐标变换
# 在计算机图形学中,经常需要在不同坐标系间转换
# 世界坐标 → 相机坐标 → 屏幕坐标

# 应用:特征脸 (Eigenfaces)
# 人脸图像可以表示为"特征脸"基的线性组合

7. 正交性与投影

# 正交:向量垂直(点积为 0)
# 标准正交:正交且为单位向量

v1 = np.array([1, 0, 0])
v2 = np.array([0, 1, 0])
v3 = np.array([0, 0, 1])

# 标准正交基
# v1·v2 = 0, v1·v3 = 0, v2·v3 = 0
# ||v1|| = ||v2|| = ||v3|| = 1

# 投影:一个向量在另一个向量上的"影子"
# proj_b(a) = (a·b / b·b) * b

def project(a, b):
return np.dot(a, b) / np.dot(b, b) * b

# 正交投影矩阵
# P = A(A^T A)^(-1) A^T

def projection_matrix(A):
return A @ np.linalg.inv(A.T @ A) @ A.T

# 最小二乘的几何解释
# 当 Ax = b 无解时,找到 b 在 A 列空间上的投影

# Gram-Schmidt 正交化
# 将任意基转换为标准正交基

def gram_schmidt(vectors):
ortho_basis = []
for v in vectors:
u = v.copy()
for e in ortho_basis:
u -= project(v, e)
if np.linalg.norm(u) > 1e-10:
ortho_basis.append(u / np.linalg.norm(u))
return np.array(ortho_basis)

# QR 分解:A = QR
# Q 是正交矩阵,R 是上三角矩阵
Q, R = np.linalg.qr(A)

8. 奇异值分解 (SVD)

# SVD: A = UΣV^T
# 任意矩阵都可以分解为三个矩阵的乘积

# U: m×m 正交矩阵(左奇异向量)
# Σ: m×n 对角矩阵(奇异值)
# V: n×n 正交矩阵(右奇异向量)

A = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[10, 11, 12]])

U, sigma, VT = np.linalg.svd(A, full_matrices=False)

# 几何意义
# 1. 任何线性变换都可以分解为:
# 旋转 (V^T) → 缩放 (Σ) → 旋转 (U)

# 2. 奇异值表示各方向的重要性

# 应用:数据压缩
# 只保留前 k 个大的奇异值
k = 2
A_approx = U[:, :k] @ np.diag(sigma[:k]) @ VT[:k, :]

# 应用:推荐系统
# 用户 - 物品矩阵的 SVD
# 发现隐含的用户偏好和物品特征

# 应用:图像压缩
# 将图像视为矩阵,进行 SVD 分解
# 保留主要奇异值,实现压缩

# 应用:去噪
# 小奇异值通常对应噪声
# 截断 SVD 可以去除噪声

经典摘录

线性代数的本质是空间变换。向量是空间中的箭头,矩阵是改变箭头的机器。

行列式告诉你空间被拉伸或压缩了多少,特征向量告诉你哪些方向在变换中保持不变。

矩阵乘法不是数字的乘法,而是变换的复合。

SVD 揭示了任意矩阵的内在结构,是线性代数中最有用的分解。

理解线性代数的几何意义,让抽象的公式变得直观可见。

读书心得

《线性代数的几何意义》是一本独特的线性代数入门书籍。与传统教材不同,这本书从几何视角出发,让抽象的代数概念变得直观可感。

书中对我影响最深的是矩阵作为线性变换的观点。一旦理解了矩阵乘法就是对向量进行变换,很多原本抽象的概念就变得清晰了:

  • 行列式是变换的缩放因子
  • 特征向量是变换中方向不变的向量
  • SVD 是旋转 - 缩放 - 旋转的分解

特征值与特征向量的几何解释也非常精彩。它们不是凭空定义的概念,而是描述了变换的"主轴"和"缩放倍数"。理解了这一点,PCA、PageRank 等应用就变得容易理解了。

SVD 分解的部分让我印象深刻。这个看似复杂的分解,几何上只是三个简单变换的复合:旋转→缩放→旋转。理解了这一点,SVD 在数据压缩、推荐系统、图像处理等领域的应用就水到渠成了。

对于机器学习从业者来说,线性代数是必备基础:

  • 神经网络 = 矩阵乘法 + 非线性激活
  • PCA = 特征值分解
  • 最小二乘 = 向量投影
  • 推荐系统 = 矩阵分解

这本书能帮助读者建立对线性代数的直观理解,是学习机器学习和深度学习的良好前置知识。

建议配合 3Blue1Brown 的"线性代数的本质"系列视频一起学习,几何直观 + 代数推导,效果更佳。