Numpy/Scipy的pinv和pinv2行为不同。

4
我正在使用Numpy处理二维数组来进行极限学习机的工作。我的其中一个数组H是随机的,我想计算它的伪逆。 如果我使用scipy.linalg.pinv2,一切都很顺利。但是,如果我使用scipy.linalg.pinv,有时候(30-40%的情况下)会出现问题。
我之所以使用pinv2,是因为我在这里读到(http://vene.ro/blog/inverses-pseudoinverses-numerical-issues-speed-symmetry.html),pinv2能够更好地处理“高”和“宽”数组。
问题在于,如果H有一列j全是1,pinv(H)在第j行上有很大的系数。 这反过来又是一个问题,因为在这种情况下,np.dot(pinv(H),Y)包含一些nan值(Y是一个由小整数组成的数组)。
现在,我对线性代数和数值计算不够了解,无法确定这是一个错误还是两个函数精度相关的属性。如果是这样,请您回答这个问题,这样我就可以提交错误报告(老实说,此时我甚至不知道该写什么)。
我用 np.savetxt(fn, a, '%.2e', ';') 保存了数组:请参见 https://dl.dropboxusercontent.com/u/48242012/example.tar.gz 查找它们。
感谢您的帮助。在提供的文件中,您可以在 pinv(H).csv 中看到第14、33、55、56和99行具有巨大的值,而在 pinv2(H) 中相同的行具有更好的值。
感谢您的帮助。

改用浮点数而不是整数? - Carl Witthoft
你能解释一下为什么会改变结果吗? - marcotama
我还没有查看你的数据,但如果你有大于32位整数的值,那么你可能会强制将数据转换为NaN。 - Carl Witthoft
pinv和pinv2的不同行为是在NaN出现之前。它们出现在连续的点积中。你说得对,在这一点上,大量的整数和float16之间的点积可能会导致NaN,因为结果数组仍然是float16,因此无法存储大值。然而,这并不能解释为什么pinv和pinv2的结果如此不同。 - marcotama
截至2022年,pinv2已被弃用。 - skjerns
2个回答

3
简而言之,这两个函数实现了计算伪逆矩阵的两种不同方法:
  1. scipy.linalg.pinv使用最小二乘法,可能需要大量计算并占用大量内存。https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.pinv.html#scipy.linalg.pinv

  2. scipy.linalg.pinv2使用奇异值分解(SVD),在大多数情况下应该以较小的内存占用运行。numpy.linalg.pinv也实现了这种方法。

    https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.pinv2.html#scipy.linalg.pinv2
由于这是两种不同的评估方法,因此得出的矩阵将不相同。每种方法都有其优点和缺点,并且如果不深入了解数据和伪逆用途,则不总是容易确定应该使用哪种方法。我建议尝试几次并使用为分类器提供最佳结果的方法。
请注意,在某些情况下,这些函数无法收敛到解决方案,然后会引发scipy.stats.LinAlgError。在这种情况下,您可以尝试使用第二个pinv实现,这将大大减少您收到的错误数量。

1

从scipy 1.7.0开始,pinv2已被弃用,并被SVD解决方案替代。

DeprecationWarning: 自SciPy 1.7.0起,scipy.linalg.pinv2已被弃用,请使用scipy.linalg.pinv

这意味着,numpy.pinvscipy.pinvscipy.pinv2现在都计算所有等效的解决方案。它们的计算速度也相同,其中scipy略快一些。

import numpy as np
import scipy

arr = np.random.rand(1000, 2000)
res1 = np.linalg.pinv(arr)
res2 = scipy.linalg.pinv(arr)
res3 = scipy.linalg.pinv2(arr)

np.testing.assert_array_almost_equal(res1, res2, decimal=10)
np.testing.assert_array_almost_equal(res1, res3, decimal=10)

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