我一直在处理Python中形式为A = Bx的线性代数问题,并将其与同事在MATLAB和Mathematica中的代码进行比较。当B是一个奇异矩阵时,我们已经注意到Python和其他矩阵之间的区别。当使用numpy.linalg.solve()
时,我抛出一个奇异矩阵错误,所以我实现了.pinv()
(摩尔彭罗斯伪逆)。
我知道存储逆是计算效率低下的,我首先想知道在Python中是否有更好的方法来处理奇异矩阵。然而,我的问题的重点在于Python如何从无限的解空间中选择一个答案,以及为什么它选择了一个与MATLAB和Mathematica不同的答案。
这是我的玩具问题:B = np.array([[2,4,6],[1,0,3],[0,7,0]])
A = np.array([[12],[4],[7]])
BI = linalg.pinv(B)
x = BI.dot(A)
Python输出给我的答案是:
[[ 0.4]
[ 1. ]
[ 1.2]]
虽然这肯定是一个正确的答案,但它不是我想要的:(1,1,1)。为什么Python生成这个特殊的解?是否有一种方法可以返回解的空间而不是一个可能的解?我同事的代码返回(1,1,1)- Python不同于Mathematica和MATLAB有什么原因吗?
简而言之,您的代码(显然是np.linalg.lstsq
)使用Moore-Penrose伪逆,这在np.linalg.pinv
中实现。MATLAB和Mathematica可能会使用高斯消去法来求解系统。我们可以在Python中使用LU分解复制后一种方法:
B = np.array([[2,4,6],[1,0,3],[0,7,0]])
y = np.array([[12],[4],[7]])
P, L, U = scipy.linalg.lu(B)
这将B
分解为B = P L U
,其中U
现在是上对角矩阵,P L
是可逆的。特别是,我们发现:
>>> U
array([[ 2., 4., 6.],
[ 0., 7., 0.],
[ 0., 0., 0.]])
和
>>> np.linalg.inv(P @ L) @ y
array([[ 12.],
[ 7.],
[ 0.]])
目标是解决这个未确定的转换问题,U x = (P L)^{-1} y
。解集和原来的问题是一样的。让解写成x = (x_1, x_2, x_3)
。然后我们立即看到,任何解决方案必须有x_2 = 1
。那么我们必须有2 x_1 + 4 + 6 x_2 = 12
。解x_1
,得到x_1 = 4 - 3 x_2
。所以任何解的形式都是(4 - 3 x_2, 1, x_2)
生成上述解决方案的最简单方法是简单地选择x_2 = 1
。然后是x_1 = 1
,然后恢复MATLAB给出的解:(1,1,1)。
另一方面,np.linalg.pinv
计算Moore-Penrose伪逆,即满足B
伪逆性质的唯一矩阵。这里的重点是唯一的。因此,当你说:
我的问题是Python如何从无限解空间中选择一个答案
答案是,当你使用伪逆时,所有的选择实际上都是由你完成的,因为np.linalg.pinv(B)
是一个唯一矩阵,因此np.linalg.pinv(B) @ y
是唯一的。
要生成完整的解决方案集,请参阅@ali_m上面的注释