Skip to content
Published on

线性代数完全攻略:从向量到 SVD 的零基础进阶指南

分享
Authors

引言

线性代数(Linear Algebra)是现代数学与工程学的核心基础。从数据科学、机器学习、计算机图形学,到量子力学,几乎所有领域都要用到它。本指南从向量与矩阵的基础开始,一路讲到 SVD(奇异值分解),系统地梳理线性代数的核心概念。

参考资料:

  • Gilbert Strang, MIT OCW 18.06 Linear Algebra
  • 3Blue1Brown: Essence of Linear Algebra (YouTube)
  • NumPy 官方文档(numpy.org)
  • scikit-learn PCA 文档

1. 向量 (Vectors)

向量的定义与表示

向量(vector)是同时具有大小(magnitude)和方向(direction)的数学对象。nn 维向量 v\mathbf{v} 表示如下。

v=(v1v2vn)Rn\mathbf{v} = \begin{pmatrix} v_1 \\ v_2 \\ \vdots \\ v_n \end{pmatrix} \in \mathbb{R}^n

向量运算

加法与标量乘法:

u+v=(u1+v1u2+v2),cv=(cv1cv2)\mathbf{u} + \mathbf{v} = \begin{pmatrix} u_1 + v_1 \\ u_2 + v_2 \end{pmatrix}, \quad c\mathbf{v} = \begin{pmatrix} cv_1 \\ cv_2 \end{pmatrix}

内积(Dot Product):

uv=i=1nuivi=uvcosθ\mathbf{u} \cdot \mathbf{v} = \sum_{i=1}^{n} u_i v_i = \|\mathbf{u}\| \|\mathbf{v}\| \cos\theta

内积为 0 时,两个向量互相正交(orthogonal)。

外积(Cross Product) — 仅在 3 维空间中定义:

u×v=ijku1u2u3v1v2v3\mathbf{u} \times \mathbf{v} = \begin{vmatrix} \mathbf{i} & \mathbf{j} & \mathbf{k} \\ u_1 & u_2 & u_3 \\ v_1 & v_2 & v_3 \end{vmatrix}

范数(Norm)

  • L1 范数: v1=ivi\|\mathbf{v}\|_1 = \sum_{i} |v_i|
  • L2 范数(欧几里得): v2=ivi2\|\mathbf{v}\|_2 = \sqrt{\sum_{i} v_i^2}
  • Lp 范数: vp=(ivip)1/p\|\mathbf{v}\|_p = \left(\sum_{i} |v_i|^p\right)^{1/p}

单位向量(Unit Vector):

v^=vv\hat{\mathbf{v}} = \frac{\mathbf{v}}{\|\mathbf{v}\|}

import numpy as np

# 定义向量
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

# 向量加法
print("加法:", a + b)          # [5 7 9]

# 标量乘法
print("标量乘法:", 3 * a)     # [3 6 9]

# 内积
dot = np.dot(a, b)
print("内积:", dot)             # 32

# 外积
cross = np.cross(a, b)
print("外积:", cross)           # [-3  6 -3]

# L2 范数
norm_l2 = np.linalg.norm(a)
print("L2 范数:", norm_l2)      # 3.7416...

# L1 范数
norm_l1 = np.linalg.norm(a, ord=1)
print("L1 范数:", norm_l1)      # 6.0

# 单位向量
unit = a / np.linalg.norm(a)
print("单位向量:", unit)
print("模长确认:", np.linalg.norm(unit))  # 1.0

# 两向量的夹角
cos_theta = np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
angle = np.arccos(cos_theta)
print("角度(弧度):", angle)
print("角度(度):", np.degrees(angle))

2. 矩阵 (Matrices)

矩阵的定义与种类

m×nm \times n 矩阵是由 mm 行、nn 列数字排列成的矩形阵列。

A=(a11a12a1na21a22a2nam1am2amn)A = \begin{pmatrix} a_{11} & a_{12} & \cdots & a_{1n} \\ a_{21} & a_{22} & \cdots & a_{2n} \\ \vdots & \vdots & \ddots & \vdots \\ a_{m1} & a_{m2} & \cdots & a_{mn} \end{pmatrix}

主要矩阵类型:

类型定义示例
单位矩阵 (Identity)Iij=1I_{ij} = 1 (i=j), 0 (i≠j)I2=(1001)I_2 = \begin{pmatrix}1&0\\0&1\end{pmatrix}
对角矩阵 (Diagonal)对角线外全部为 0diag(d1,d2)\text{diag}(d_1, d_2)
对称矩阵 (Symmetric)A=ATA = A^T
正交矩阵 (Orthogonal)ATA=IA^T A = I旋转矩阵

矩阵运算

矩阵乘法 (Matrix Multiplication):

(AB)ij=k=1naikbkj(AB)_{ij} = \sum_{k=1}^{n} a_{ik} b_{kj}

矩阵乘法不满足交换律:ABBAAB \neq BA(一般情况下)

转置矩阵 (Transpose):

(AT)ij=Aji(A^T)_{ij} = A_{ji}

逆矩阵 (Inverse):

方阵 AA 的逆矩阵 A1A^{-1} 满足 AA1=A1A=IAA^{-1} = A^{-1}A = I。逆矩阵只有在行列式不为 0 时才存在。

import numpy as np

# 定义矩阵
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])

# 矩阵加法
print("矩阵加法:\n", A + B)

# 矩阵乘法
C = A @ B
print("矩阵乘法:\n", C)

# 逐元素乘法 (Hadamard product)
print("逐元素乘法:\n", A * B)

# 转置矩阵
print("转置矩阵:\n", A.T)

# 逆矩阵
A_inv = np.linalg.inv(A)
print("逆矩阵:\n", A_inv)

# 验证: A @ A_inv = I
print("验证(A @ A_inv):\n", A @ A_inv)

# 单位矩阵
I = np.eye(3)
print("3x3 单位矩阵:\n", I)

# 对角矩阵
D = np.diag([1, 2, 3])
print("对角矩阵:\n", D)

# 生成对称矩阵
S = A @ A.T
print("对称矩阵(A @ A^T):\n", S)
print("验证对称性:", np.allclose(S, S.T))

3. 行列式 (Determinant)

行列式的定义与计算

行列式(determinant)是在方阵上定义的标量值,蕴含着矩阵的多种特性。

2×2 行列式:

det(abcd)=adbc\det\begin{pmatrix} a & b \\ c & d \end{pmatrix} = ad - bc

3×3 行列式(萨吕法则,Sarrus' Rule):

det(A)=a11(a22a33a23a32)a12(a21a33a23a31)+a13(a21a32a22a31)\det(A) = a_{11}(a_{22}a_{33} - a_{23}a_{32}) - a_{12}(a_{21}a_{33} - a_{23}a_{31}) + a_{13}(a_{21}a_{32} - a_{22}a_{31})

行列式的性质

  1. det(I)=1\det(I) = 1
  2. det(AB)=det(A)det(B)\det(AB) = \det(A)\det(B)
  3. det(AT)=det(A)\det(A^T) = \det(A)
  4. det(A1)=1/det(A)\det(A^{-1}) = 1/\det(A)
  5. 行列式为 0 时逆矩阵不存在(奇异矩阵,singular matrix)
  6. 几何意义:行向量所构成的平行六面体的体积

克拉默法则 (Cramer's Rule)

线性方程组 Ax=bA\mathbf{x} = \mathbf{b} 的解:

xi=det(Ai)det(A)x_i = \frac{\det(A_i)}{\det(A)}

这里 AiA_i 是将 AA 的第 ii 列替换为 b\mathbf{b} 后得到的矩阵。

import numpy as np

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

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

# 计算行列式
det_A = np.linalg.det(A)
det_B = np.linalg.det(B)
print("det(A):", det_A)   # 接近于 0(接近奇异矩阵)
print("det(B):", det_B)   # 4.0

# 验证性质: det(A@B) = det(A)*det(B)
print("det(A)*det(B):", det_A * det_B)
print("det(A@B):", np.linalg.det(A @ B))

# 用克拉默法则求解线性方程组
A_sys = np.array([[2, 1], [5, 3]], dtype=float)
b_sys = np.array([1, 2], dtype=float)

det_A_sys = np.linalg.det(A_sys)

# 计算 x1
A1 = A_sys.copy()
A1[:, 0] = b_sys
x1 = np.linalg.det(A1) / det_A_sys

# 计算 x2
A2 = A_sys.copy()
A2[:, 1] = b_sys
x2 = np.linalg.det(A2) / det_A_sys

print(f"x1 = {x1}, x2 = {x2}")
# 用 numpy linalg solve 验证
x = np.linalg.solve(A_sys, b_sys)
print("numpy solve:", x)

4. 线性方程组与高斯消元法

线性方程组

关于 nn 个未知数的 mm 个线性方程:

a11x1+a12x2++a1nxn=b1a_{11}x_1 + a_{12}x_2 + \cdots + a_{1n}x_n = b_1 a21x1+a22x2++a2nxn=b2a_{21}x_1 + a_{22}x_2 + \cdots + a_{2n}x_n = b_2 \vdots am1x1+am2x2++amnxn=bma_{m1}x_1 + a_{m2}x_2 + \cdots + a_{mn}x_n = b_m

矩阵形式:Ax=bA\mathbf{x} = \mathbf{b}

增广矩阵 (Augmented Matrix)

[Ab]=(a11a1nb1am1amnbm)[A|\mathbf{b}] = \left(\begin{array}{ccc|c} a_{11} & \cdots & a_{1n} & b_1 \\ \vdots & \ddots & \vdots & \vdots \\ a_{m1} & \cdots & a_{mn} & b_m \end{array}\right)

高斯消元法 (Gaussian Elimination)

初等行变换(Elementary Row Operations):

  1. 交换两行:RiRjR_i \leftrightarrow R_j
  2. 给某一行乘以标量:RicRiR_i \leftarrow c \cdot R_i
  3. 把某一行的倍数加到另一行:RiRi+cRjR_i \leftarrow R_i + c \cdot R_j

通过这些运算,可以得到行阶梯形(Row Echelon Form, REF)或简化行阶梯形(Reduced REF)。

LU 分解

A=LUA = LU:将 AA 分解为下三角矩阵 LL 与上三角矩阵 UU 的乘积

import numpy as np
from scipy import linalg

# 线性方程组: 2x + y = 5, x + 3y = 10
A = np.array([[2, 1], [1, 3]], dtype=float)
b = np.array([5, 10], dtype=float)

# numpy linalg.solve
x = np.linalg.solve(A, b)
print("解:", x)  # [1. 3.]

# 实现高斯-若尔当消元法
def gauss_jordan(A, b):
    n = len(b)
    # 生成增广矩阵
    aug = np.hstack([A.astype(float), b.reshape(-1, 1).astype(float)])

    for col in range(n):
        # 选取主元(部分主元法)
        max_row = np.argmax(np.abs(aug[col:, col])) + col
        aug[[col, max_row]] = aug[[max_row, col]]

        # 归一化主元所在行
        aug[col] = aug[col] / aug[col, col]

        # 在其余行中消元
        for row in range(n):
            if row != col:
                aug[row] -= aug[row, col] * aug[col]

    return aug[:, -1]

solution = gauss_jordan(A.copy(), b.copy())
print("高斯-若尔当解:", solution)

# LU 分解
P, L, U = linalg.lu(A)
print("L 矩阵:\n", L)
print("U 矩阵:\n", U)
print("P 矩阵:\n", P)

# 用 LU 分解求解线性方程组
x_lu = linalg.solve(A, b)
print("LU 分解解:", x_lu)

5. 向量空间 (Vector Spaces)

向量空间的定义

集合 VV 要成为向量空间,须对加法与标量乘法满足以下 8 条公理:

  1. 封闭性 (Closure): u,vVu+vV\mathbf{u}, \mathbf{v} \in V \Rightarrow \mathbf{u} + \mathbf{v} \in V
  2. 交换律: u+v=v+u\mathbf{u} + \mathbf{v} = \mathbf{v} + \mathbf{u}
  3. 结合律: (u+v)+w=u+(v+w)(\mathbf{u} + \mathbf{v}) + \mathbf{w} = \mathbf{u} + (\mathbf{v} + \mathbf{w})
  4. 零向量存在: v+0=v\mathbf{v} + \mathbf{0} = \mathbf{v}
  5. 逆元存在: v+(v)=0\mathbf{v} + (-\mathbf{v}) = \mathbf{0}
  6. 标量封闭性: cR,vVcvVc \in \mathbb{R}, \mathbf{v} \in V \Rightarrow c\mathbf{v} \in V
  7. 分配律 1: c(u+v)=cu+cvc(\mathbf{u} + \mathbf{v}) = c\mathbf{u} + c\mathbf{v}
  8. 分配律 2: (c+d)v=cv+dv(c + d)\mathbf{v} = c\mathbf{v} + d\mathbf{v}

线性无关 (Linear Independence)

向量集合 {v1,v2,,vk}\{\mathbf{v}_1, \mathbf{v}_2, \ldots, \mathbf{v}_k\}线性无关的,是指:

c1v1+c2v2++ckvk=0    c1=c2==ck=0c_1\mathbf{v}_1 + c_2\mathbf{v}_2 + \cdots + c_k\mathbf{v}_k = \mathbf{0} \implies c_1 = c_2 = \cdots = c_k = 0

也就是说,只能存在平凡解(trivial solution)。

基 (Basis) 与维数 (Dimension)

向量空间 VV(basis)是张成(span) VV 的一组线性无关向量。

  • 维数(dimension): 基中元素的个数
  • Rn\mathbb{R}^n 的标准基:e1,e2,,en\mathbf{e}_1, \mathbf{e}_2, \ldots, \mathbf{e}_n

行空间、列空间、零空间

对于矩阵 ARm×nA \in \mathbb{R}^{m \times n}

  • 行空间 (Row Space):AA 的行向量张成的空间,Rn\subseteq \mathbb{R}^n
  • 列空间 (Column Space):AA 的列向量张成的空间,Rm\subseteq \mathbb{R}^m
  • 零空间 (Null Space): Ax=0A\mathbf{x} = \mathbf{0} 的解集,Rn\subseteq \mathbb{R}^n
  • 维数定理: rank(A)+nullity(A)=n\text{rank}(A) + \text{nullity}(A) = n

秩 (Rank)

rank(A)=dim(Row Space)=dim(Column Space)\text{rank}(A) = \dim(\text{Row Space}) = \dim(\text{Column Space})

import numpy as np

A = np.array([[1, 2, 3],
              [4, 5, 6],
              [2, 4, 6]])  # 第 3 行是第 1 行的 2 倍(线性相关)

# 计算秩
rank = np.linalg.matrix_rank(A)
print("秩:", rank)  # 2

# 计算零空间 (null space)
from scipy.linalg import null_space
ns = null_space(A)
print("零空间:\n", ns)

# 列空间的基(利用 QR 分解)
Q, R = np.linalg.qr(A)
print("列空间的基(Q 的前 rank 列):\n", Q[:, :rank])

# 验证线性无关的例子
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])
print("v1, v2, v3 的秩:", np.linalg.matrix_rank(M))  # 3 = 线性无关

v4 = np.array([1, 2, 3])
v5 = np.array([2, 4, 6])  # v5 = 2*v4
M2 = np.column_stack([v4, v5])
print("v4, v5 的秩:", np.linalg.matrix_rank(M2))  # 1 = 线性相关

6. 线性变换 (Linear Transformations)

线性变换的定义

函数 T:VWT: V \to W 要成为线性变换,须满足:

  1. T(u+v)=T(u)+T(v)T(\mathbf{u} + \mathbf{v}) = T(\mathbf{u}) + T(\mathbf{v}) (可加性)
  2. T(cv)=cT(v)T(c\mathbf{v}) = cT(\mathbf{v}) (齐次性)

矩阵表示

所有线性变换都可以用矩阵表示:T(x)=AxT(\mathbf{x}) = A\mathbf{x}

核 (Kernel): ker(T)={vV:T(v)=0}\ker(T) = \{\mathbf{v} \in V : T(\mathbf{v}) = \mathbf{0}\}

像 (Image): Im(T)={T(v):vV}\text{Im}(T) = \{T(\mathbf{v}) : \mathbf{v} \in V\}

维数定理: dim(kerT)+dim(ImT)=dimV\dim(\ker T) + \dim(\text{Im} T) = \dim V

几何变换

2 维空间中主要的变换矩阵:

旋转矩阵(角度 θ\theta): R(θ)=(cosθsinθsinθcosθ)R(\theta) = \begin{pmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{pmatrix}

关于 x 轴的反射: Fx=(1001)F_x = \begin{pmatrix} 1 & 0 \\ 0 & -1 \end{pmatrix}

均匀缩放(比例 s): S=(s00s)S = \begin{pmatrix} s & 0 \\ 0 & s \end{pmatrix}

import numpy as np
import matplotlib.pyplot as plt

# 旋转变换
def rotation_matrix(theta):
    return np.array([[np.cos(theta), -np.sin(theta)],
                     [np.sin(theta),  np.cos(theta)]])

# 旋转 45 度
theta = np.pi / 4
R = rotation_matrix(theta)
print("旋转 45 度的矩阵:\n", R)

# 变换向量
v = np.array([1, 0])
v_rotated = R @ v
print("旋转后的向量:", v_rotated)  # [0.707, 0.707]

# 剪切变换 (shear)
shear = np.array([[1, 1],
                  [0, 1]])

# 变换单位正方形的顶点
corners = np.array([[0, 1, 1, 0, 0],
                    [0, 0, 1, 1, 0]])

transformed = shear @ corners
print("剪切变换后的顶点:\n", transformed)

# 验证正交矩阵
print("R^T @ R =\n", R.T @ R)  # 单位矩阵
print("det(R) =", np.linalg.det(R))  # 1

7. 内积空间 (Inner Product Spaces)

内积的定义

内积(inner product) ,:V×VR\langle \cdot, \cdot \rangle: V \times V \to \mathbb{R} 满足以下条件:

  1. 正定性: v,v0\langle \mathbf{v}, \mathbf{v} \rangle \geq 0,等号仅当 v=0\mathbf{v} = \mathbf{0} 时成立
  2. 对称性: u,v=v,u\langle \mathbf{u}, \mathbf{v} \rangle = \langle \mathbf{v}, \mathbf{u} \rangle
  3. 线性性: au+bv,w=au,w+bv,w\langle a\mathbf{u} + b\mathbf{v}, \mathbf{w} \rangle = a\langle \mathbf{u}, \mathbf{w} \rangle + b\langle \mathbf{v}, \mathbf{w} \rangle

柯西-施瓦茨不等式

u,vuv|\langle \mathbf{u}, \mathbf{v} \rangle| \leq \|\mathbf{u}\| \cdot \|\mathbf{v}\|

等号当 u\mathbf{u}v\mathbf{v} 平行时成立。

格拉姆-施密特正交化过程 (Gram-Schmidt Process)

从一组线性无关的向量出发,构造标准正交基(orthonormal basis)。

给定向量 v1,v2,,vk\mathbf{v}_1, \mathbf{v}_2, \ldots, \mathbf{v}_k

u1=v1\mathbf{u}_1 = \mathbf{v}_1 u2=v2v2,u1u1,u1u1\mathbf{u}_2 = \mathbf{v}_2 - \frac{\langle \mathbf{v}_2, \mathbf{u}_1 \rangle}{\langle \mathbf{u}_1, \mathbf{u}_1 \rangle} \mathbf{u}_1

一般地:

uk=vkj=1k1vk,ujuj,ujuj\mathbf{u}_k = \mathbf{v}_k - \sum_{j=1}^{k-1} \frac{\langle \mathbf{v}_k, \mathbf{u}_j \rangle}{\langle \mathbf{u}_j, \mathbf{u}_j \rangle} \mathbf{u}_j

最后对每个 ui\mathbf{u}_i 做归一化。

import numpy as np

def gram_schmidt(vectors):
    """格拉姆-施密特正交化"""
    basis = []
    for v in vectors:
        w = v.copy().astype(float)
        for b in basis:
            w -= np.dot(v, b) * b
        norm = np.linalg.norm(w)
        if norm > 1e-10:
            basis.append(w / norm)
    return np.array(basis)

# 线性无关的向量
v1 = np.array([1, 1, 0])
v2 = np.array([1, 0, 1])
v3 = np.array([0, 1, 1])

# 应用格拉姆-施密特正交化
basis = gram_schmidt([v1, v2, v3])
print("标准正交基:\n", basis)

# 验证正交性
print("验证内积(应为 0):")
print("e1 dot e2:", np.dot(basis[0], basis[1]))
print("e1 dot e3:", np.dot(basis[0], basis[2]))
print("e2 dot e3:", np.dot(basis[1], basis[2]))

# 验证单位向量
print("验证范数(应为 1):")
for i, b in enumerate(basis):
    print(f"  e{i+1} 范数:", np.linalg.norm(b))

# scipy 的格拉姆-施密特(利用 QR 分解)
A = np.column_stack([v1, v2, v3])
Q, R = np.linalg.qr(A)
print("QR 分解的 Q 矩阵:\n", Q)

8. 特征值与特征向量 (Eigenvalues & Eigenvectors)

定义

对方阵 AA,满足以下条件的标量 λ\lambda 与非零向量 v\mathbf{v}

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

  • λ\lambda特征值 (eigenvalue)
  • v\mathbf{v}:对应于 λ\lambda特征向量 (eigenvector)

特征向量在被 AA 变换时方向保持不变,只有大小变为 λ\lambda 倍。

特征方程

det(AλI)=0\det(A - \lambda I) = 0

该多项式(characteristic polynomial)的根即为特征值。

2×2 示例:

A=(4123)A = \begin{pmatrix} 4 & 1 \\ 2 & 3 \end{pmatrix}

det(AλI)=(4λ)(3λ)2=λ27λ+10=(λ2)(λ5)=0\det(A - \lambda I) = (4-\lambda)(3-\lambda) - 2 = \lambda^2 - 7\lambda + 10 = (\lambda-2)(\lambda-5) = 0

因此 λ1=2\lambda_1 = 2λ2=5\lambda_2 = 5

特征值分解 (Eigendecomposition)

可对角化的矩阵 AA 可分解为:

A=PΛP1A = P \Lambda P^{-1}

这里 Λ=diag(λ1,λ2,,λn)\Lambda = \text{diag}(\lambda_1, \lambda_2, \ldots, \lambda_n)PP 的列向量为特征向量。

对称矩阵的谱定理

实对称矩阵 A=ATA = A^T 具有以下性质:

  1. 所有特征值均为实数
  2. 对应不同特征值的特征向量互相正交
  3. A=QΛQTA = Q \Lambda Q^T(可正交对角化)
import numpy as np
from scipy.linalg import eig

# 一般矩阵的特征值/特征向量
A = np.array([[4, 1],
              [2, 3]])

eigenvalues, eigenvectors = np.linalg.eig(A)
print("特征值:", eigenvalues)          # [5., 2.]
print("特征向量(按列排列):\n", eigenvectors)

# 验证: A @ v = lambda * v
for i in range(len(eigenvalues)):
    lam = eigenvalues[i]
    v = eigenvectors[:, i]
    print(f"\nlambda={lam:.2f}:")
    print("  A @ v:", A @ v)
    print("  lambda * v:", lam * v)

# 特征值分解: A = P @ Lambda @ P^{-1}
P = eigenvectors
Lambda = np.diag(eigenvalues)
A_reconstructed = P @ Lambda @ np.linalg.inv(P)
print("\n重构矩阵:\n", A_reconstructed)
print("与原矩阵相同:", np.allclose(A, A_reconstructed))

# 对称矩阵(保证特征值为实数)
B = np.array([[2, 1, 0],
              [1, 3, 1],
              [0, 1, 2]])

eigenvalues_B, eigenvectors_B = np.linalg.eigh(B)  # 专用于对称矩阵
print("\n对称矩阵的特征值:", eigenvalues_B)
print("验证正交性(Q^T @ Q = I):\n",
      np.round(eigenvectors_B.T @ eigenvectors_B))

# 幂运算: A^n = P @ Lambda^n @ P^{-1}
n = 5
Lambda_n = np.diag(eigenvalues ** n)
A_power = P @ Lambda_n @ np.linalg.inv(P)
print(f"\nA^{n}:\n", A_power)
print("与直接计算结果比较:\n", np.linalg.matrix_power(A, n))

9. 奇异值分解 (SVD - Singular Value Decomposition)

SVD 的定义

任意 m×nm \times n 矩阵 AA 都可分解为:

A=UΣVTA = U \Sigma V^T

  • URm×mU \in \mathbb{R}^{m \times m}:左奇异向量(left singular vectors),正交矩阵
  • ΣRm×n\Sigma \in \mathbb{R}^{m \times n}:奇异值对角矩阵(σ1σ20\sigma_1 \geq \sigma_2 \geq \cdots \geq 0
  • VRn×nV \in \mathbb{R}^{n \times n}:右奇异向量(right singular vectors),正交矩阵

几何意义

AA 可以看作以下三种变换的复合:

  1. VTV^T:旋转/反射
  2. Σ\Sigma:沿坐标轴方向缩放
  3. UU:旋转/反射

与 PCA 的关系

对数据矩阵 XX 执行 SVD,等价于执行主成分分析(PCA)。

X=UΣVTX = U \Sigma V^T 中,VV 的列向量即为主成分(principal components)。

图像压缩

将奇异值按降序排列后,可用前 kk 个奇异值构造近似矩阵:

Ak=i=1kσiuiviTA_k = \sum_{i=1}^{k} \sigma_i \mathbf{u}_i \mathbf{v}_i^T

import numpy as np
import matplotlib.pyplot as plt

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

U, S, Vt = np.linalg.svd(A)
print("U 的形状:", U.shape)      # (4, 4)
print("S(奇异值):", S)         # 奇异值
print("Vt 的形状:", Vt.shape)    # (3, 3)

# 验证重构
Sigma = np.zeros(A.shape)
Sigma[:min(A.shape), :min(A.shape)] = np.diag(S)
A_reconstructed = U @ Sigma @ Vt
print("重构误差:", np.linalg.norm(A - A_reconstructed))

# 图像压缩模拟
def svd_compress(matrix, k):
    """用前 k 个奇异值压缩矩阵"""
    U, S, Vt = np.linalg.svd(matrix)
    # 只使用 k 个分量
    U_k = U[:, :k]
    S_k = S[:k]
    Vt_k = Vt[:k, :]
    return U_k @ np.diag(S_k) @ Vt_k

# 测试矩阵(模拟图像)
np.random.seed(42)
img = np.random.randn(100, 100)

# 测试不同的压缩比
for k in [5, 10, 20, 50]:
    compressed = svd_compress(img, k)
    error = np.linalg.norm(img - compressed, 'fro') / np.linalg.norm(img, 'fro')
    compression_ratio = k * (100 + 100 + 1) / (100 * 100)
    print(f"k={k}: 相对误差={error:.4f}, 压缩比={compression_ratio:.4f}")

# 用 SVD 实现 PCA
def pca_svd(X, n_components):
    """利用 SVD 实现 PCA"""
    # 数据中心化
    X_centered = X - X.mean(axis=0)

    # 执行 SVD
    U, S, Vt = np.linalg.svd(X_centered, full_matrices=False)

    # 投影到主成分
    X_pca = X_centered @ Vt[:n_components].T

    # 解释方差比
    explained_variance_ratio = (S[:n_components]**2) / (S**2).sum()

    return X_pca, Vt[:n_components], explained_variance_ratio

# 示例数据
np.random.seed(42)
X = np.random.randn(100, 5)
X_pca, components, evr = pca_svd(X, 2)
print("\nPCA 解释方差比:", evr)
print("投影后数据的形状:", X_pca.shape)

10. 矩阵分解 (Matrix Factorizations)

主要分解方法比较

分解形式适用条件主要用途
LU 分解A = LU方阵线性方程组
QR 分解A = QR任意矩阵最小二乘法、特征值
CholeskyA = LL^T正定对称数值优化
SVDA = UΣV^T任意矩阵PCA、图像压缩
特征值分解A = PΛP^-1方阵谱分析

Cholesky 分解

对于正定(positive definite)对称矩阵:A=LLTA = LL^T

import numpy as np
from scipy import linalg

# QR 分解
A = np.array([[1, 2, 3],
              [4, 5, 6],
              [7, 8, 10]], dtype=float)

Q, R = np.linalg.qr(A)
print("Q(正交矩阵):\n", Q)
print("R(上三角矩阵):\n", R)
print("验证 Q^T @ Q = I:\n", np.round(Q.T @ Q))

# Cholesky 分解
B = np.array([[4, 2, 2],
              [2, 3, 1],
              [2, 1, 3]], dtype=float)

L = np.linalg.cholesky(B)
print("\nCholesky L:\n", L)
print("验证 L @ L^T = A:\n", L @ L.T)

# LU 分解 (scipy)
P, L_lu, U = linalg.lu(A)
print("\nLU 分解:")
print("P:\n", P)
print("L:\n", L_lu)
print("U:\n", U)
print("验证 P @ L @ U = A:\n", np.round(P @ L_lu @ U))

11. AI/ML 中的线性代数

神经网络中的矩阵乘法

神经网络的前向传播(forward propagation)可以表示为连续的矩阵乘法:

h(l)=f(W(l)h(l1)+b(l))\mathbf{h}^{(l)} = f(W^{(l)} \mathbf{h}^{(l-1)} + \mathbf{b}^{(l)})

  • W(l)W^{(l)}:权重矩阵
  • b(l)\mathbf{b}^{(l)}:偏置向量
  • ff:激活函数

批处理时可将输入表示为矩阵 XRn×dX \in \mathbb{R}^{n \times d},从而实现并行计算。

梯度与雅可比矩阵

损失函数 LL 关于权重矩阵的梯度:

LW=LhxT\frac{\partial L}{\partial W} = \frac{\partial L}{\partial \mathbf{h}} \mathbf{x}^T

用 PCA 做降维

在高维特征空间中找出主要的方差方向,从而实现降维。

Transformer 的注意力机制 (Attention)

Self-Attention 利用三个矩阵 Q,K,VQ, K, V(Query、Key、Value):

Attention(Q,K,V)=softmax(QKTdk)V\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right) V

import numpy as np
from sklearn.decomposition import PCA
from sklearn.datasets import load_iris

# 1. 简单的神经网络前向传播
np.random.seed(42)
n_samples, input_dim, hidden_dim, output_dim = 32, 784, 128, 10

X = np.random.randn(n_samples, input_dim)
W1 = np.random.randn(input_dim, hidden_dim) * 0.01
b1 = np.zeros(hidden_dim)
W2 = np.random.randn(hidden_dim, output_dim) * 0.01
b2 = np.zeros(output_dim)

# 前向传播
H1 = np.maximum(0, X @ W1 + b1)  # ReLU 激活
logits = H1 @ W2 + b2
print("logits 的形状:", logits.shape)  # (32, 10)

# 2. 用 PCA 降维
iris = load_iris()
X_iris = iris.data  # (150, 4)

pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_iris)
print("\nPCA 后的形状:", X_pca.shape)  # (150, 2)
print("解释方差比:", pca.explained_variance_ratio_)
print("累计解释方差:", pca.explained_variance_ratio_.sum())

# 3. Scaled Dot-Product Attention
def scaled_dot_product_attention(Q, K, V):
    d_k = Q.shape[-1]
    # Q @ K^T / sqrt(d_k)
    scores = Q @ K.T / np.sqrt(d_k)

    # Softmax
    exp_scores = np.exp(scores - scores.max(axis=-1, keepdims=True))
    attention_weights = exp_scores / exp_scores.sum(axis=-1, keepdims=True)

    # 加权求和
    output = attention_weights @ V
    return output, attention_weights

# 示例
seq_len, d_model = 5, 8
Q = np.random.randn(seq_len, d_model)
K = np.random.randn(seq_len, d_model)
V = np.random.randn(seq_len, d_model)

output, weights = scaled_dot_product_attention(Q, K, V)
print("\nAttention 输出的形状:", output.shape)  # (5, 8)
print("Attention 权重之和:", weights.sum(axis=-1))  # 均为 1

# 4. Word Embedding 相似度
word_embeddings = {
    "king": np.array([0.8, 0.3, 0.1, 0.9]),
    "queen": np.array([0.7, 0.4, 0.2, 0.8]),
    "man": np.array([0.6, 0.1, 0.7, 0.2]),
    "woman": np.array([0.5, 0.2, 0.8, 0.1])
}

def cosine_similarity(a, b):
    return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

print("\n词语相似度:")
print("king-queen:", cosine_similarity(
    word_embeddings["king"], word_embeddings["queen"]))
print("man-woman:", cosine_similarity(
    word_embeddings["man"], word_embeddings["woman"]))

# king - man + woman ≈ queen(类比关系)
analogy = word_embeddings["king"] - word_embeddings["man"] + word_embeddings["woman"]
sim_queen = cosine_similarity(analogy, word_embeddings["queen"])
print("king - man + woman 与 queen 的相似度:", sim_queen)

12. 测验

Q1. 向量的内积与正交性之间是什么关系?

答案:两个向量的内积为 0 时,它们互相正交(orthogonal)。

说明:根据内积公式 uv=uvcosθ\mathbf{u} \cdot \mathbf{v} = \|\mathbf{u}\|\|\mathbf{v}\|\cos\theta,由于 cos90°=0\cos 90° = 0,当两个向量成直角时内积为 0。可以据此构造标准正交基,或计算正交投影。

Q2. 逆矩阵存在的条件是什么?

答案:当方阵的行列式(determinant)不为 0 时,逆矩阵存在。

说明:若 det(A)0\det(A) \neq 0,则 AA 是可逆矩阵(invertible matrix)。行列式为 0 的矩阵称为奇异矩阵(singular matrix),不存在逆矩阵。这意味着该矩阵的秩(rank)小于矩阵的大小,对应的线性方程组也就不存在唯一解。

Q3. 特征值与特征向量的几何意义是什么?

答案:特征向量是经过线性变换后方向不发生改变的向量,特征值则表示该向量被拉伸或压缩的倍数。

说明:在 Av=λvA\mathbf{v} = \lambda\mathbf{v} 中,即使经过矩阵 AA 的变换,向量 v\mathbf{v} 的方向也保持不变,只有大小变为 λ\lambda 倍。当 λ>1\lambda > 1 时被拉伸,当 0<λ<10 < \lambda < 1 时被压缩,当 λ<0\lambda < 0 时方向发生反转。特征值分解被用于 PCA、矩阵幂运算等场景。

Q4. SVD 与 PCA 之间是什么关系?

答案:对中心化后的数据矩阵应用 SVD,会得到与 PCA 相同的结果。SVD 的右奇异向量(V)对应于 PCA 的主成分(principal components)。

说明:将数据矩阵 XX 中心化后执行 SVD,会得到 X=UΣVTX = U\Sigma V^T。此时 VV 的列向量即为主成分,所解释的方差与奇异值 σi\sigma_i 的平方成正比。由于在数值上比对协方差矩阵做特征值分解更稳定,sklearn 的 PCA 内部也使用了 SVD。

Q5. 请说明秩-零化度定理(Rank-Nullity Theorem)。

答案:对 m×nm \times n 矩阵 AA,有 rank(A)+nullity(A)=n\text{rank}(A) + \text{nullity}(A) = n 成立。

说明:rank(A) 是列空间(column space)的维数,nullity(A) 是零空间(null space)的维数。列数 nn 始终等于这两个维数之和。例如若一个 3×4 矩阵的秩为 3,则零空间的维数就是 1。这条定理对于理解线性方程组解的结构至关重要。


总结与学习路线图

线性代数的核心概念彼此紧密相连:

向量 -> 矩阵 -> 行列式 -> 线性方程组
  |         |
向量空间 -> 线性变换 -> 内积空间
  |
特征值/特征向量 -> SVD -> AI/ML 应用

推荐的后续学习资料:

  1. Gilbert Strang 的 Linear Algebra(MIT OCW 18.06):最系统的线性代数课程
  2. 3Blue1Brown - Essence of Linear Algebra:在建立几何直觉方面非常出色
  3. NumPy 官方文档:可用于实践线性代数模块(numpy.linalg
  4. scikit-learn PCA 文档:了解它在实际 ML 流水线中的应用
  5. Matrix Methods in Data Analysis(MIT 18.065):高级应用课程

线性代数的关键并不在于死记硬背公式,而在于理解矩阵与向量的几何意义。希望你能通过持续的代码实践与可视化,逐步积累起深入的理解。