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

Posted

技术标签:

【中文标题】scipy.linalg.eig 返回协方差矩阵的复特征值?【英文标题】:scipy.linalg.eig return complex eigenvalues for covariance matrix? 【发布时间】:2012-02-04 14:58:09 【问题描述】:

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

不过,看看下面的 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

【问题讨论】:

【参考方案1】:

您提出了两个问题:

    scipy.linalg.eig 返回的特征值不是真实的。 一些特征值是负的。

这两个问题都是由截断和舍入误差引入的错误造成的,使用浮点运算的迭代算法总是会发生这种情况。请注意,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 的结果相同。

【讨论】:

【参考方案2】:

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

注意:

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

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

【讨论】:

以上是关于scipy.linalg.eig 返回协方差矩阵的复特征值?的主要内容,如果未能解决你的问题,请参考以下文章

使用 R copula 包拟合 copula 时估计相关(协方差)矩阵

matlab中怎样求随机数的和、均方差、均值、平方

如何用matlab计算样本均值和方差

协方差矩阵的计算

协方差矩阵怎么求?

MATLAB学习八:协方差cov