Python 矩阵乘以逆不产生恒等式

Python 矩阵乘以逆不产生恒等式,python,numpy,matrix,Python,Numpy,Matrix,我试图使用np.linalg.inv()函数找到给定矩阵的逆矩阵inv生成一个看起来不错的矩阵,但是当尝试将原始矩阵乘以逆矩阵时,输出不是逆矩阵定义所假定的恒等式 from numpy.linalg import inv M = np.random.random((4, 4)) Mi = inv(M) I = M @ Mi # using matrix multiplication operator I.astype(int) #as the output looks like 2.77555

我试图使用
np.linalg.inv()
函数找到给定矩阵的逆矩阵
inv
生成一个看起来不错的矩阵,但是当尝试将原始矩阵乘以逆矩阵时,输出不是逆矩阵定义所假定的恒等式

from numpy.linalg import inv

M = np.random.random((4, 4))
Mi = inv(M)
I = M @ Mi # using matrix multiplication operator
I.astype(int) #as the output looks like 2.77555756e-17

>>> array([[0, 0, 0, 0],
           [0, 0, 0, 0],
           [0, 0, 0, 0],
           [0, 0, 0, 1]])

这显然不是标识(在多次运行时给出的答案略有不同)

在转换为int之前,请先尝试将其舍入

np.around(I).astype(int)
创建随机矩阵:

>>> M = np.random.random((4,4))
>>> M
array([[0.51351957, 0.57864882, 0.0489495 , 0.85066216],
       [0.60052988, 0.93844708, 0.74651889, 0.17237584],
       [0.26191596, 0.46451226, 0.46514401, 0.81917544],
       [0.19247662, 0.82801899, 0.83839146, 0.08531949]])
取反:

>>> from numpy.linalg import inv
>>> Mi = inv(M)
>>> Mi
array([[-1.3515514 ,  3.53647196,  1.0391335 , -3.64654487],
       [ 2.76188122, -2.23981308, -2.74634579,  3.35680468],
       [-2.44320291,  1.47102487,  2.36135635, -1.28451339],
       [ 0.2533113 , -0.69591469,  1.10498293, -0.00818495]])
现在,将
M
Mi
相乘应该会产生标识

>>> M @ Mi
array([[ 1.00000000e+00, -4.44089210e-16, -1.11022302e-16, -6.93889390e-18],
       [-4.16333634e-17,  1.00000000e+00, -8.32667268e-17, -8.60856525e-17],
       [ 5.55111512e-17, -2.22044605e-16,  1.00000000e+00, -1.57859836e-16],
       [ 6.24500451e-17, -8.32667268e-17, -2.35922393e-16, 1.00000000e+00]])
>>> np.around(M @ Mi).astype(int)
array([[1, 0, 0, 0],
       [0, 1, 0, 0],
       [0, 0, 1, 0],
       [0, 0, 0, 1]])
但这显然不是身份。但如果仔细观察,对角线值非常接近1,所有其他值都是非常小的数字(几乎为零),如指数中的
-16
-17

这个错误是,因为浮点值从来都不是精确的值,所以它们总是有一些错误。看一看这篇文章,然后

现在,如果我们把它转换成int,很可能它仍然不是一个恒等式。因为一个非常接近1的值,它实际上可能比1小一点,当转换为
int
时,结果是0

>>> (M @ Mi).astype(int)
array([[1, 0, 0, 0],
       [0, 0, 0, 0],
       [0, 0, 1, 0],
       [0, 0, 0, 0]])
但如果在转换为
int
之前先将其四舍五入,则会得到一个标识

>>> M @ Mi
array([[ 1.00000000e+00, -4.44089210e-16, -1.11022302e-16, -6.93889390e-18],
       [-4.16333634e-17,  1.00000000e+00, -8.32667268e-17, -8.60856525e-17],
       [ 5.55111512e-17, -2.22044605e-16,  1.00000000e+00, -1.57859836e-16],
       [ 6.24500451e-17, -8.32667268e-17, -2.35922393e-16, 1.00000000e+00]])
>>> np.around(M @ Mi).astype(int)
array([[1, 0, 0, 0],
       [0, 1, 0, 0],
       [0, 0, 1, 0],
       [0, 0, 0, 1]])

问题是,矩阵是否接近np.eye(4)

这是您应该检查的方式:

I = M@Mi
EPS = 1e-8
r = np.all(np.abs(I - np.eye(4)) < EPS)
I=M@Mi
EPS=1e-8
r=np.all(np.abs(I-np.eye(4))

r
将指示这两个矩阵(
I
和标识)是否接近1e-8。

打印
I
时,如下所示:

array([[ 1.00000000e+00, -5.55111512e-17, -1.66533454e-16, 0.00000000e+00],
       [ 6.38378239e-16,  1.00000000e+00, -5.55111512e-17, 0.00000000e+00],
       [ 0.00000000e+00,  0.00000000e+00,  1.00000000e+00, 0.00000000e+00],
       [-5.55111512e-17, -1.11022302e-16, -1.24900090e-16, 1.00000000e+00]])
但是,
1.00
条目并不准确。打印
1-I
时,您可以看到:

array([[-2.22044605e-16,  1.00000000e+00,  1.00000000e+00, 1.00000000e+00],
       [ 1.00000000e+00,  2.22044605e-16,  1.00000000e+00, 1.00000000e+00],
       [ 1.00000000e+00,  1.00000000e+00,  0.00000000e+00, 1.00000000e+00],
       [ 1.00000000e+00,  1.00000000e+00,  1.00000000e+00, 0.00000000e+00]])
正对角线条目表示
I
中略小于1的值。当您执行整数截断(这就是
astype(int)
所做的),您将把这些元素设置为零。而是将值转换为最接近的整数,而不是截断:

np.around(I).astype(int)
但是,您不一定总是有这样的整数输入,在这种情况下,舍入会产生误导。Numpy提供用于比较公差范围内的值的功能:

np.allclose(I, np.identity(I.shape[0]), rtol=0, atol=1e-15)
您还可以使用以下方法执行元素检查:


我将相对公差设置为零,因为它与第二个矩阵的元素相乘,因此在这种情况下它是无用的。

问题在于
astype
函数不舍入,它只是截断。因此,您没有看到标识矩阵的原因是,其他应为
1
的值大约在
0.99999
附近。您可以使用以下选项:

import numpy as np
a = np.random.random((4,4))
b = np.linalg.inv(a)
# 0.00001 is the tolerance about which you which to consider values to be == 1
c = np.array(a@b + 0.00001, dtype=int)
print(c)
如果您想简单地四舍五入(高公差==0.5),请使用以下选项:

import numpy as np
a = np.random.random((4,4))
b = np.linalg.inv(a)
c = np.array(np.round(a@b), dtype=int)
print(c)

此外,最好使用完整的
np.linalg.inv
函数。

您的目标是什么

看起来你只是想知道如何得到单位矩阵,并比较矩阵乘法的结果是否接近它

如果是这样,您应该这样做:

import numpy as np

matrix1 = np.random.random((4,4))
matrix1_inv = np.linalg.inv(matrix1)

# get what may be identity matrix
ident_pred = matrix1 @ matrix1_inv

# get what is the identity matrix
ident_true = np.identity(matrix1.shape[0])

# check that they are the same
print(np.allclose(ident_pred, ident_true))

整数截断就是这样工作的。你试过四舍五入吗?这仍然会隐藏高达50%的差异。是的,这让我感到困扰,所以我在这一部分中添加了一段。我认为添加
astype(int)
只是为了查看矩阵。真正的用例可能不涉及转换为
int
@MatthieuBrucher。我已完成编辑。谢谢你的耐心。不用担心,很好的解决方案。你的ε应该比这个小很多+1作为第一个发布合理比较方法的人。事实上,我只是给出了1e-8作为参考,我会用ε来表示它的两倍或一个小增量。这不是最好的解决方案,当结果为50%时,会把结果看作是好的,当它不是的时候,我已经更新了它——第一个解决方案包括一个容差阈值,这仍然是不正确的,并且没有正确地检查结果接近于身份矩阵。正确的方法是@MadPhysician answer。“正确”是主观的——我的答案比@MadPhysician的答案更具可读性,这也很重要。作者想知道如何获得身份,而不是检查是否是身份——这是一个不同的问题。这是我三小时前发布的答案的翻版。