我一直在处理Python中 A = Bx 形式的线性代数问题,并将其与MATLAB和Mathematica中的同事代码进行比较。当 B 是一个奇异矩阵时,我们注意到了Python和其他人之间的差异。当使用numpy.linalg.solve()
时,我抛出一个奇异矩阵错误,所以我反而实现了.pinv()
(Moore Penrose伪逆)。
据我所知,存储逆是计算效率低的,如果有更好的方法来处理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不同?
答案 0 :(得分:2)
简而言之,您的代码(显然np.linalg.lstsq
)使用了Moore-Penrose伪逆,它在np.linalg.pinv
中实现。 MATLAB和Mathematica可能使用高斯消元法来解决系统问题。我们可以使用LU分解在Python中复制后一种方法:
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
的伪逆属性的唯一矩阵。这里的重点是 unique 。因此,当你说:
我的问题在于Python如何从无限的解决方案空间中选择答案
答案是,当您使用伪逆时,所有选择都是由您完成的,因为np.linalg.pinv(B)
是一个唯一矩阵,因此np.linalg.pinv(B) @ y
是唯一的。
要生成完整的解决方案,请参阅@ali_m上面的评论。