scipy.linalg.eig返回协方差矩阵的复特征值?

时间:2012-01-06 22:29:02

标签: python matlab numpy scipy linear-algebra

协方差矩阵的特征值应该是实数和非负的,因为协方差矩阵是对称矩阵和半正定矩阵。

但是,请看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

2 个答案:

答案 0 :(得分:27)

您提出了两个问题:

  1. scipy.linalg.eig返回的特征值不是真实的。
  2. 有些特征值是负数。
  3. 这两个问题都是截断和舍入错误引起的错误的结果,这些错误总是发生在使用浮点运算的迭代算法中。请注意,Matlab结果也产生了负特征值。

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

    Matlab的eig检测输入矩阵是实对称还是Hermitian,并且当它是时使用Cholesky分解。请参阅eig documentationchol参数的说明。这不是在SciPy中自动完成的。

    如果要使用利用实对称或Hermitian矩阵结构的算法,请使用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相同。

答案 1 :(得分:5)

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

请注意:

(1)MATLAB也返回负值,但打印格式设置为short,并且您没有看到存储在内存中的double的完整精度。使用format long g打印更多小数

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