你是否曾经好奇,为什么一个简单的数表乘上一个向量,就能让向量跨越维度?
比如,一个 $2 \times 3$ 的矩阵,可以把三维空间中的点“拍扁”到二维平面上。
这篇文章会带你从几何直觉出发,走到具体的计算,再动手写代码,亲手体验这种变换。
设我们有一个矩阵 $A$,尺寸为 $m \times n$,以及一个 n 维列向量 $\mathbf{x} \in \mathbb{R}^n$:
$$ 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}, \quad \mathbf{x} = \begin{pmatrix} x_1 \\ x_2 \ \vdots \\ x_n \end{pmatrix} $$
它们的乘积 $\mathbf{y} = A\mathbf{x}$ 是一个 m 维向量:
$$ \mathbf{y} = \begin{pmatrix} y_1 \\ y_2 \ \vdots \\ y_m \end{pmatrix} $$
其中每个分量由“行点乘列”得到:
$$ y_i = a_{i1}x_1 + a_{i2}x_2 + \cdots + a_{in}x_n $$
因此,$A$ 就像一个函数 $f: \mathbb{R}^n \to \mathbb{R}^m$,把 n 维空间中的向量映射到 m 维空间。
为了建立直觉,我们先用小例子看一看。
当 $m = n = 2$ 时,矩阵不改变维度,但可以旋转、缩放、剪切向量。
例如,缩放矩阵:
$$ S = \begin{pmatrix} 2 & 0 \\ 0 & 0.5 \end{pmatrix} $$
它将向量 $(x_1, x_2)^T$ 变成 $(2x_1, 0.5x_2)^T$——在 x 方向拉伸,在 y 方向压缩。
再来一个旋转矩阵:
$$ R = \begin{pmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{pmatrix} $$
它会将整个平面绕原点逆时针旋转 $\theta$ 角度,所有向量的长度保持不变。
这里我们看一个 $2 \times 3$ 矩阵,输入三维向量,输出二维向量。
例如投影矩阵:
$$ P = \begin{pmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \end{pmatrix} $$
它直接丢弃第三个坐标:
$$ P \begin{pmatrix} x \\ y \\ z \end{pmatrix} = \begin{pmatrix} x \\ y \end{pmatrix} $$
这在几何上相当于沿 z 轴正投影到 xy 平面——一个三维物体被压成了平面影子。
再比如更一般的变换:
$$ A = \begin{pmatrix} 1 & 2 & 0 \\ 0 & 1 & 3 \end{pmatrix} $$
会把三维点映射成二维点,坐标之间发生混合,可以理解为先“揉搓”三维空间,再丢掉一个维度。
$3 \times 1$ 矩阵将一维向量(标量)映射到三维空间:
$$ B = \begin{pmatrix} 1 \\ 2 \\ 0.5 \end{pmatrix}, \quad B \cdot (t) = \begin{pmatrix} t \\ 2t \\ 0.5t \end{pmatrix} $$
这定义了一条穿过原点、方向为 $(1, 2, 0.5)^T$ 的直线。
调整 $t$,你就在这条直线上移动。
就像第一节中的公式,输出向量的第 $i$ 个分量是第 $i$ 行与 $\mathbf{x}$ 的内积。
适合计算,但不那么直观。
把矩阵按列分块:
$$ A = \begin{pmatrix} \mathbf{c}_1 & \mathbf{c}_2 & \cdots & \mathbf{c}_n \end{pmatrix}, \quad \mathbf{c}_j \in \mathbb{R}^m $$
那么:
$$ A\mathbf{x} = x_1 \mathbf{c}_1 + x_2 \mathbf{c}_2 + \cdots + x_n \mathbf{c}_n $$
输出向量是矩阵各列的线性组合,系数就是输入向量的各个分量。
换句话说,变换后的所有可能结果,都落在由这些列向量张成的子空间里(列空间)。
如果 $m < n$,这个子空间最多是 m 维的,因此信息一定会被压缩。
当 $m < n$ 时,矩阵的列数大于行数,列向量必然线性相关,不是单射——不同的输入可能映射到同一个输出。
例如投影矩阵 $P$,所有具有相同 $(x, y)$ 但不同 $z$ 的点,都会映射到同一个二维点。
这些被“压扁”掉的方向,构成了零空间(核):
$$ \ker(A) = { \mathbf{x} \in \mathbb{R}^n \mid A\mathbf{x} = \mathbf{0} } $$
秩-零化度定理告诉我们:
$$ \dim(\text{列空间}) + \dim(\ker(A)) = n $$
当 $m < n$ 时,零空间的维度至少为 $n - m$,意味着至少有 $n - m$ 个独立方向的信息会彻底消失。
理论说完,我们来亲手创造矩阵,并观察它如何把向量“搬来搬去”。
确保你已经安装 numpy 和 matplotlib。
可以在 Jupyter Notebook 或任意 Python 环境中运行以下代码。
import numpy as np
import matplotlib.pyplot as plt
我们在平面上取一个单位圆上的点,施加不同矩阵,观察形状变化。
# 生成单位圆上的点
theta = np.linspace(0, 2*np.pi, 200)
circle = np.vstack([np.cos(theta), np.sin(theta)]) # 2 x 200
# 定义几个变换矩阵
S = np.array([[2, 0],
[0, 0.5]]) # 缩放
theta_rot = np.pi/4
R = np.array([[np.cos(theta_rot), -np.sin(theta_rot)],
[np.sin(theta_rot), np.cos(theta_rot)]]) # 旋转45度
# 施加变换
circle_S = S @ circle
circle_R = R @ circle
# 绘图
fig, axes = plt.subplots(1, 3, figsize=(12, 4))
axes[0].plot(circle[0], circle[1])
axes[0].set_title("原始单位圆")
axes[0].axis("equal")
axes[1].plot(circle_S[0], circle_S[1])
axes[1].set_title("拉伸矩阵 S")
axes[1].axis("equal")
axes[2].plot(circle_R[0], circle_R[1])
axes[2].set_title("旋转矩阵 R")
axes[2].axis("equal")
plt.show()
你会看到:
原始圆被 S 拉成一个椭圆;
被R旋转后仍然是一个圆,只是转了 45°。
这次我们生成三维空间中的点(比如一个螺旋线),用 2×3 矩阵投影到平面上。
from mpl_toolkits.mplot3d import Axes3D
# 生成三维螺旋线
t = np.linspace(0, 4*np.pi, 300)
x3d = np.vstack([np.cos(t), np.sin(t), t]) # 3 x 300
# 定义投影矩阵(丢弃z)
P = np.array([[1, 0, 0],
[0, 1, 0]])
# 另一个混合矩阵
A = np.array([[1, 0.5, 0],
[0, 1, 0.3]])
proj_P = P @ x3d # 2 x 300
proj_A = A @ x3d # 2 x 300
# 绘制三维原图与二维投影
fig = plt.figure(figsize=(15, 5))
ax1 = fig.add_subplot(131, projection='3d')
ax1.plot(x3d[0], x3d[1], x3d[2])
ax1.set_title("三维螺旋线")
ax2 = fig.add_subplot(132)
ax2.plot(proj_P[0], proj_P[1])
ax2.set_title("投影 P(丢弃 z)")
ax2.axis("equal")
ax3 = fig.add_subplot(133)
ax3.plot(proj_A[0], proj_A[1])
ax3.set_title("混合投影 A")
ax3.axis("equal")
plt.show()
观察:
直接丢弃 z 轴得到的投影,就是螺旋在 xy 平面的“影子”(一个圆)。
混合矩阵 A 则给出了一个更复杂的平面曲线,因为它在丢弃信息的同时还混合了坐标。
对于 A(A 矩阵),理论上它有一个一维的零空间(因为 2×3 且满秩时零空间维度为 1)。我们可以数值计算,验证 Ax=0。
# 计算零空间(通过奇异值分解)
U, S, Vt = np.linalg.svd(A)
null_space = Vt[2] # 最后一个右奇异向量(对应奇异值为0的方向)
print("零空间的一个基向量:", null_space)
你会看到输出接近零向量(数值误差范围内),完美验证。
把 $A$ 看作函数后,很多性质都变得自然:
矩阵变换保持向量的加法与数乘运算:
$$ A(\alpha \mathbf{x} + \beta \mathbf{y}) = \alpha A\mathbf{x} + \beta A\mathbf{y} $$
这意味着: - 直线上的点经过变换后,仍然落在一条直线上(或收缩为一个点); - 原点经过任何矩阵变换,始终保持在原点。
这一性质是“线性”二字的由来,也是矩阵变换最根本的约束。
矩阵乘法对应函数复合。若有 $B$ 为 $p \times m$ 矩阵,则:
$$ B (A \mathbf{x}) = (BA) \mathbf{x} $$
这意味着: - 先将 $\mathbf{x}$ 从 $n$ 维送入 $A$,得到 $m$ 维向量; - 再将这个 $m$ 维向量送入 $B$,得到 $p$ 维向量; - 整个过程等价于直接使用乘积矩阵 $BA$(尺寸为 $p \times n$)对 $\mathbf{x}$ 进行一次变换。
这种“先 $A$ 后 $B$”的复合操作,恰好对应矩阵乘法的结合律,是深度学习等框架中逐层变换的数学基础。
矩阵变换的升维与降维能力,使其成为许多领域的核心工具:
数据降维(PCA)
主成分分析使用 $m \times n$ 矩阵($m \ll n$)将高维数据投影到低维主成分空间,在保留主要信息的同时实现可视化或去噪。
神经网络中的全连接层
一个全连接层的权重矩阵 $W$(尺寸为 $m \times n$)将上一层的 $n$ 维特征映射为下一层的 $m$ 维特征,后接激活函数引入非线性,层层堆叠构成深度网络。
计算机图形学中的齐次变换
三维空间中的平移、旋转、缩放与透视投影,统一由 $4 \times 4$ 矩阵作用于齐次坐标 $(x, y, z, 1)^T$ 上完成,优雅且高效。
现在你已经知道:
一个 $m \times n$ 矩阵,就是在做一件非常简单却又强大的事——
把来自 $n$ 维世界的向量,重新组合、旋转、拉伸甚至压平,然后送入 $m$ 维空间。
在计算层面,它是行向量与输入向量的内积;
在几何层面,它是矩阵各列向量的线性组合。
你可以继续深入以下话题:
升维变换($m > n$)
当输出维度高于输入维度时,矩阵如何将低维数据“嵌入”高维空间。例如,用 $3 \times 2$ 矩阵将二维平面弯曲嵌入到三维空间中,形成参数化曲面。
奇异值分解(SVD)
任意一个 $m \times n$ 矩阵 $A$ 可分解为:
$$ A = U \Sigma V^T $$
其中 $U$ 和 $V$ 是正交矩阵(对应旋转/反射),$\Sigma$ 是对角矩阵(对应各坐标轴方向的缩放)。
这意味着:任何线性变换都可以拆解为“旋转 → 沿坐标轴缩放 → 再旋转”三步,这是理解矩阵几何意义的终极视角。
给定矩阵 $C = \begin{pmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \end{pmatrix}$,请问:
尝试用本文介绍的列空间与零空间的概念,以及 Python 代码验证你的答案。
希望这篇文章和代码能帮你建立对线性变换的几何直觉——矩阵不再只是数字的排列,而是一台维度搬运机。