我正在寻找一种 C/C++/Python 算法实现来计算对称的半正定协方差矩阵的特征值和特征向量。
通用特征分解算法的复杂度约为,但对于对称的半正定协方差矩阵,可能存在更快的方法。
我正在寻找一种 C/C++/Python 算法实现来计算对称的半正定协方差矩阵的特征值和特征向量。
通用特征分解算法的复杂度约为,但对于对称的半正定协方差矩阵,可能存在更快的方法。
TL;DR:我认为您无法击败任何真实/供应商的特征求解器,但想想很有趣。
更深切:对称特征分解的一种经典算法是通过户主方法对 A=Q T Q' 进行三对角化,然后在 T 上进行 QR 迭代。QR 迭代(非常)松散地基于迭代:[Q,R] = A; A = R * Q。也就是说,在 QR 分解之间交替,然后以相反的顺序将它们相乘。在多次迭代的限制下,A 将收敛到对角矩阵(从而显示特征值)并且也与原始输入相似(相同的特征值)。
对于对称正定 A,我认为理论上您可以使用基于 Cholesky 分解的类似三元迭代的方法击败该算法 [Consult Golub & Van Loan 第 3 版,第 8 章,问题 8.2.1]。它会(非常)松散地基于迭代 [G,G'] = chol(A); A = G'*G。也就是说,计算 Cholesky 分解,然后以相反的顺序将它们相乘。值得注意的是,这也收敛到一个对角矩阵,这类似于原始输入。与正交迭代的偏离是轻微的担忧,但幸运的是 Cholesky 分解也相当稳定。您还希望使用户主三对角化“前端”该算法,以便所有有问题的 A 都变成三对角线,而 Cholesky 都是带状的,band=1。从根本上说,
我认为您还可以在进行过程中“累积”所有这些相似性变换(本质上是带状反解步骤),以构建特征向量。这就是在经典 QR 迭代中累积给定旋转的方式。如果由于某种原因这是不可行的,一旦你掌握了特征值,你总是可以在最后使用逆迭代。
综上所述,真实/供应商求解器不仅在执行愚蠢的 QR/RQ/QR/RQ 迭代......(至少)还有转移,以及该领域更广泛的(更快!)算法(划分和征服、MRR、二等分等)。这是一个荒谬的机器/累积改进,试图与之竞争......许多(!!)人年的努力已经投入到这些算法及其实现(EISPACK/LAPACK/MKL/等)的开发中。我认为这是一个有趣的思想实验(哇,一个由如此简单的分解构建的特征求解器),但不是一个非常实用的实验。
对称矩阵的特征分解有专门的方法。LAPACK 有DSYEV
,Numpy 有numpy.linalg.eigh
。它们仍然是,但总体上更便宜且更准确。你应该使用它们。
我不熟悉 JAMA,但从我可以谷歌并在一分钟内理解的内容中,它是 QR/Francis 算法的旧的 pre-LAPACK 实现的纯 Java 端口。这可能是让你慢下来的原因。尝试用本机代码替换它:找到用您的语言包装 LAPACK 的任何库,然后使用它。
据我所知,您的矩阵是半正定的,也无法从它具有对角线 1 的事实(当人们说“协方差矩阵”时假设的属性)获得进一步的加速。我认为,如果可以的话,廉价的缩放和移位技巧将允许对所有对称矩阵应用相同的加速。
我认为,对于,您应该对 Matlab 中的 eig 方法或 Numpy/Python 中的 numpy.linalg.eig 感到满意。因为它是一个协方差算子,所以它是对称正半定的。或许您可以通过求解器传递这些信息来加快实现速度。
对于如此小的矩阵,几乎没有机会更快地解决它。
如果你的协方差矩阵有一些结构,确实有更快解决问题的方法 - 并且比:
如果您的矩阵是 Toeplitz 或带有 Toeplitz 块的 Block-Toeplitz,则可以使用循环嵌入来采样. 链接到教程。
有一些多极方法可用于加速协方差算子的特征分解。请参阅此技术报告。
您需要解决几个矩阵的特征分解。如果有一些底层结构,您可以在减少的基础上解决问题。我和我的同事提供的预印本可能会对您有所帮助。
Schur 分解是寻找对称矩阵的特征值和特征向量的一个很好的解决方案。在 MATLAB 中,使用 schur.m。