SVD 速度较慢,但通常被认为是首选方法,因为它具有更高的数值精度。
正如您在问题中所说,主成分分析 (PCA) 可以通过中心数据矩阵的 SVD (有关更多详细信息,请参阅此 Q&A 线程)或协方差矩阵(或者,如果,请参阅此处了解更多详细信息)。X1n−1X⊤XXX⊤n≪p
这是 MATLAB 的pca()
函数帮助中写的内容:
pca
用于执行主成分分析的主成分算法[...]:
'svd' -- 默认值。X 的奇异值分解 (SVD)。
'eig' - 协方差矩阵的特征值分解 (EIG)。EIG 算法比 SVD 更快,当观察次数,n, 超过变量的数量,p, 但不太准确,因为协方差的条件数是 X 的条件数的平方。
最后一句话强调了关键的速度-准确性权衡。
您正确地观察到协方差矩阵的特征分解通常比数据矩阵的 SVD 更快。这是 Matlab 中的一个简短基准,随机1000×100数据矩阵:
X = randn([1000 100]);
tic; svd(X); toc %// Elapsed time is 0.004075 seconds.
tic; svd(X'); toc %// Elapsed time is 0.011194 seconds.
tic; eig(X'*X); toc %// Elapsed time is 0.001620 seconds.
tic; eig(X*X'); toc; %// Elapsed time is 0.126723 seconds.
在这种情况下,最快的方法是通过协方差矩阵(第三行)。当然,如果n≪p(而不是相反)那么这将是最慢的方式,但在这种情况下使用 Gram 矩阵XX⊤(第四行)将是最快的方式。无论哪种方式,数据矩阵本身的 SVD 都会变慢。
但是,它会更准确,因为相乘X本身会导致数值精度损失。这是一个示例,改编自@JM 对Why SVD on的回答X优于特征分解XX⊤在Math.SE 上的 PCA中。
考虑一个数据矩阵
X=⎛⎝⎜⎜⎜1ϵ0010ϵ0100ϵ⎞⎠⎟⎟⎟,
有时称为 Läuchli 矩阵(让我们在此示例中省略居中)。它的平方奇异值为3+ϵ2,ϵ2, 和ϵ2. 服用ϵ=10−5,我们可以使用 SVD 和 EIG 来计算这些值:
eps = 1e-5;
X = [1 1 1; eye(3)*eps];
display(['Squared sing. values of X: ' num2str(sort(svd(X),'descend').^2')])
display(['Eigenvalues of X''*X: ' num2str(sort(eig(X'*X),'descend')')])
获得相同的结果:
Squared sing. values of X: 3 1e-10 1e-10
Eigenvalues of X'*X: 3 1e-10 1e-10
但现在服用ϵ=10−10我们可以观察到 SVD 如何仍然表现良好,但 EIG 出现故障:
Squared sing. values of X: 3 1e-20 1e-20
Eigenvalues of X'*X: 3 0 -3.3307e-16
这里发生的是,协方差矩阵的计算使条件数平方X, 所以特别是在X有一些几乎共线的列(即一些非常小的奇异值),首先计算协方差矩阵,然后计算其特征分解与直接 SVD 相比会导致精度损失。
我应该补充一点,人们通常很乐意忽略这种潜在的[微小]精度损失,而是使用更快的方法。