Python:将矩阵转换为半正定矩阵

10

我目前在研究核方法,在某个阶段我需要将一个非正半定矩阵(即相似度矩阵)转化为一个正半定矩阵。

我尝试了以下方法:

def makePSD(mat):
    #make symmetric
    k = (mat+mat.T)/2
    #make PSD
    min_eig = np.min(np.real(linalg.eigvals(mat)))
    e = np.max([0, -min_eig + 1e-4])
    mat = k + e*np.eye(mat.shape[0]);
    return mat

但是如果我使用下面的函数测试生成的矩阵,它就会失败:

def isPSD(A, tol=1e-8):
    E,V = linalg.eigh(A)
    return np.all(E >= -tol)

我也尝试了其他相关问题中提出的方法(如何计算最近的半正定矩阵?),但是得到的矩阵也未能通过isPSD测试。
你有没有关于如何正确进行这种转换的建议?
3个回答

26

首先要说的是,不要使用eigh来测试正定性,因为eigh假定输入矩阵是 Hermite 矩阵。这可能是你认为你引用的答案不起作用的原因。

我不喜欢那个答案,因为它有一个迭代过程(而且我无法理解它的示例),也不喜欢其他答案,因为它不能保证给出最好的正定矩阵,即在 Frobenius 范数(元素平方和)意义下与输入最接近的矩阵。(我绝对不知道你在问题中的代码应该做什么。)

我很喜欢这篇 Higham 在1988年发表的文章的 Matlab 实现:https://www.mathworks.com/matlabcentral/fileexchange/42885-nearestspd,所以我把它移植到 Python (编辑已更新至 Python 3):

from numpy import linalg as la
import numpy as np


def nearestPD(A):
    """Find the nearest positive-definite matrix to input

    A Python/Numpy port of John D'Errico's `nearestSPD` MATLAB code [1], which
    credits [2].

    [1] https://www.mathworks.com/matlabcentral/fileexchange/42885-nearestspd

    [2] N.J. Higham, "Computing a nearest symmetric positive semidefinite
    matrix" (1988): https://doi.org/10.1016/0024-3795(88)90223-6
    """

    B = (A + A.T) / 2
    _, s, V = la.svd(B)

    H = np.dot(V.T, np.dot(np.diag(s), V))

    A2 = (B + H) / 2

    A3 = (A2 + A2.T) / 2

    if isPD(A3):
        return A3

    spacing = np.spacing(la.norm(A))
    # The above is different from [1]. It appears that MATLAB's `chol` Cholesky
    # decomposition will accept matrixes with exactly 0-eigenvalue, whereas
    # Numpy's will not. So where [1] uses `eps(mineig)` (where `eps` is Matlab
    # for `np.spacing`), we use the above definition. CAVEAT: our `spacing`
    # will be much larger than [1]'s `eps(mineig)`, since `mineig` is usually on
    # the order of 1e-16, and `eps(1e-16)` is on the order of 1e-34, whereas
    # `spacing` will, for Gaussian random matrixes of small dimension, be on
    # othe order of 1e-16. In practice, both ways converge, as the unit test
    # below suggests.
    I = np.eye(A.shape[0])
    k = 1
    while not isPD(A3):
        mineig = np.min(np.real(la.eigvals(A3)))
        A3 += I * (-mineig * k**2 + spacing)
        k += 1

    return A3


def isPD(B):
    """Returns true when input is positive-definite, via Cholesky"""
    try:
        _ = la.cholesky(B)
        return True
    except la.LinAlgError:
        return False


if __name__ == '__main__':
    import numpy as np
    for i in range(10):
        for j in range(2, 100):
            A = np.random.randn(j, j)
            B = nearestPD(A)
            assert (isPD(B))
    print('unit test passed!')

除了仅查找最近的正定矩阵外,上述库还包括isPD,它使用Cholesky分解来确定矩阵是否为正定。这样,您就不需要任何公差 - 任何想要正定的函数都会在其上运行Cholesky,因此这是确定正定性的绝佳方法。

它还有一个基于蒙特卡洛的单元测试,如果您将其放入posdef.py并运行python posdef.py,它将在我的笔记本电脑上在大约一秒钟内通过单元测试。然后在您的代码中,您可以import posdef并调用posdef.nearestPDposdef.isPD

如果您需要的话,该代码也在Gist上。


2
问题是关于将矩阵转换为半正定矩阵,但是根据我的理解,答案是关于将其转换为正定矩阵。我有什么遗漏吗? - Celik
你说得对,这个函数只返回正定矩阵,可能有正半定矩阵更好,但是论文只讨论了正定的情况。 - Ahmed Fasih

2

我知道这个帖子有点老,但是想说一下,由@user1231818提出的问题现在已经有了令人满意的答案,至少在我测试的情况下:https://dev59.com/7Wgu5IYBdhLWcg3w9ryX#63131250

我在这里留下代码,但是如果需要更多详细信息,请访问链接:

import numpy as np

def get_near_psd(A):
    C = (A + A.T)/2
    eigval, eigvec = np.linalg.eig(C)
    eigval[eigval < 0] = 0

    return eigvec.dot(np.diag(eigval)).dot(eigvec.T)

这肯定会给你一个PSD矩阵,但不一定“接近”原始矩阵。但是如果A大多数情况下是对称的,并且你不需要“最好的”,那么这个方法可以应急使用。 - Ahmed Fasih
是的,在我的情况下,A 大多是对称的。问题在于,对于我尝试过的情况(而且我尝试了很多),所有其他方法都给我提供了非常不同的矩阵,而这种简单的方法是“最接近”的。而且这些差异对我来说非常明显。虽然我不确定为什么。也许我只是尝试了太多简单的矩阵(在我的情况下主要是 2 x 2),而其他方法可能更适用于更高维度或其他情况。 - tjiagoM
2
啊,我可以看到这种情况发生:我回答中的算法最小化输入和输出之间的Frobenius范数(所有元素差的平方和),因此它可能返回一个在视觉上与输入不同的矩阵,因为它试图将误差范数分散在矩阵的所有元素之间。嗯,虽然我不确定当您将负特征值归零时会经常发生这种情况。抱歉在您发布后这么长时间打扰您,感谢您的回复! - Ahmed Fasih

1

以防其他人遇到相同的问题。 @tjiagoM和@Ahmed Fasih解释的两种方法是等效的,并且都应该给出最小化Frobenius范数的psd矩阵。 在论文的方程式(2.1)和(2.2)中。

'''
[2] N.J. Higham, "Computing a nearest symmetric positive semidefinite
matrix" (1988): https://doi.org/10.1016/0024-3795(88)90223-6
'''

在Ahmed的回答中,tjiagoM使用的计算方法被描述并实际上被称为计算最接近psd矩阵的首选方式。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接