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

时间:2020-02-01 18:04:56

标签: python numpy matrix

我正在阅读一本名为 Scikit-Learn,Keras和Tensorflow的动手机器学习的书,作者在解释矩阵的伪逆(Moore-Penrose逆)是如何在线性回归的上下文中计算。我在这里逐字引用:

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

我从this的帖子中了解了伪逆和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)

1 个答案:

答案 0 :(得分:2)

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

svd

尽管这是一个2x2的矩阵,但它只有一个线性独立的列,因此其rank是1而不是2。因此,我们应该期望,当将其传递给>>> a = numpy.arange(2) + 1 >>> A = a[:, None] * a[None, :] >>> A array([[1, 2], [2, 4]]) 时,其中一个奇异值将为零。但是看看会发生什么:

svd

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