特征值与 SVD 概览
使用 np.linalg.eig 计算特征值和特征向量,并理解 SVD 如何支撑 PCA 降维
特征值与 SVD 概览 是 CoddyKit 上的免费 Pandas & NumPy Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Pandas & NumPy Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Pandas & NumPy Academy 课程共包含 4 节课。
什么是特征值和特征向量?
方阵 A 的特征向量是满足 A @ v = lambda * v 的非零向量 v——与 A 相乘只会缩放 v,而不会改变其方向。标量 λ 称为与 v 对应的特征值。特征值揭示了线性变换固有的“伸缩因子”:特征值为 2 表示矩阵会将特征向量方向上的长度加倍;负特征值则会翻转方向。
import numpy as np
A = np.array([[3.0, 1.0],
[0.0, 2.0]])
eigenvalues, eigenvectors = np.linalg.eig(A)
print('Eigenvalues:', eigenvalues)
print('Eigenvectors (columns):')
print(eigenvectors)使用 np.linalg.eig() 计算特征值
np.linalg.eig(A) 返回一个元组 (eigenvalues, eigenvectors)。特征值是一个一维数组;特征向量是一个二维数组,其中每个列都是一个特征向量。对于实对称矩阵(例如协方差矩阵),特征值始终为实数,特征向量彼此正交——对于对称矩阵,请使用 np.linalg.eigh(A),因为它速度更快,并且保证返回实数结果。
import numpy as np
# Symmetric matrix -> use eigh for efficiency and real eigenvalues
A = np.array([[4.0, 2.0],
[2.0, 3.0]])
vals, vecs = np.linalg.eigh(A)
print('Eigenvalues (real):', vals)
print('Eigenvectors (orthonormal columns):')
print(vecs)
# Verify: A @ v = lambda * v for each eigenvector
for i in range(len(vals)):
lhs = A @ vecs[:, i]
rhs = vals[i] * vecs[:, i]
print(f'v{i} check:', np.allclose(lhs, rhs))特征值与矩阵性质
特征值编码了矩阵的重要性质。行列式等于 all 特征值的乘积:det(A) = product(eigenvalues)。迹(对角元素之和)等于特征值之和:trace(A) = sum(eigenvalues)。矩阵是正定的(all 特征值 > 0)当且仅当 all 特征值均为正数——这是有效协方差矩阵和凸优化问题的一项关键性质。
import numpy as np
A = np.array([[4.0, 2.0],
[2.0, 3.0]])
vals, _ = np.linalg.eigh(A)
print('Eigenvalues:', vals)
print('Product (should = det):', np.prod(vals))
print('np.linalg.det:', np.linalg.det(A))
print('Sum (should = trace):', np.sum(vals))
print('np.trace:', np.trace(A))
print('Positive definite:', np.all(vals > 0))奇异值分解(SVD)概览
奇异值分解(SVD)可以将任意矩阵 A(不只是方阵)分解为 A = U @ S @ V.T,其中 U 和 V 是正交矩阵,S 是对角矩阵,对角线上为非负的奇异值。SVD 是最通用且数值最稳定的矩阵分解方法。它是 PCA、图像压缩、推荐系统和伪逆计算的基础。np.linalg.svd(A) 返回 U、s(一维奇异值数组)和 Vh(V 的转置)。
import numpy as np
A = np.array([[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0]])
U, s, Vh = np.linalg.svd(A, full_matrices=False)
print('U shape:', U.shape)
print('s (singular values):', s)
print('Vh shape:', Vh.shape)
# Reconstruct A
A_reconstructed = U @ np.diag(s) @ Vh
print('Reconstruction correct:', np.allclose(A, A_reconstructed))奇异值与矩阵秩
奇异值(S 的对角元素)始终为非负数,通常按降序排列。非零奇异值的数量等于矩阵的秩。接近零的奇异值表示行或列之间接近线性相关。最大的奇异值给出了矩阵的谱范数,而最大奇异值与最小非零奇异值之比就是用于衡量数值稳定性的条件数。
import numpy as np
# Full-rank matrix
A = np.random.rand(5, 3)
U, s, Vh = np.linalg.svd(A, full_matrices=False)
print('Singular values:', np.round(s, 4))
print('Rank (non-zero sv):', np.linalg.matrix_rank(A))
print('Condition number:', s[0] / s[-1])
# Rank-deficient matrix
B = np.array([[1.0, 2.0], [2.0, 4.0], [3.0, 6.0]])
_, sb, _ = np.linalg.svd(B, full_matrices=False)
print('Rank-deficient sv:', np.round(sb, 8))SVD 与 PCA:二者的联系
主成分分析(PCA)可以直接通过 SVD 实现。将数据矩阵 X 进行中心化(减去各列的均值)后,Vh 中的右奇异向量就是主成分,而奇异值的平方除以 n-1 得到解释方差。Sklearn 的 PCA 正是采用这种方法。理解这种联系后,您就可以从头实现或自定义 PCA,用于降维。
import numpy as np
np.random.seed(0)
X = np.random.randn(100, 4)
# Center the data
X_centered = X - X.mean(axis=0)
# SVD-based PCA
U, s, Vh = np.linalg.svd(X_centered, full_matrices=False)
# Variance explained by each component
var_explained = (s ** 2) / (X.shape[0] - 1)
total_var = var_explained.sum()
print('Variance explained ratio:', np.round(var_explained / total_var, 3))
# Project onto top 2 principal components
X_pca = X_centered @ Vh[:2].T
print('Reduced shape:', X_pca.shape)使用 SVD 进行低秩近似
SVD 支持低秩矩阵近似:只保留前 k 个奇异值和奇异向量,然后重建原矩阵的近似结果。这是图像压缩和推荐系统协同过滤的基础。截断 SVD U[:, :k] @ np.diag(s[:k]) @ Vh[:k, :] 在最小二乘意义下给出了最佳的秩为 k 的近似(Eckart-Young 定理)。
import numpy as np
np.random.seed(1)
A = np.random.rand(20, 15)
U, s, Vh = np.linalg.svd(A, full_matrices=False)
# Rank-3 approximation
k = 3
A_approx = U[:, :k] @ np.diag(s[:k]) @ Vh[:k, :]
error = np.linalg.norm(A - A_approx, 'fro')
total = np.linalg.norm(A, 'fro')
print(f'Approximation error: {error/total:.3f} (fraction of total)')
print(f'Top-3 singular values capture {(s[:3]**2).sum()/(s**2).sum():.1%} of variance')特征分解与 SVD:何时使用哪一种
当您有一个方形对称矩阵,并希望理解其主轴时,请使用特征分解(np.linalg.eig 或 eigh),例如 PCA 中的协方差矩阵或马尔可夫转移矩阵。当矩阵为矩形,或您需要最高的数值稳定性时,请使用 SVD(np.linalg.svd)。SVD 始终存在;对于非对称矩阵,特征分解可能产生复数。
import numpy as np
# Non-symmetric matrix: eigenvalues may be complex
A = np.array([[0.0, -1.0],
[1.0, 0.0]])
vals, _ = np.linalg.eig(A)
print('Eigenvalues (complex for rotation):', vals)
# SVD always gives real singular values
_, s, _ = np.linalg.svd(A)
print('Singular values (always real):', s)对称矩阵的谱定理
谱定理指出,每个实对称矩阵 A 都可以分解为 A = Q @ diag(eigenvalues) @ Q.T,其中 Q 是正交矩阵(Q.T = Q⁻¹)。这意味着对称矩阵始终可以通过实特征值和正交特征向量对角化。协方差矩阵、SVM 中的核矩阵以及优化中的海森矩阵都是对称的,因此该定理在机器学习理论中具有普遍用途。
import numpy as np
A = np.array([[5.0, 2.0, 1.0],
[2.0, 3.0, 0.0],
[1.0, 0.0, 4.0]])
vals, Q = np.linalg.eigh(A)
print('Eigenvalues:', np.round(vals, 4))
# Reconstruct A = Q @ diag(vals) @ Q.T
A_reconstructed = Q @ np.diag(vals) @ Q.T
print('Reconstruction correct:', np.allclose(A, A_reconstructed))
print('Q is orthogonal:', np.allclose(Q.T @ Q, np.eye(3)))实践:使用幂迭代求主特征值
当您只需要最大特征值及其特征向量时,幂迭代比计算 all 特征值高效得多。从一个随机向量开始,反复与 A 相乘并进行归一化,最终会收敛到主特征向量。这就是 Google 最初的 PageRank 算法所采用的方法。NumPy 让每次迭代只需通过 @ 执行一次矩阵-向量乘法。
import numpy as np
A = np.array([[4.0, 1.0, 2.0],
[1.0, 3.0, 0.0],
[2.0, 0.0, 2.0]])
v = np.random.rand(3)
for _ in range(50):
v = A @ v
v = v / np.linalg.norm(v)
eigenvalue_approx = v @ A @ v
print('Dominant eigenvector:', np.round(v, 4))
print('Approx eigenvalue:', round(eigenvalue_approx, 4))
# Verify with eigh
vals, vecs = np.linalg.eigh(A)
print('True max eigenvalue:', round(vals[-1], 4))在实际流水线中使用 np.linalg.svd
在实际的数据流水线中,SVD 用于降噪和数据压缩。在训练数据上拟合 SVD 后,只保留能够捕获 95% 方差的前 k 个成分。这样,在将新数据输入分类器或回归器之前,可以先降低其维度,从而加快训练速度,并且通常能够通过移除噪声维度来提升泛化能力。务必只在训练数据上拟合 SVD,并将相同的变换应用于测试数据。
import numpy as np
np.random.seed(7)
X_train = np.random.randn(200, 50)
X_test = np.random.randn(40, 50)
# Fit on training data
X_mean = X_train.mean(axis=0)
X_centered = X_train - X_mean
U, s, Vh = np.linalg.svd(X_centered, full_matrices=False)
# Choose k to capture 90% variance
cumvar = np.cumsum(s**2) / (s**2).sum()
k = np.searchsorted(cumvar, 0.9) + 1
print(f'Components to capture 90% variance: {k}')
# Transform test data using the same Vh
X_test_reduced = (X_test - X_mean) @ Vh[:k].T
print('Reduced test shape:', X_test_reduced.shape)快速检查
测试您对本课数据分析概念的理解。
课程回顾
在本课中,您学到了:np.linalg.eig()/eigh() 计算特征值和特征向量,揭示矩阵固有的伸缩方向;np.linalg.svd() 将任意矩阵分解为 U、奇异值和 Vh,从而支持 PCA 和低秩近似;奇异值量化每个成分所捕获的方差,并决定矩阵的秩。接下来,我们将学习通过分块流式读取 CSV 文件来处理大型数据集。
常见问题解答
「特征值与 SVD 概览」课时是免费的吗?
是的 — 「特征值与 SVD 概览」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Pandas & NumPy Academy 课程的其余内容,请升级到 CoddyKit PRO。 Pandas & NumPy Academy 课程共包含 4 节课。
「特征值与 SVD 概览」这节课中我会学到什么?
使用 np.linalg.eig 计算特征值和特征向量,并理解 SVD 如何支撑 PCA 降维 你通过在浏览器中直接运行的动手代码来练习 Pandas & NumPy Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Pandas & NumPy Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Pandas & NumPy Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「特征值与 SVD 概览」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Pandas & NumPy Academy 课中编写并运行代码吗?
能。每节 Pandas & NumPy Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 使用 np.matmul 和 @ 进行矩阵乘法
- 行列式、逆矩阵与转置
- 线性方程组求解
- 特征值与 SVD 概览