在python中计算一个非常大且稀疏的邻接矩阵的所有特征值的最快方法是什么?

计算科学 线性代数 Python 表现 本征系统 scipy
2021-12-04 00:54:43

我试图弄清楚是否有比使用 scipy.sparse.linalg.eigsh 更快的方法来计算一个非常大且稀疏的邻接矩阵的所有特征值和特征向量据我所知,这种方法只使用稀疏和矩阵的对称属性。邻接矩阵也是二进制的,这让我觉得有一种更快的方法来做到这一点。

我创建了一个随机的 1000x1000 稀疏邻接矩阵,并在我的 x230 ubuntu 13.04 笔记本电脑上比较了几种方法:

  • scipy.sparse.linalg.eigs:0.65 秒
  • scipy.sparse.linalg.eigsh:0.44 秒
  • scipy.linalg.eig:6.09 秒
  • scipy.linalg.eigh:1.60 秒

使用稀疏的 eigs 和 eigsh,我将所需的特征值和特征向量的数量 k 设置为矩阵的秩。

问题从更大的矩阵开始——在 9000x9000 矩阵上,scipy.sparse.linalg.eigsh 花了 45 分钟!

2个回答

FILTLAN是一个 C++ 库,用于计算稀疏对称矩阵的内部特征值。有一整套专门用于解决此问题的事实应该告诉您,这是一个非常困难的问题。找到对称矩阵的最大或最小的几个特征值可以通过移位/反转和使用 Lanczos 算法来完成,但频谱的中间是另一回事。如果您确实想使用它,可以使用 SWIG 从 python 调用 C++ 程序。

如果您的最终目标是计算矩阵的大幂,您可以只计算与最大特征值相对应的特征向量,因为您知道较小的模式在您采用大幂时将不那么重要。

也就是说,您可能确实最好直接计算幂。当您计算更高的功率时,它们会变得越来越稀疏,这意味着占用更多的内存;取决于多高ķ是,您最终可能想要切换到密集矩阵。

如果这些对您来说已经很明显,请原谅我:您可以通过告诉 numpy 它由整数而不是浮点数组成来利用矩阵的二进制性质,例如使用

a = np.zeros(100,dtype=np.uint)

这将(希望)节省一些空间。您可以通过阻止矩阵乘法来节省时间(但不能节省内存)。说你想计算一个16; 你计算一个2, 然后平方得到一个4, 平方得到一个8, 等等。这样,你做日志2ķ矩阵乘法而不是ķ乘法。

如果您关心速度并且您拥有 NVIDIA GPU,您还可以探索从 Python 调用并行稀疏线性代数库(如 CUSP 或 cuSPARSE)。

我想评论 Daniel Shapero 的回答,但我没有足够的 SE 声誉。

接受的答案让我很困惑。我认为移位反转模式可以很容易地用于计算内部特征值。请参阅: https ://docs.scipy.org/doc/scipy/reference/tutorial/arpack.html

回答最初的问题:您很少需要大型稀疏矩阵的所有特征值。通常,您需要极值或一些内部值集群。在这种情况下,对于 Hermitian 矩阵eigsh来说更快。对于非厄米特人,您将不得不选择eigs. 而且它们比 numpyeigeigh.