LoginSignup
7
2

More than 5 years have passed since last update.

MatlabとPython(Numpy)のSVD(特異値分解)の違いについて

Last updated at Posted at 2018-01-30

目的

  • MatlabのSVD(特異値分解)とPythonのSVDの振る舞いの違いを調べる.

方法

  1. Matlabのrand関数で生成した$m \times n, m<n$の行列ランダムな行列を生成. ($m=20, n=50$)
    データ: Googleスプレッドシートからコピーまたはmatファイルをダウンロード.

  2. Matlabの関数svdsを用いてSVDを行う. Pythonのnumpy.linalg.svd関数を用いてSVDを行う. この際, 最も大きい特異値とそれに係る特異ベクトルについて比較を行う.

    • Matlabではsvds(A,k)により行列Aの最も大きいk個の特異値/特異ベクトルを得る.
    • Pythonではnumpy.linalg.svd(A)により行列Aの特異値/特異ベクトルを降順に得る.
  3. 出力された特異値, 左特異ベクトル, 右特異ベクトルをプロットして比較する.

コードと出力

Matlab

>> file_name = 'ファイルのある場所/random_mat.mat';
>> file_data = load(file_name);
>> data = file_data.data;
[U S V flag] = svds((data), 1); % SVDのサブセット, 最大特異値の出力を得る

>> U'

  1 列から 12 
    0.2245    0.2040    0.2040    0.2177    0.2319    0.2341    0.2295    0.2020    0.1833    0.2041    0.2266    0.2597
  13 列から 20 
    0.2235    0.2244    0.2418    0.2249    0.2409    0.2307    0.2062    0.2443

>> S

S =

   15.3810

>> V'

  1 列から 12 
    0.1722    0.1295    0.1461    0.1505    0.1550    0.1368    0.1490    0.1064    0.1726    0.1539    0.1277    0.1579
  13 列から 24 
    0.1508    0.1461    0.1372    0.1189    0.1264    0.1490    0.1351    0.1326    0.1604    0.1393    0.1482    0.1407
  25 列から 36 
    0.1607    0.1165    0.1639    0.1267    0.1293    0.1426    0.1419    0.1283    0.1586    0.1445    0.1452    0.1595
  37 列から 48 
    0.1137    0.1127    0.1629    0.1240    0.1341    0.1257    0.1646    0.1342    0.1221    0.1149    0.1182    0.1754
  49 列から 50 
    0.1214    0.1347

Python

>> import scipy.io as sio
>> file_name = 'ファイルのある場所/random_mat.mat';
>> file_data = sio.loadmat(file_name)
>> data = file_data['data']
>> U, S, V = np.linalg.svd(data) # SVDの結果を降順に得る

>> In [26]: U[0]
Out[26]:
array([-0.22454768,  0.17010075, -0.20816028,  0.1740133 , -0.13221578,
        0.12589231, -0.1504946 ,  0.08601189, -0.15019956,  0.0628708 ,
        0.00390582, -0.63042417, -0.17370565,  0.11313939, -0.34084198,
        0.02180581,  0.36452862,  0.14897765, -0.16904068, -0.12814262])

In [27]: S[0]
Out[27]: 15.380960870979512

In [29]: V[0]
Out[29]:
array([-0.17217701, -0.12945966, -0.14610378, -0.15052239, -0.15495316,
       -0.1368263 , -0.14904164, -0.10638937, -0.17259396, -0.1539205 ,
       -0.12765933, -0.1579254 , -0.15083483, -0.14612175, -0.13719313,
       -0.11890223, -0.12643451, -0.14904031, -0.1350735 , -0.13258259,
       -0.16038814, -0.13927807, -0.14819803, -0.14068011, -0.16073848,
       -0.11647424, -0.16391321, -0.12670191, -0.12928473, -0.14260052,
       -0.14186614, -0.12825514, -0.15857603, -0.14445415, -0.14522958,
       -0.15945624, -0.11366243, -0.11273067, -0.16286158, -0.12396521,
       -0.13413132, -0.12574699, -0.16463963, -0.13424388, -0.12212364,
       -0.11485005, -0.11818812, -0.17539564, -0.12136569, -0.13473575])

Matlabの出力をPythonにインポートして出力の比較

Matlabの出力のmatファイル
Pythonの出力のpickleファイル

Pythonのコード

# matlabでの結果のインポート
>> result_name = 'ファイルのある場所/matlab_result.mat'
>> result_file = sio.loadmat(result_name)
>> matlab_U = result_file['U']
>> matlab_S = result_file['S']
>> matlab_V = result_file['V']

# 特異値の比較
In [55]: S[0] - matlab_S
Out[55]: array([[  1.77635684e-15]])

比較

特異値

MatlabとPythonでの誤差が1.77635684e-15であることからほぼ同じであると言って良い.

左特異ベクトル

compare_U.png
まるで違う.

右特異ベクトル

compare_V.png
おや...?? 似た波形をしている.実際に符号を反転させてみると,
compare_abs_V.png
同じベクトルのようだ.

結論

  • $m \times n, m<n$の行列に対してMatlabとPythonのSVDの出力の比較を行った.
  • MatlabとPythonにおいて, 同じ特異値を得ることがわかった.一方で、違う特異ベクトルを得ることがわかった.
  • 原因: 特異値を降順に並べ替えたとき特異値は一意に定まる. 一方で特異ベクトルは一意に定まらないため.
  • SVDの一意性に調べたが, 特異値の一意性を分解の一意性と勘違いしていたためにこんなことを調べる羽目になってしまった...
  • 一方で右特異ベクトルは符号を絶対値で正にしてやると同じになることがわかったから, まぁいっか.
  • どうにかMatlabとPythonで同じSVDをしたい... → 解決しました! MatlabのSVD(特異値分解)のScipyでの再現についての検証
    • $\bf U = A\rm | \bf V \rm |^{\rm -1}\sum^{\rm -1}$とかで$\bf U$を計算しなおすとか?
7
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
2