numpy.linalg.eigh和numpy.linalg.svd怎么样?

时间:2018-05-15 19:59:32

标签: python numpy lapack numerical

问题描述

对于方阵,可以获得SVD

X= USV'

分解,只需使用 numpy.linalg.svd

u,s,vh = numpy.linalg.svd(X)     

例程或 numpy.linalg.eigh ,计算Hermitian矩阵 X' X XX' 的eig分解

他们使用相同的算法吗?调用相同的Lapack例程?

速度方面有什么不同吗?和稳定性?

2 个答案:

答案 0 :(得分:5)

事实上,numpy.linalg.svdnumpy.linalg.eigh并没有调用相同的Lapack程序。一方面,numpy.linalg.eigh指的是LAPACK的dsyevd()numpy.linalg.svd使用LAPACK的dgesdd()

这些例程之间的共同点是使用Cuppen的分而治之算法,首先设计用于解决三对角特征值问题。例如,dsyevd()仅处理Hermitian矩阵并执行以下步骤,仅在需要特征向量时才执行:

  1. 使用DSYTRD()将矩阵缩减为三对角形式

  2. 使用分而治之算法,通过DSTEDC()

  3. 计算三对角矩阵的特征向量
  4. 使用DORMTR()应用DSYTRD()报告的Householder反射。

  5. 相反,要计算SVD,dgesdd()执行以下步骤,在作业== A(需要U和VT)的情况下:

    1. 使用dgebrd()
    2. Bidiagonalize A
    3. 使用分算算法使用DBDSDC()
    4. 计算双对角矩阵的SVD
    5. 使用dgebrd()两次应用dormbr()返回的矩阵P和Q恢复双向对角化,一次用于U,一次用于V。
    6. 虽然LAPACK的实际操作非常不同,但策略在全球范围内是相似的。这可能源于这样的事实:计算一般矩阵A的SVD类似于执行对称矩阵A ^ T.A的特征分解。

      关于lapack划分和征服SVD的准确性和性能,请参阅This survey of SVD methods

      • 它们通常可以实现基于QR的SVD的准确性,但尚未得到证实。
      • 最坏的情况是O(n ^ 3),如果没有发生通货紧缩,但往往证明比这更好。
      • 内存要求是矩阵大小的8倍,这可能会变得过高。

      关于对称特征值问题,复杂度为4 / 3n ^ 3(但通常比这更好),并且内存占用量约为2n ^ 2加上矩阵的大小。因此,如果您的矩阵是对称的,那么最好的选择可能是numpy.linalg.eigh

      可以使用以下代码计算特定矩阵的实际复杂度:

      import numpy as np
      from matplotlib import pyplot as plt
      from scipy.optimize import curve_fit
      
      # see https://stackoverflow.com/questions/41109122/fitting-a-curve-to-a-power-law-distribution-with-curve-fit-does-not-work
      def func_powerlaw(x, m, c):
          return np.log(np.abs( x**m * c))
      
      import time
      
      start = time.time()
      print("hello")
      end = time.time()
      print(end - start)
      
      timeev=[]
      timesvd=[]
      size=[]
      
      for n in range(10,600):
          print n
          size.append(n)
          A=np.zeros((n,n))
          #populate A, 1D diffusion. 
          for j in range(n):
              A[j,j]=2.
              if j>0:
                  A[j-1,j]=-1.
              if j<n-1:
                  A[j+1,j]=-1.
      
          #EIG
          Aev=A.copy()
          start = time.time()
          w,v=np.linalg.eigh(Aev,'L')
          end = time.time()
          timeev.append(end-start)
          Asvd=A.copy()
          start = time.time()
          u,s,vh=np.linalg.svd(Asvd)
          end = time.time()
          timesvd.append(end-start)
      
      
      poptev, pcov = curve_fit(func_powerlaw, size[len(size)/2:], np.log(timeev[len(size)/2:]),p0=[2.1,1e-7],maxfev = 8000)
      print poptev
      
      poptsvd, pcov = curve_fit(func_powerlaw, size[len(size)/2:], np.log(timesvd[len(size)/2:]),p0=[2.1,1e-7],maxfev = 8000)
      print poptsvd
      
      plt.figure()
      
      fig, ax = plt.subplots()
      
      plt.plot(size,timeev,label="eigh")
      plt.plot(size,[np.exp(func_powerlaw(x, poptev[0], poptev[1])) for x in size],label="eigh-adjusted complexity: "+str(poptev[0]))
      
      plt.plot(size,timesvd,label="svd")
      plt.plot(size,[np.exp(func_powerlaw(x, poptsvd[0], poptsvd[1])) for x in size],label="svd-adjusted complexity: "+str(poptsvd[0]))
      
      
      ax.set_xlabel('n')
      ax.set_ylabel('time, s')
      
      #plt.legend(loc="upper left")
      
      ax.legend(loc="lower right")
      ax.set_yscale("log", nonposy='clip')
      
      fig.tight_layout()
      
      
      
      plt.savefig('eigh.jpg')
      plt.show()
      

      对于这样的一维扩散矩阵,eigh优于svd,但实际复杂度相似,略低于n ^ 3,类似于n ^ 2.5。 。 enter image description here

      也可以检查准确性。

答案 1 :(得分:1)

不,他们不会使用相同的算法,因为他们做不同的事情。它们有些相关但也非常不同。让我们首先考虑一下您可以在m x n矩阵上执行SVD,其中mn不需要相同。

取决于numpy的版本,你正在做。以下是lapack中用于双精度的特征值例程:
http://www.netlib.org/lapack/explore-html/d9/d8e/group__double_g_eeigen.html
根据SVD例程:
http://www.netlib.org/lapack/explore-html/d1/d7e/group__double_g_esing.html

例行程序有所不同。差异很大。如果你关心细节,那么很好地在fortran标题中指定它们。在许多情况下,找出你面前有什么样的矩阵是有意义的,可以选择常规。矩阵对称/埃尔米特?它是上对角形式吗?它是半正的吗? ...

运行时存在着巨大的差异。但根据经验,EIG比SVD便宜。但这也取决于收敛速度,而收敛速度又很大程度上取决于矩阵的条件数,换句话说,矩阵有多么恶劣,......

SVD通常非常强大且速度慢,通常用于反演,通过截断进行速度优化,主要成分分析实际上是开发,你正在处理的矩阵只是一堆糟糕的行;)