我正在尝试使用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]])
显然不是身份(多次运行时给出的答案略有不同)
答案 0 :(得分:3)
打印出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)
就是这样做)时,会将这些元素设置为零。相反,round的值应为最接近的整数而不是被截断:
np.around(I).astype(int)
但是,您将不会总是有这样的整数输入,在这种情况下,四舍五入会产生误导。 Numpy提供了allclose
函数,用于比较公差范围内的值:
np.allclose(I, np.identity(I.shape[0]), rtol=0, atol=1e-15)
您还可以使用isclose
进行逐元素检查:
np.isclose(I, np.identity(I.shape[0]), rtol=0, atol=1e-15)
我将相对容差设置为零,因为它乘以第二个矩阵的元素,使它在这种情况下无用。
答案 1 :(得分:2)
问题在于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
功能。
答案 2 :(得分: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]])
但这显然不是身份。但是,如果仔细观察,对角线值非常接近1,而所有其他值实际上都是很小的数字(几乎为零),如指数中的-16
或-17
。
此错误是因为浮点值永远都不是精确值,所以它们中总是存在一些错误。看一下文章15. Floating Point Arithmetic: Issues and Limitations和Is floating point math broken?。
现在,如果我们仅将其转换为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
之前先对其进行四舍五入,则会获得一个身份。
>>> np.around(M @ Mi).astype(int)
array([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]])
答案 3 :(得分:1)
问题是,矩阵是否接近np.eye(4)
。
这是您应该检查的方式:
I = M@Mi
EPS = 1e-8
r = np.all(np.abs(I - np.eye(4)) < EPS)
r
将指示两个矩阵(I
和标识)是否接近1e-8。
答案 4 :(得分:0)
您在这里的目标是什么?
似乎您只是想知道如何获取单位矩阵并比较矩阵乘法的结果是否接近该矩阵。
如果是这样,这就是你应该做的:
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))