在Python中寻找特征值/特征向量的最快方法是什么?

45 投票
2 回答
62337 浏览
提问于 2025-04-16 21:27

我现在在用numpy,它能完成我的工作。不过,我正在处理几千行和几千列的矩阵,之后这个数字还会增加到几万行几万列。我在想,是否有其他的工具可以更快地进行这种计算呢?

2 个回答

9

如果你的矩阵是稀疏的,也就是说里面大部分元素都是零,那么你可以试试使用scipy的稀疏特征值函数,这样会更快一些:

http://docs.scipy.org/doc/scipy/reference/sparse.linalg.html

你还可以看看一些专门的工具包,比如SLEPc,它有Python的接口,并且可以通过mpi进行并行计算:

http://code.google.com/p/slepc4py/

63
  • **如果你的矩阵是稀疏的,建议使用scipy.sparse中的构造函数来创建你的矩阵,然后在scipy.sparse.linalg中使用相应的特征向量/特征值方法。从性能的角度来看,这样做有两个好处:

    • scipy.sparse构造的矩阵会更小,具体大小取决于它的稀疏程度。

    • 稀疏矩阵的特征值/特征向量方法eigseigsh)可以接受一个可选参数k,这个参数是你想要返回的特征向量/特征值对的数量。通常来说,能够解释超过99%方差所需的数量远小于列数,你可以在计算后验证这一点;换句话说,你可以告诉方法不要计算和返回所有的特征向量/特征值对——超出(通常)小部分所需的特征向量/特征值对,其他的通常用不到。

  • 使用SciPy中的线性代数库scipy.linalg而不是同名的NumPy库。这两个库名字相同,方法名也一样,但性能上有差别。这种差别是因为numpy.linalg是对相应的LAPACK例程的一个不太完美的封装,牺牲了一些性能以换取可移植性和便利性(也就是说,为了符合NumPy的设计目标,即整个NumPy库应该在没有Fortran编译器的情况下构建)。而SciPy中的linalg则是对LAPACK的一个更完整的封装,并使用了f2py

  • 选择适合你使用场景的函数;换句话说,不要使用超出你需求的函数。在scipy.linalg中,有几个函数可以计算特征值;虽然它们之间的差别不大,但通过仔细选择计算特征值的函数,你应该能看到性能提升。例如:

    • scipy.linalg.eig返回特征值和特征向量
    • scipy.linalg.eigvals只返回特征值。所以如果你只需要矩阵的特征值,就不要使用linalg.eig,而是使用linalg.eigvals
    • 如果你有一个实值的对称矩阵(等于它的转置),那么使用scipy.linalg.eigsh
  • 优化你的SciPy构建。准备你的SciPy构建环境主要是在SciPy的setup.py脚本中完成的。性能上最重要的选项可能是识别任何优化过的LAPACK库,比如ATLAS或Accelerate/vecLib框架(仅限OS X?),这样SciPy就能检测到它们并进行构建。根据你当前的设备,优化你的SciPy构建并重新安装可以显著提高性能。有关SciPy核心团队的更多说明,请查看这里

这些函数适用于大矩阵吗?

我认为是的。这些是工业级的矩阵分解方法,实际上只是对相应的Fortran LAPACK例程的简单封装。

我使用过linalg库中的大多数方法来分解列数通常在5到50之间、行数通常超过500,000的矩阵。无论是SVD还是特征值方法似乎都能很好地处理这种大小的矩阵。

使用库中的linalg,你可以通过一次调用,使用该库中的几种方法(eigeigvalsheigh)来计算特征向量和特征值。

>>> import numpy as NP
>>> from scipy import linalg as LA

>>> A = NP.random.randint(0, 10, 25).reshape(5, 5)
>>> A
    array([[9, 5, 4, 3, 7],
           [3, 3, 2, 9, 7],
           [6, 5, 3, 4, 0],
           [7, 3, 5, 5, 5],
           [2, 5, 4, 7, 8]])

>>> e_vals, e_vecs = LA.eig(A)

撰写回答