跳到主要内容

特征值与 SVD:计算、重构和近似

把矩阵拆成几个方向上的作用,就能看清它怎样拉伸向量、哪些信息在变换后消失,以及少保留几个方向会损失多少。线性代数概览介绍向量、秩、正交投影和最小二乘;这里从一个二阶矩阵算起,再用一个三行两列的矩阵完成 SVD、重构和低秩近似。矩阵均取实数,向量按列书写,TT 表示转置。

特征向量:变换后仍留在同一条直线上​

对方阵 BB,若非零向量 vv 满足 Bv=λvBv=\lambda v,则 vv 是特征向量,λ\lambda 是特征值。MIT 18.06SC 的特征值讲义从这个关系出发:vv 所在的直线在变换下保持不变。λ>0\lambda>0 时方向不变,λ<0\lambda<0 时反向,λ=0\lambda=0 时被映到零。零向量不能作为特征向量,否则任何 λ\lambda 都满足等式。

取

B=[2112].B=\begin{bmatrix}2&1\\1&2\end{bmatrix}.

由 (B−λI)v=0(B-\lambda I)v=0,要有非零解,必须使 B−λIB-\lambda I 奇异。因此先解特征方程:

det⁡(B−λI)=(2−λ)2−1=λ2−4λ+3=(λ−3)(λ−1)=0.\det(B-\lambda I)=(2-\lambda)^2-1 =\lambda^2-4\lambda+3=(\lambda-3)(\lambda-1)=0.

得到 λ1=3\lambda_1=3、λ2=1\lambda_2=1。再分别求零空间:

  • 当 λ=3\lambda=3,B−3I=[−111−1]B-3I=\begin{bmatrix}-1&1\\1&-1\end{bmatrix},所以 v2=v1v_2=v_1。
  • 当 λ=1\lambda=1,B−I=[1111]B-I=\begin{bmatrix}1&1\\1&1\end{bmatrix},所以 v2=−v1v_2=-v_1。

归一化后选取

q1=12[11],q2=12[1−1].q_1=\frac{1}{\sqrt2}\begin{bmatrix}1\\1\end{bmatrix},\qquad q_2=\frac{1}{\sqrt2}\begin{bmatrix}1\\-1\end{bmatrix}.

直接相乘可查得 Bq1=3q1Bq_1=3q_1、Bq2=q2Bq_2=q_2。任意 x=c1q1+c2q2x=c_1q_1+c_2q_2 都满足 Bx=3c1q1+c2q2Bx=3c_1q_1+c_2q_2:沿第一条轴放大三倍,沿第二条轴保持原长度。

实 n×nn\times n 矩阵能写成 B=PΛP−1B=P\Lambda P^{-1},且 P,ΛP,\Lambda 都为实矩阵,当且仅当它有 nn 个线性无关的实特征向量。实矩阵也可能有复特征值;上面的不变直线解释适用于实特征向量。例如 J=[1101]J=\begin{bmatrix}1&1\\0&1\end{bmatrix} 的特征值 1 重复两次,但 J−IJ-I 的零空间只有 (1,0)T(1,0)^T 张成的一条直线,无法组成二维基。

对称性为什么带来正交分解​

MIT 的对称矩阵讲义给出的谱定理是:实对称矩阵有实特征值,并且可以选出一组完整的标准正交特征向量。对不同特征值 λi≠λj\lambda_i\ne\lambda_j,正交性可直接推出:

λjqiTqj=qiTBqj=(Bqi)Tqj=λiqiTqj,qiTqj=0.\lambda_j q_i^Tq_j=q_i^TBq_j=(Bq_i)^Tq_j =\lambda_i q_i^Tq_j, \qquad q_i^Tq_j=0.

有重复特征值时,同一特征空间内任意选取的两个向量未必正交,但可以在其中选标准正交基。令 Q=[q1 q2]Q=[q_1\ q_2],则 QTQ=IQ^TQ=I、Q−1=QTQ^{-1}=Q^T,上面的例子可以写成

B=Q[3001]QT=3q1q1T+q2q2T.B=Q\begin{bmatrix}3&0\\0&1\end{bmatrix}Q^T =3q_1q_1^T+q_2q_2^T.

右侧每一项都是“先投影到一条轴,再乘以特征值”。对称性不保证特征值为正;这个例子的两个特征值恰好都为正。

长方形矩阵的 SVD 与因子尺寸​

三行两列的矩阵把二维输入映到三维输出,输入与输出无法直接用 Av=λvAv=\lambda v 比较。MIT 的 SVD 讲义说明任意实矩阵都存在 SVD,用两组标准正交方向连接输入与输出:

A=UΣVT,Avi=σiui.A=U\Sigma V^T,\qquad Av_i=\sigma_i u_i.

viv_i 是输入空间的右奇异向量,uiu_i 是输出空间的左奇异向量,奇异值按 σ1≥⋯≥σp≥0\sigma_1\ge\cdots\ge\sigma_p\ge0 排列,p=min⁡(m,n)p=\min(m,n)。先用 VTV^T 取输入坐标,再由 Σ\Sigma 拉伸,最后由 UU 映回输出坐标。

形式,A∈Rm×nA\in\mathbb R^{m\times n}UUΣ\SigmaVTV^T
完整 SVDm×mm\times mm×nm\times nn×nn\times n
经济型 SVD,p=min⁡(m,n)p=\min(m,n)m×pm\times pp×pp\times pp×np\times n
只留非零项,r=rank⁡(A)r=\operatorname{rank}(A)m×rm\times rr×rr\times rr×nr\times n

完整形式的 U,VU,V 是正交方阵;后两种形式中 U,VU,V 的列向量标准正交,但矩阵可能不是方阵。经济型形式仍可包含零奇异值,不能把 pp 和秩 rr 混为一谈。

SciPy 线性代数教程用 U, s, Vh 表示返回结果;s 是一维奇异值数组,Vh 对实矩阵就是 VTV^T,并不是 VV。scipy.linalg.svd 的接口文档列出了 full_matrices=False 对应的经济型尺寸。

从两个奇异分量重构矩阵​

取

A=[2002−2−2],ATA=[8448]=4B.A=\begin{bmatrix}2&0\\0&2\\-2&-2\end{bmatrix},\qquad A^TA=\begin{bmatrix}8&4\\4&8\end{bmatrix}=4B.

因为 ATAvi=σi2viA^TA v_i=\sigma_i^2v_i,前面的特征向量可以直接复用:v1=q1v_1=q_1、v2=q2v_2=q_2,对应特征值 12 和 4,所以

σ1=12=23,σ2=2.\sigma_1=\sqrt{12}=2\sqrt3,\qquad \sigma_2=2.

对非零奇异值,用 ui=Avi/σiu_i=Av_i/\sigma_i 求左奇异向量:

Av1=[22−22],u1=16[11−2];Av2=[2−20],u2=12[1−10].\begin{aligned} Av_1&=\begin{bmatrix}\sqrt2\\\sqrt2\\-2\sqrt2\end{bmatrix},& u_1&=\frac{1}{\sqrt6}\begin{bmatrix}1\\1\\-2\end{bmatrix};\\[6pt] Av_2&=\begin{bmatrix}\sqrt2\\-\sqrt2\\0\end{bmatrix},& u_2&=\frac{1}{\sqrt2}\begin{bmatrix}1\\-1\\0\end{bmatrix}. \end{aligned}

这里 u1Tu2=0u_1^Tu_2=0,两者长度都是 1。令 Up=[u1 u2]U_p=[u_1\ u_2],Σp=diag⁡(23,2)\Sigma_p=\operatorname{diag}(2\sqrt3,2),Vp=[v1 v2]V_p=[v_1\ v_2],便得到尺寸为 (3×2)(2×2)(2×2)(3\times2)(2\times2)(2\times2) 的经济型 SVD。完整形式再补上 u3=(1,1,1)T/3u_3=(1,1,1)^T/\sqrt3,并在 Σ\Sigma 底部补一行零;ATu3=0A^Tu_3=0。

把乘积展开成外积,每个非零分量的秩都是 1:

A=σ1u1v1T+σ2u2v2T=[1111−2−2]+[1−1−1100]=[2002−2−2].\begin{aligned} A&=\sigma_1u_1v_1^T+\sigma_2u_2v_2^T\\ &=\begin{bmatrix}1&1\\1&1\\-2&-2\end{bmatrix} +\begin{bmatrix}1&-1\\-1&1\\0&0\end{bmatrix} =\begin{bmatrix}2&0\\0&2\\-2&-2\end{bmatrix}. \end{aligned}

同时把 ui,viu_i,v_i 都乘以 −1-1,外积不变。对实对称矩阵,奇异值是特征值的绝对值;负特征值的符号要由左右奇异向量的相对方向承担。只有正半定情形才可以让奇异值直接等于特征值。

截断后,误差怎样计算​

设 1≤k<r1\le k<r,只保留最大的 kk 项:

Ak=∑i=1kσiuiviT.A_k=\sum_{i=1}^{k}\sigma_i u_i v_i^T.

Stanford CS168 的低秩近似讲义,第 5 节给出的结论是:AkA_k 在所有秩不超过 kk 的矩阵中,使 Frobenius 范数误差最小。这里 ∥M∥F2=∑a,bMab2\|M\|_F^2=\sum_{a,b}M_{ab}^2。不同外积在这个内积下正交,因为

⟨uiviT,ujvjT⟩F=(uiTuj)(viTvj).\langle u_iv_i^T,u_jv_j^T\rangle_F =(u_i^Tu_j)(v_i^Tv_j).

所以残差的平方范数就是被舍弃项的平方和:

∥A−Ak∥F=∑i=k+1rσi2,∥A−Ak∥2=σk+1.\|A-A_k\|_F=\sqrt{\sum_{i=k+1}^{r}\sigma_i^2},\qquad \|A-A_k\|_2=\sigma_{k+1}.

矩阵的 22 范数表示单位输入向量受到的最大长度放大;残差沿 vk+1v_{k+1} 达到上述值。若 k≥rk\ge r,重构误差为零。

本例保留第一项,得到

A1=[1111−2−2],A−A1=[1−1−1100].A_1=\begin{bmatrix}1&1\\1&1\\-2&-2\end{bmatrix},\qquad A-A_1=\begin{bmatrix}1&-1\\-1&1\\0&0\end{bmatrix}.

于是 ∥A−A1∥F=2\|A-A_1\|_F=2,∥A∥F=12+4=4\|A\|_F=\sqrt{12+4}=4,相对 Frobenius 误差为 1/21/2。保留的平方范数比例则是 12/(12+4)=75%12/(12+4)=75\%。保留 75% 的平方范数,与相对误差为 25% 不是同一个说法:此处被舍弃的平方误差占 25%,取平方根后才是相对范数误差。

PCA:平方奇异值变成方差​

scikit-learn 的 PCA 文档说明,PCA 在中心化后的数据上寻找解释方差最大的正交分量;中心化不会自动把各特征缩放到相同尺度。

令 X∈RN×dX\in\mathbb R^{N\times d} 的每行是一条观测,每列已经减去均值,且 N>1N>1。采用样本协方差的 N−1N-1 分母,与 PCA 接口的解释方差一致,代入完整 SVD X=UΣVTX=U\Sigma V^T 得到

C=XTXN−1=VΣTΣN−1VT.C=\frac{X^TX}{N-1} =V\frac{\Sigma^T\Sigma}{N-1}V^T.

因此,viv_i 是主成分方向,σi2/(N−1)\sigma_i^2/(N-1) 是对应的方差。保留前 kk 个方向时,得分矩阵为 Z=XVk=UkΣkZ=XV_k=U_k\Sigma_k,重构为 ZVkT=XkZV_k^T=X_k;原数据未中心化时还要加回均值。

本例的 AA 每列之和都是零,可以直接作为 XX。N=3N=3,协方差矩阵为 C=[4224]C=\begin{bmatrix}4&2\\2&4\end{bmatrix},主成分方差为 6 和 2。第一主成分的三个得分是 (2,2,−22)T(\sqrt2,\sqrt2,-2\sqrt2)^T;乘以 v1Tv_1^T 就重构出 A1A_1,解释方差比例为 6/(6+2)=75%6/(6+2)=75\%。

聚类与降维讨论怎样选择尺度、拟合数据和下游评价。这里的 75% 只度量这些坐标中的方差保留情况,不能据此判断分类任务是否保留了足够的信息。

最小二乘:零奇异值和小奇异值各意味着什么​

对 min⁡x∥Ax−b∥22\min_x\|Ax-b\|_2^2,MIT 的伪逆讲义从 SVD 出发,对非零奇异值取倒数。最小欧氏范数的最小二乘解是

x∗=A+b=∑i=1ruiTbσivi.x_*=A^+b=\sum_{i=1}^{r}\frac{u_i^Tb}{\sigma_i}v_i.

这是先把 bb 投影到列空间,再逐方向撤销拉伸。其余最小二乘解为 x∗+zx_*+z,其中 Az=0Az=0;这些零空间方向与 x∗x_* 正交,故 x∗x_* 的范数最小。

对本例取 b=(1,0,0)Tb=(1,0,0)^T,两个方向上的系数分别是 1/(62)1/(6\sqrt2) 和 1/(22)1/(2\sqrt2),得到

x∗=[1/3−1/6],Ax∗=[2/3−1/3−1/3],b−Ax∗=13[111].x_*=\begin{bmatrix}1/3\\-1/6\end{bmatrix},\quad Ax_*=\begin{bmatrix}2/3\\-1/3\\-1/3\end{bmatrix},\quad b-Ax_*=\frac13\begin{bmatrix}1\\1\\1\end{bmatrix}.

残差正是左零空间方向,AT(b−Ax∗)=0A^T(b-Ax_*)=0。AA 有满列秩,系数唯一;换成 A1A_1 后,A1v2=0A_1v_2=0,给任一解加上 tv2tv_2 都不会改变预测。线性模型的系数可辨识,要求输入方向不能被矩阵完全抹掉。

小但非零的奇异值对应另一个问题:除以它会放大数据扰动。固定 AA,若 δb=εui\delta b=\varepsilon u_i,则 δx=(ε/σi)vi\delta x=(\varepsilon/\sigma_i)v_i。例如 D=diag⁡(1,0.001)D=\operatorname{diag}(1,0.001),第二个输出坐标的扰动 10−610^{-6} 会变成系数扰动 0.0010.001。

对满列秩矩阵,谱条件数为 κ2(A)=∥A∥2∥A+∥2=σ1/σn\kappa_2(A)=\|A\|_2\|A^+\|_2=\sigma_1/\sigma_n。MIT 数值方法讲义第 5 讲把这些范数与 ATAA^TA 的最大、最小特征值联系起来,并说明 κ2(ATA)=κ2(A)2\kappa_2(A^TA)=\kappa_2(A)^2:后者的特征值是平方奇异值。本例分别为 3\sqrt3 和 3;DD 的条件数则为 1000。数值分析区分问题的敏感性与算法的稳定性;普通最小二乘与正则化进一步讨论求解器和系数解释。

为降维截断 SVD,是在控制矩阵重构误差;为求解截断伪逆,则会把某些系数方向舍弃,改变估计结果。阈值应结合数据误差与用途来选,不能把一个很小的非零奇异值直接等同于数学上的零。

用 Python 复核分量​

以下代码只用标准库,检查上面推导出的特征向量和奇异分量,并计算重构、秩一误差及最小二乘系数。辅助函数接收列表;点积的两个向量必须等长,矩阵每行的长度必须等于输入向量的长度,否则抛出 ValueError。

from math import sqrt, isclose


def dot(x, y):
if len(x) != len(y):
raise ValueError("Vector lengths must match")
return sum(a * b for a, b in zip(x, y))


def mv(matrix, vector):
return [dot(row, vector) for row in matrix]


B = [[2, 1], [1, 2]]
vectors = [[1 / sqrt(2), 1 / sqrt(2)],
[1 / sqrt(2), -1 / sqrt(2)]]
for eigenvalue, v in zip([3, 1], vectors):
assert all(isclose(a, eigenvalue * b, abs_tol=1e-12)
for a, b in zip(mv(B, v), v))

A = [[2, 0], [0, 2], [-2, -2]]
s = [sqrt(12), 2.0]
left = [[a / sigma for a in mv(A, v)]
for sigma, v in zip(s, vectors)]
assert isclose(dot(left[0], left[1]), 0, abs_tol=1e-12)
assert all(isclose(dot(u, u), 1) for u in left)
components = [[[sigma * u[i] * v[j] for j in range(2)]
for i in range(3)]
for sigma, u, v in zip(s, left, vectors)]
reconstructed = [[sum(c[i][j] for c in components) for j in range(2)]
for i in range(3)]
assert all(isclose(reconstructed[i][j], A[i][j], abs_tol=1e-12)
for i in range(3) for j in range(2))
A1 = components[0]
error = sqrt(sum((A[i][j] - A1[i][j]) ** 2
for i in range(3) for j in range(2)))
b = [1, 0, 0]
x = [sum(v[j] * dot(u, b) / sigma
for sigma, u, v in zip(s, left, vectors)) for j in range(2)]
print("eigenvalues:", [3, 1])
print("singular values:", [round(t, 6) for t in s])
print("reconstructed:", [[round(t, 6) for t in row] for row in reconstructed])
print("rank-one:", [[round(t, 6) for t in row] for row in A1])
print(f"Frobenius error: {error:.6f}")
print(f"retained variance: {s[0] ** 2 / sum(t * t for t in s):.6f}")
print("least-squares x:", [round(t, 6) for t in x])

运行输出:

eigenvalues: [3, 1]
singular values: [3.464102, 2.0]
reconstructed: [[2.0, 0.0], [0.0, 2.0], [-2.0, -2.0]]
rank-one: [[1.0, 1.0], [1.0, 1.0], [-2.0, -2.0]]
Frobenius error: 2.000000
retained variance: 0.750000
least-squares x: [0.333333, -0.166667]
探索关联打开关联网络