numpy/scipy特征分解的不稳定结果

numpy/scipy特征分解的不稳定结果,numpy,scipy,eigenvalue,Numpy,Scipy,Eigenvalue,我发现scipy.linalg.eig有时会给出不一致的结果。但不是每次 >>> import numpy as np >>> import scipy.linalg as lin >>> modmat=np.random.random((150,150)) >>> modmat=modmat+modmat.T # the data i am interested in is described by real symme

我发现scipy.linalg.eig有时会给出不一致的结果。但不是每次

>>> import numpy as np
>>> import scipy.linalg as lin
>>> modmat=np.random.random((150,150))
>>> modmat=modmat+modmat.T  # the data i am interested in is described by real symmetric matrices
>>> d,v=lin.eig(modmat)
>>> dx=d.copy()
>>> vx=v.copy()
>>> d,v=lin.eig(modmat)
>>> np.all(d==dx)
False
>>> np.all(v==vx)
False
>>> e,w=lin.eigh(modmat)
>>> ex=e.copy()
>>> wx=w.copy()
>>> e,w=lin.eigh(modmat)
>>> np.all(e==ex)
True
>>> e,w=lin.eigh(modmat)
>>> np.all(e==ex)
False
虽然我不是最伟大的线性代数向导,但我确实理解特征分解本质上会受到奇怪的舍入错误的影响,但我不理解为什么重复计算会产生不同的值。但我的结果和再现性是不同的

问题的本质到底是什么——好吧,有时候结果是可以接受的不同,有时候则不是。以下是一些例子:

>>> d[1]
(9.8986888573772465+0j)
>>> dx[1]
(9.8986888573772092+0j)
上述~3e-13的差异似乎并没有什么大不了的。相反,真正的问题(至少对我目前的项目来说)是一些特征值似乎不能在正确的符号上一致

>>> np.all(np.sign(d)==np.sign(dx))
False
>>> np.nonzero(np.sign(d)!=np.sign(dx))
(array([ 38,  39,  40,  41,  42,  45,  46,  47,  79,  80,  81,  82,  83,
    84, 109, 112]),)
>>> d[38]
(-6.4011617320002525+0j)
>>> dx[38]
(6.1888785138080209+0j)

MATLAB中类似的代码似乎没有这个问题。

我认为你的问题是你期望特征值以特定的顺序返回,并且它们的结果并不总是相同的。把它们分类,你就可以上路了。如果我用
eig
运行代码生成
d
dx
,我会得到以下结果:

>>> np.max(d - dx)
(19.275224236664116+0j)
但是

>>> d_i = np.argsort(d)
>>> dx_i = np.argsort(dx)
>>> np.max(d[d_i] - dx[dx_i])
(1.1368683772161603e-13+0j)

特征值分解满足一个V=Vλ,这就是所有被保证的——例如,特征值的顺序不是

回答你问题的第二部分:

现代编译器/线性代数库产生/包含做不同事情的代码 取决于数据是否在内存中按(例如)16字节边界对齐。这会影响计算中的舍入误差,因为浮点运算的顺序不同。如果算法(此处为LAPACK/xGEEV)不能保证这方面的数值稳定性,则舍入误差的微小变化可能会影响特征值的顺序

(如果您的代码对此类内容敏感,则它是不正确的!例如,在不同的平台或不同的库版本上运行它将导致类似的问题。)

结果通常是准确定性的——例如,根据数组是否在内存中对齐,您可以得到两个可能结果中的一个。如果您对对齐方式感兴趣,请检查
A.uuu数组_uu接口uu['data'][0]%16


有关更多信息,请参见

我尝试使用NumPy 1.6.1/SciPy 0.10.1复制此内容,但无法。我正在使用NumPy 1.6.1和SciPy 0.10.0。另外,当我没有使用copy()时,我无法产生这个错误(但它确实存在于我的更大的应用程序中,在这个应用程序中,类似于copy()的事情正在发生)。这并不意味着什么,因为这是令人难以置信的不一致。这不是很正确的答案,但它足够接近,它为我指明了正确的方向。在我的程序中发生的事情是,在我的代码中的其他地方,我在没有索引的位置索引特征向量。它确实帮助我修复了我的bug(谢谢),但它并没有解释我提出的问题,这就是为什么这个计算在多次运行时会提供不同的答案——或者不同的顺序。也就是说,好的,特征值不能保证以任何特定的顺序,但是如果你给它相同的矩阵作为输入,为什么它们会改变?除了解释之外,在这里包含一个问题的解决方案是非常有用的。我不知道如何/在何处使用
A.\uuuuu数组\u接口\uuuu['data'][0]%16
,基本上,考虑到这是我的问题,我如何更改代码,使其不敏感?