温馨提示:本文翻译自stackoverflow.com,查看原文请点击:python - Understanding the logic behind numpy code for Moore-Penrose inverse
matrix numpy python

python - 了解Moore-Penrose逆的numpy代码背后的逻辑

发布于 2020-04-11 00:18:11

我正在阅读一本名为《使用Scikit-Learn,KerasTensorflow进行动手机器学习》的书作者在解释如何在线性回归的情况下计算矩阵的伪逆(Moore-Penrose逆)。我在这里逐字引用:

伪逆本身是使用称为奇异值分解(SVD)的标准矩阵分解技术,可以分解训练集矩阵计算X成的三个矩阵的矩阵乘法û Σ V T(参照numpy.linalg.svd())。伪逆的计算公式为X + = V * Σ + * UT。为计算矩阵 Σ +,该算法将Σ并将所有小于微小阈值的值设置为零,然后将所有非零值替换为其反值,最后,它转置所得矩阵。这种方法比计算法线方程更有效。

我从这篇文章中了解了伪逆和SVD是如何关联的。但是我无法掌握将所有小于阈值的值设置为零的理由。对角矩阵的逆是通过对角元素的倒数获得的。然后在逆矩阵中将小值转换为大值,对吗?那为什么我们要删除较大的值呢?

我去看了一下numpy代码,它看起来像下面,仅供参考:

@array_function_dispatch(_pinv_dispatcher)
def pinv(a, rcond=1e-15, hermitian=False):
a, wrap = _makearray(a)
    rcond = asarray(rcond)
    if _is_empty_2d(a):
        m, n = a.shape[-2:]
        res = empty(a.shape[:-2] + (n, m), dtype=a.dtype)
        return wrap(res)
    a = a.conjugate()
    u, s, vt = svd(a, full_matrices=False, hermitian=hermitian)

    # discard small singular values
    cutoff = rcond[..., newaxis] * amax(s, axis=-1, keepdims=True)
    large = s > cutoff
    s = divide(1, s, where=large, out=s)
    s[~large] = 0

    res = matmul(transpose(vt), multiply(s[..., newaxis], transpose(u)))
    return wrap(res)

查看更多

提问者
Bitswazsky
被浏览
142
senderle 2020-02-03 23:06

几乎可以肯定,这是对数字误差的调整。要了解为什么这样做可能是必要的,请看一下采用svd1x 2x2秩矩阵时会发生什么我们可以通过像这样获取向量的外积来创建一个秩矩阵:

>>> a = numpy.arange(2) + 1
>>> A = a[:, None] * a[None, :]
>>> A
array([[1, 2],
       [2, 4]])

尽管这是一个2x2矩阵,但它只有一个线性独立的列,因此其等级为1而不是2。因此,我们应该期望在将其传递给时svd,其中一个奇异值将为零。但是看看会发生什么:

>>> U, s, V = numpy.linalg.svd(A)
>>> s
array([5.00000000e+00, 1.98602732e-16])

其实我们得到的是一个奇异值,是不是很为零。鉴于我们正在使用有限精度浮点数,因此在很多情况下此结果都是不可避免的。因此,尽管您确定的问题是一个真实的问题,但实际上我们将无法分辨出奇异值很小的矩阵和奇异值应该为零但没有的矩阵之间的区别。将小值设置为零是解决该问题的最安全实用方法。