如何判断一个矩阵是否为正定矩阵?
我的矩阵是一个NumPy矩阵。我本来期望在NumPy库中能找到相关的方法,但是没有成功。
我的矩阵是一个NumPy矩阵。我本来期望在NumPy库中能找到相关的方法,但是没有成功。
import numpy as np
def is_pos_def(x):
return np.all(np.linalg.eigvals(x) > 0)
numpy.linalg.cholesky
)。如果矩阵不是正定的,它将引发LinAlgError
错误。numpy.linalg.cholesky
的文档中可以看到:没有执行检查以验证 a 是否是 Hermitian。此外,只使用 a 的下三角和对角线元素。
换句话说,如果你测试一个非对称或非 Hermitian 矩阵,即使该矩阵不是正定的,cholesky
也可能不会引发 LinAlgError
。请参考 @DanielGarza 的答案,了解潜在的修复方法。 - Praveen以上所有回答中似乎存在一些小混淆(至少与问题相关)。
对于实矩阵,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),以避免由于浮点误差而导致的差异。
numpy.linalg.LinAlgError
,除非你使用 from numpy.linalg import LinAlgError
导入它,但如果我在代码中只捕获这个特定的异常一两次,我不想这样做。 - Imperishable Nightnp.allclose(A, A.T)
的第一个“if”语句)。使用np.allclose(A, A.H)
将解决此问题(OP表示他正在使用numpy矩阵,如果使用ndarray,请使用A.conj().T
而不是.H
)。 - H. Rev.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
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
np.all( X - X.H == 0 )
这个判断条件太严格了,我认为 np.allclose(X, X.H)
更好。 - syockitX - X.H
时没有浮点数或其他数字误差。因此,如果您以可靠的厄米方式构建X,则此算法是正确的选择。如果您正在逼近一个厄米矩阵,那么我同意使用allclose
更好。 - CognizantApeimport numpy as np
def is_pos_def(A):
M = np.matrix(A)
return np.all(np.linalg.eigvals(M+M.transpose()) > 0)
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+1e-5*np.identity(n_size) # little trick I found for PS matrix
eigvals
检查正定性时,您可能需要将其与某个epsilon进行比较。例如,np.linalg.matrix_rank
使用机器epsilon乘以最大特征值(和max(x.shape)
),而np.linalg.lstsq
以类似的方式使用机器epsilon。实际上,如果存在低于机器epsilon但带有负号的特征值,则上述PSD测试可能会失败。 - syockitminV['success']
),或达到最大迭代次数(minV['status'] == 2
)。如果在这一点上结果仍然是正的,我们可以认为该矩阵是正定的。from scipy.optimize import minimize
import numpy as np
def is_pos_def(m,z0='rand', maxiter=100):
#tells if matrix is positive definite
if m.shape[0] != m.shape[1]:
raise Exception("Matrix is not square")
elif (m==m.T).all(): #symmetry testing
return np.all(np.linalg.eigvals(m) > 0)
else:
def f(z):
z=np.array(list(z))[:,np.newaxis]
return np.dot(np.dot(z.T, m),z)
if z0=='rand':
z0 = list(np.random.rand(m.shape[0]))
#constraints for a non-zero vector solution
cons = ({'type': 'ineq', 'fun': lambda z: np.sum(np.abs(z))})
minV = minimize(f, z0, method='COBYLA', options={'maxiter' : maxiter},constraints=cons);
if minV['success'] or minV['status'] == 2:
return minV['fun']+0 > 0
else:
return minV
这种方法适用于对称和非对称的矩阵,你可以使用以下矩阵进行测试(也可以在wolfram alpha上验证)
m=np.array([[3, 0, 0],
[0, 2, 0],
[4, 3, 3]])
np.linalg.cholesky
,检查对称性也是必要的(它不会检查并可能返回错误结果,就像您的示例一样)。我想知道如何通过数值方法检查非对称矩阵是否正定... - jorgecanp.all(x-x.T==0)
来检查对称性。 - shinjinnp.linalg.eigvalsh
代替;它的计算速度更快。 - Joren