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的答案更具可读性,这也很重要。作者想知道如何获得身份,而不是检查是否是身份——这是一个不同的问题。这是我三小时前发布的答案的翻版。