【问题标题】:Find out if matrix is positive definite with numpy用numpy找出矩阵是否是正定的
【发布时间】:2013-04-22 09:58:00
【问题描述】:

我需要确定矩阵是否为positive definite。我的矩阵是 numpy 矩阵。我期待在 numpy 库中找到任何相关的方法,但没有成功。 感谢您的帮助。

【问题讨论】:

    标签: python matrix numpy scipy


    【解决方案1】:

    您可以尝试计算 Cholesky 分解 (numpy.linalg.cholesky)。如果矩阵不是正定矩阵,这将引发LinAlgError

    【讨论】:

    • 这应该比特征值解决方案更有效。
    • 请注意,在半正定情况下,从数值上讲,还可以向矩阵添加一点单位(从而将所有特征值移动少量,例如机器精度的几倍)然后使用像往常一样的cholesky方法。
    【解决方案2】:

    你还可以检查矩阵的所有特征值是否为正,如果是则矩阵是正定的:

    import numpy as np
    
    def is_pos_def(x):
        return np.all(np.linalg.eigvals(x) > 0)
    

    【讨论】:

    • 你可以使用 np.linalg.eigvals 代替,它只计算特征值。即使这样,它也比 @NPE 的方法慢得多(10x10 矩阵为 3x,1000x1000 为 40x)。
    • 除非您知道矩阵是对称的(实际情况)或 Hermitian(复杂情况),否则并非所有正特征值都意味着正定性。例如, A = array([[1, -100],[0, 2]]) 不是正定的。有些可能包括对称或 Hermitian 作为“正定”定义的一部分,但这并不普遍。
    • @WarrenWeckesser 哎呀,没错,不是迂腐!事实上,如果使用np.linalg.cholesky,也需要检查对称性(它不会检查它并且可能返回错误的结果,正如您的示例还显示的那样)。我想知道如何检查非对称矩阵是否是正定的可以用数字来完成......
    • 您可以通过np.all(x-x.T==0) 来检查对称性
    • 这是非常低效的!对于大于大约 6 或 7 行/列的矩阵,请使用下面 NPE 指出的 cholesky。 cholesky 路线感觉不太方便(捕获异常等),但浪费少得多。
    【解决方案3】:

    我不知道为什么 NPE 的解决方案被低估了。这是最好的方法。我在Wkipedia 上发现复杂度是立方的。

    此外,据说它在数值上比 Lu 分解更稳定。并且Lu分解比寻找所有特征值的方法更稳定。

    而且,这是一个非常优雅的解决方案,因为这是事实:

    矩阵具有 Cholesky 分解当且仅当它是对称正的。

    那么为什么不使用数学呢?也许有些人害怕引发异常,但这也是一个事实,使用异常进行编程非常有用。

    【讨论】:

    • 从同一个维基百科页面,您的陈述似乎是错误的。该页面显示“如果矩阵 A 是 Hermitian 且半正定矩阵,则如果 L 的对角线条目允许为零,则它仍然具有 A = LL* 形式的分解。[3]”因此,具有Cholesky 分解并不意味着矩阵是对称正定矩阵,因为它可能只是半定矩阵。我解释错了吗?此外,您似乎只是在暗示中抛出了“对称”。即不应该是每个 Hermitian 正定矩阵都有唯一的 Cholesky 分解吗?
    【解决方案4】:

    对于一个实数矩阵 $A$,我们有 $x​​^TAx=\frac{1}{2}(x^T(A+A^T)x)$,$A+A^T$ 是对称实矩阵。所以 $A$ 是正定的,如果 $A+A^T$ 是正定的,如果 $A+A^T$ 的所有特征值都是正的。

    import numpy as np
    
    def is_pos_def(A):
        M = np.matrix(A)
        return np.all(np.linalg.eigvals(M+M.transpose()) > 0)
    

    【讨论】:

    • 这是正确回答 OP 问题的唯一答案:“如何确定矩阵是否为 DP”。所有其他答案令人困惑地假设矩阵需要对称才能确定为正,但事实并非如此。
    【解决方案5】:

    用一些现成的代码来说明@NPE的答案:

    import numpy as np
    
    def is_pd(K):
        try:
            np.linalg.cholesky(K)
            return 1 
        except np.linalg.linalg.LinAlgError as err:
            if 'Matrix is not positive definite' in err.message:
                return 0
            else:
                raise 
    

    【讨论】:

      【解决方案6】:

      以上所有答案似乎都存在一些小混乱(至少与问题有关)。

      对于实矩阵,np.linalg.cholesky 中的正特征值和正前导项的检验仅适用于对称矩阵。所以首先需要测试矩阵是否对称,然后应用其中一种方法(正特征值或 Cholesky 分解)。

      例如:

      import numpy as np
      
      #A nonsymmetric matrix
      A = np.array([[9,7],[6,14]])
      
      #check that all eigenvalues are positive:
      np.all(np.linalg.eigvals(A) > 0)
      
      #take a 'Cholesky' decomposition:
      chol_A = np.linalg.cholesky(A)
      

      矩阵 A 不是对称的,但特征值是正的,Numpy 返回的 Cholesky 分解是错误的。你可以检查一下:

      chol_A.dot(chol_A.T)
      

      与 A 不同。

      您还可以检查上面的所有 python 函数是否会为“正定性”测试为阳性。如果您尝试使用 Cholesky 分解来计算逆,这可能是一个严重的问题,因为:

      >np.linalg.inv(A)
      array([[ 0.16666667, -0.08333333],
         [-0.07142857,  0.10714286]])
      
      >np.linalg.inv(chol_A.T).dot(np.linalg.inv(chol_A))
      array([[ 0.15555556, -0.06666667],
         [-0.06666667,  0.1       ]])
      

      不同。

      总之,我建议在上面的任何函数中添加一行来检查矩阵是否对称,例如:

      def is_pos_def(A):
          if np.array_equal(A, A.T):
              try:
                  np.linalg.cholesky(A)
                  return True
              except np.linalg.LinAlgError:
                  return False
          else:
              return False
      

      您可能希望将上述函数中的 np.array_equal(A, A.T) 替换为 np.allclose(A, A.T) 以避免因浮点错误导致的差异。

      【讨论】:

      • Nitpick:您可能应该检查 numpy.linalg.LinAlgError,除非您使用 from numpy.linalg import LinAlgError 导入它,如果我只在我的代码。
      • 如果使用复杂矩阵,这可能会导致错误(即如果 A 是复正定的,因此具有严格正特征值的厄米特,cholesky 技巧仍然是正确的,但它不会通过第一个 @987654327 @ 声明为np.allclose(A, A.T))。使用 np.allclose(A, A.H) 将解决此问题(OP 说他正在使用 numpy 矩阵,如果使用 ndarray,请使用 A.conj().T 而不是 .H
      【解决方案7】:

      如果您特别想要对称(厄米特,如果复杂)正半定矩阵,则可以使用以下方法。如果您不关心对称性(厄米特,如果复杂),请删除检查它的“if”状态。如果您想要正定而不是正半定而不是删除正则化行(并将传递给 'np.lingalg.cholesky()' 的值从 'regularized_X' 更改为 'X')。下面

      import numpy as np
      
      def is_hermitian_positive_semidefinite(X):
          if X.shape[0] != X.shape[1]: # must be a square matrix
              return False
      
          if not np.all( X - X.H == 0 ): # must be a symmetric or hermitian matrix
              return False
      
          try: # Cholesky decomposition fails for matrices that are NOT positive definite.
      
              # But since the matrix may be positive SEMI-definite due to rank deficiency
              # we must regularize.
              regularized_X = X + np.eye(X.shape[0]) * 1e-14
      
              np.linalg.cholesky(regularized_X)
          except np.linalg.LinAlgError:
              return False
      
          return True
      

      【讨论】:

      • @DeepRazi Numpy 的 Cholesky 分解实现适用于复数(即复数 np.dtype)。所以是的,它在这个意义上是有效的。但是我上面的代码最初检查了转置而不是共轭转置是否等于自身,这使得整个函数对复数无效。我现在将转置更改为共轭转置,它现在对复数有效。
      【解决方案8】:

      对于非对称矩阵,您可以使用 Principal Minor Test :

      def isPD(Y):
        row = X.shape [0]
        i = 0
        j = 0
        for i in range(row+1) : 
          Step = Y[:i,:j]
          j+=1
          i+=1
          det = np.linalg.det(Step)
          if det > 0 : 
              continue 
          else :
              return ("Not Positive Definite, Test Principal minor failed")
      
        return ("Positive Definite")
      

      【讨论】:

        【解决方案9】:

        正定

        numpy.linalg.cholesky(x) # just handle the error LinAlgError
        

        正半定

        np.all(np.linalg.eigvals(x) >= 0)
        

        注意:大多数情况下np.all(np.linalg.eigvals(x) > 0) 也会给你,如果你的矩阵是PSD,即使你看到> 而不仅仅是>=,我几天前就遇到了这个问题。我认为这应该与舍入误差有关,因为我们的特征值非常小,甚至 Cholesky 分解也可能产生错误。

        注意

        为了测试,您可能需要创建一些正半定矩阵和一些正定矩阵:

        n_size=4
        a = np.random.rand(n_size)
        A_PSD = np.outer(a,a)  # the outer product of any vector generates a PSD matrix
        A_PD = A_PSD+np.identity(n_size) # little trick I found for PS matrix
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-01-11
          • 1970-01-01
          • 1970-01-01
          • 2015-03-19
          • 1970-01-01
          • 2019-10-08
          • 2017-08-12
          • 1970-01-01
          相关资源
          最近更新 更多