numpy总是得到复杂的特征值和错误的特征向量



我正在用numpy进行简单的线性代数操作。直到现在,一切都非常好,当我取一个简单的2x2矩阵,它的特征值和向量我都知道,并在它们上测试numpy时。

例如下面的示例矩阵,存在单个特征值e=1,以及单个相关的特征向量[-3,1]:

A = np.array([[-2, -9],
[ 1,  4]])

vals, vects = np.linalg.eig(A)
vals2, vects2 = np.linalg.eigh(A)
vals3 = np.linalg.eigvals(A)
print("Eigenvalues (linalg.eig): n", vals)
print("Eigenvalues (linalg.eigvals): n", vals3)
print("Eigenvectors: n", vects)

结果如下:

Eigenvalues (linalg.eig):
[1.+1.89953279e-08j 1.-1.89953279e-08j]
Eigenvalues (linalg.eigvals):
[1.+1.89953279e-08j 1.-1.89953279e-08j]
Eigenvectors:
[[ 0.9486833 +0.00000000e+00j  0.9486833 -0.00000000e+00j]
[-0.31622777-2.00228337e-09j -0.31622777+2.00228337e-09j]] 

我知道特征向量是列格式的。如果忽略小的虚部,两个向量几乎都是单个正确特征向量的标量倍数。

我的矩阵不是对称的或共轭对称的,因此linalg.eigh不应该工作,但我还是尝试了它。它给了我真正的价值,但它们完全是假的。

我还搜索了其他类似的问题,但没有找到令人满意的答案。我得到的最接近的答案是,建议写一个函数来去掉它们的小虚部的特征值。这是有效的,但仍然留下不正确的特征向量。

这里发生了什么?如何简单地修复它?为了使简单的计算正确,我自己编写函数来纠正这样一个建立良好的库似乎有点过分

Numpy为每个特征值返回归一化特征向量;由于这里的特征值具有重数2,所以它两次返回相同的特征向量。您可以使用np.real_if_close重新转换为真实:

In [156]: A = np.array([[-2, -9],
...:               [ 1,  4]])
...: 
...: w, v = np.linalg.eig(A)
...: v = np.real_if_close(v, tol=1)
...: v
Out[156]: 
array([[ 0.9486833 ,  0.9486833 ],
[-0.31622777, -0.31622777]])

卫生检查:

In [157]: v * 10**.5
Out[157]: 
array([[ 3.,  3.],
[-1., -1.]])

如果你想要精确的解决方案,而不是容易出现机器错误的解决方案。我可以建议sympy:吗

In [159]: from sympy import Matrix
...: m = Matrix(A)
...: m.eigenvects()
Out[159]: 
[(1,
2,
[Matrix([
[-3],
[ 1]])])]

其中我们得到特征值1,它的多重性2,以及与之相关的特征向量

您注意到的是相对近似误差。

Numpy并没有精确地计算特征值和特征向量,相反,它使用了强大且优化的数值算法,这些算法不会得出确切的答案,而是得出相当接近的答案。对于这些,它使用了较旧的LAPACK库dggev:http://www.netlib.org/lapack/double/dggev.f

如果你正在寻找一个确切的答案,那么Numpy不是一个适合你的解决方案。相反,看看Sympy。这里也讨论了一个类似的问题:numpy特征值和特征向量是如何计算的

最新更新