【问题标题】:scipy.sparse.linalg.eigsh() doesn't give out the same result as Matlab's eigs(), why?scipy.sparse.linalg.eigsh() 给出的结果与 Matlab 的 eigs() 不同,为什么?
【发布时间】:2017-12-17 12:10:48
【问题描述】:

我正在使用scipy.sparse.linalg.eigsh() 来解决广义特征值问题。我想使用eigsh(),因为我正在处理一些大型稀疏矩阵。问题是我无法得到正确的答案,eigsh() 输出的特征值和特征向量与我从 Matlab 的eigs() 得到的完全不同。

看起来像这样: 数据:

a: 
   304.7179  103.1667   36.9583   61.3478   11.5724
    35.5242  111.4789   -9.8928    8.2586   -4.7405
    10.8358    4.3433  145.6586   26.5153   13.1871
    -1.1924   -2.5430    0.4322   43.1886   -0.6098
   -18.7751   -8.8031   -4.3962   -5.8791   17.6588
b: 
   736.9822  615.7946  587.6828  595.7169  545.1878
   615.7946  678.2142  575.7579  587.3469  524.7201
   587.6828  575.7579  698.6223  593.5402  534.3675
   595.7169  587.3469  593.5402  646.0410  530.1114
   545.1878  524.7201  534.3675  530.1114  590.1373

在python中: a,b 是 numpy.ndarray

In [11]: import scipy.sparse.linalg as lg

In [14]: x,y=lg.eigsh(a,M=b,k=2,which='SM')

In [15]: x
Out[15]: array([ 0.01456738,  0.22578463])

In [16]: y
Out[16]: 
array([[ 0.00052614,  0.00807034],
       [ 0.00514091, -0.01593113],
       [ 0.00233622, -0.00429671],
       [ 0.01877451, -0.06259276],
       [ 0.01491696,  0.08002341]])

In [18]: a.dot(y[:,0])-x[0]*b.dot(y[:,0])
Out[18]: array([ 1.74827445,  0.30325634,  0.71299604,  0.42842245, -0.24724681])

In [19]: a.dot(y[:,1])-x[1]*b.dot(y[:,1])
Out[19]: array([-2.2463206 , -1.64704567, -0.80086734, -1.56796329, 0.03027861])

可以看出,特征值和特征向量都不足以重构原始矩阵。

但是,在 MATLAB 中它运行良好:

[y,x] = eigs(a,b,2,'sm');

y =

    0.0037   -0.0141
   -0.0056    0.0151
    0.0015    0.0079
   -0.0117    0.0666
   -0.0298   -0.0753
x =

    0.0202         0
         0    0.3499
a*x(:,1)-y(1,1)*b*x(:,1)

ans =

   1.0e-14 *

   -0.3775
    0.0777
    0.0777
    0.0555
    0.0666

另外,数据 b 是正定的:

In [24]: np.linalg.eigvals(b)
Out[24]: 
array([ 2951.07297125,   137.81545217,    90.40223937,   107.04818229,
          63.65818086])

谁能解释为什么我不能在 python 中得到正确的答案?


使用lg.eigs()我们确实得到了与在 MATLAB 中相同的输出。 但是...当矩阵像这样变大时会出现问题:

test_eigs.mat

在 MATLAB 中我们有这样的东西:

>> [x,y] = eigs(A,B,4,'sm');
y =

0.0001         0         0         0
     0    0.0543         0         0
     0         0    0.1177         0
     0         0         0    0.1350

在 python(python3.5.2,scipy1.0.0) 中使用 lg.eigs(A,M=B,k=4,which='SM') 时,其特征值如下:

array([  4.43277284e+51 +0.00000000e+00j,
     1.04797857e+48 +8.30096152e+47j,
     1.04797857e+48 -8.30096152e+47j,  -1.45582240e+31 +0.00000000e+00j])

【问题讨论】:

  • 可能是因为h过剩?我没有深入研究它,但 eigsh 要求 A 是对称的或 Hermitian,而您的 A 不是。但是scipy 也有eigs,如果没有这个要求,它似乎是一样的。
  • 此外,eigsh()eigs() 的输出每次都是随机变化的。这在我的程序中是不可接受的。
  • B 在数值上是半正定的,所以你需要设置sigma
  • 随机性是由于起始向量 v0 是随机的;您可以为其提供一些值以使其具有非随机结果(请参阅 eigs 的文档)。我还没试过你的大矩阵。
  • @percusse 我试过sigma。也许我不太清楚,但我猜sigma 在我的迭代中每一轮都需要固定为给定值,不是吗?如果是这样的话,怎么每次都得到预期值呢?谢谢

标签: python matlab scipy eigenvalue eigenvector


【解决方案1】:

正如 Paul Panzer 所说,“eigsh”中的“h”代表 Hermitian,而您的矩阵 A 不是。 (此外,具有正特征值并不意味着是正定的;这仅在矩阵一开始是 Hermitian 时才成立。)eigsh 方法不检查输入是否为 Hermitian。它只是遵循一个假设它是的过程;所以假设失败时输出不正确。

使用 eigs 方法产生与 Matlab 相同的结果:

x, y = lg.eigs(a,M=b,k=2,which='SM') 
np.real(x), np.real(y)  # x and y have tiny imaginary parts due to float math errors

(array([ 0.02022333,  0.34993346]), 
 array([[-0.00368007, -0.0140898 ],
    [ 0.0056435 ,  0.01509067],
    [-0.00154725,  0.00790518],
    [ 0.01170563,  0.06664118],
    [ 0.02981777, -0.07528778]]))

当然,eigs 的运行时间比 eigsh 长得多。


您的第二个示例是一个 34 x 34 密集矩阵,它根本没有零。对它使用稀疏线性代数是不合理的;并且有一个警告说该方法没有收敛。常规线性代数模块工作正常。

import scipy.linalg as la
sorted_eigenvals = np.sort(np.real(la.eigvals(Am, Bm)))

这会返回

5.90947734e-05, 5.42521180e-02, 1.17669899e-01, 1.34952286e-01, ...

与您引用的 MATLAB 输出一致(Matlab 将数字四舍五入除外)

0.0001、0.0543、0.1177、0.1350

【讨论】:

  • 非常感谢:) 但是......对于更大的矩阵(在我的场景中,它的范围从 34*34 到 1000*1000)又会出现问题。我已经修改了问题并将原始数据文件上传到 github。如果您有机会检查一下,将不胜感激。非常感谢你:)
  • 我终于有时间测试你的矩阵了(提示:如果你想让别人用 Python 测试你的数据,不要以只有 Matlab 可以读取的格式呈现它。你可以将它保存为带有csvwrite 的 CSV)。查看答案的补充。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-07
  • 2010-10-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多