2012-01-06 109 views
9

协方差矩阵的特征值应该是实数且非负的,因为协方差矩阵是对称和半正定的。scipy.linalg.eig返回协方差矩阵的复特征值?

但是,看看下面的实验SciPy的:

>>> a=np.random.random(5) 
>>> b=np.random.random(5) 
>>> ab = np.vstack((a,b)).T 
>>> C=np.cov(ab) 
>>> eig(C) 
7.90174997e-01 +0.00000000e+00j, 
2.38344473e-17 +6.15983679e-17j, 
2.38344473e-17 -6.15983679e-17j, 
-1.76100435e-17 +0.00000000e+00j, 
5.42658040e-33 +0.00000000e+00j 

然而,复制在Matlab上面的例子可以正常工作:

a = [0.6271, 0.4314, 0.3453, 0.8073, 0.9739] 
b = [0.1924, 0.3680, 0.0568, 0.1831, 0.0176] 
C=cov([a;b]) 
eig(C) 
-0.0000 
-0.0000 
0.0000 
0.0000 
0.7902 

回答

20

你提了两个问题:

  1. 通过scipy.linalg.eig返回的特征值是不是真实的。
  2. 某些特征值是负值。

这两个问题都是由截断和舍入错误引起的错误的结果,这些错误始终发生在使用浮点算法的迭代算法中。请注意,Matlab结果也产生负特征值。

现在,对于这个问题的一个更有趣的方面:​​为什么Matlab的结果是真实的,而SciPy的结果有一些复杂的组件?

Matlab的eig检测输入矩阵是真正的对称还是厄密,并且当它是时使用Cholesky因式分解。请参阅eig documentation中参数chol的说明。这不会在SciPy中自动完成。

如果要使用利用实对称或厄密矩阵结构的算法,请使用scipy.linalg.eigh。对于这个问题的例子:

>>> eigh(C, eigvals_only=True) 
array([ -3.73825923e-17, -1.60154836e-17, 8.11704449e-19, 
     3.65055777e-17, 7.90175615e-01]) 

这样的结果是一样的Matlab的,如果四舍五入到相同数量的该Matlab的印刷精度数字。

3

什么,你遇到的是数值不稳定由于浮点精度的限制。

需要注意的是:

(1)MATLAB也回到负值,但打印格式设置为short,你没有看到存储在内存双的全精度。使用format long g打印更多小数点

(2)numpy的linalg.eig返回的所有虚部都接近机器精度。因此你应该将它们视为零。