2013-11-21 55 views
4

以我Python代碼,我用numpy.linalg.svd計算一些數據的SVD:由該返回爲什麼犰狳的SVD結果與NumPy不同?

from numpy import linalg 
(_, _, v) = linalg.svd(m) 

V矩陣變換是:

[[ 0.4512937 -0.81992002 -0.35222884] 
[-0.22254721 0.27882908 -0.93419863] 
[ 0.86417981 0.4999855 -0.05663711]] 

雖然移植我的代碼C++,我切換到使用Armadillo用於計算SVD:

#include <armadillo> 

arma::fmat M; // Input data 
arma::fmat U; 
arma::fvec S; 
arma::fmat V; 
arma::svd(U, S, V, M); 

對於相同的數據所得到的V是:

0.4513 -0.2225 -0.8642 
-0.8199 0.2788 -0.5000 
-0.3522 -0.9342 0.0566 

我們可以看到,來自Armadillo的V的轉置與來自NumPy的V相匹配。除此之外,來自Armadillo的V的最後一列。這些值與NumPy結果的最後一行中的值具有相反的符號。

這裏發生了什麼?爲什麼兩個流行庫的SVD結果會有這樣的差異?兩者中的哪一個是正確的結果?

+0

什麼是您將SVD應用於您的原始矩陣?你能保證它在兩個系統之間是一致的嗎?通常唯一的區別可能是特徵向量的大小... –

+0

@ AlexanderL.Belikoff:是的,輸入數據是相同的。在C++中,類型是float,在Python中它是我猜的兩倍。但是,這種精度差異應該不重要? –

+0

從技術上來說,SVD分解並不是唯一的(不能確定符號的變化)。除此之外,可能其中一個返回V *而不是V,因此是轉置。此外,在一個實數矩陣的SVD中產生一個U和V,它們都是旋轉矩陣,「犰狳」在這裏是正確的。你可以發佈你的原始矩陣? – sbabbi

回答

6

兩者都是正確的...你從numpy得到的v的行是M.dot(M.T)的特徵向量(轉置將是複數情況下的共軛轉置)。特徵向量在一般情況下僅限於乘法常數,因此您可以將v的任何行乘以不同的數字,並且它仍然是特徵向量矩陣。

v還有一個附加約束條件,它是unitary matrix,它鬆散地轉換爲其正交正交的行。這將每個特徵向量的可用選項減少到2:指向任一方向的歸一化特徵向量。但您仍然可以將任何行乘以-1,並仍然有效v

如果你想測試你的矩陣,這是我加載a

>>> u, d, v = np.linalg.svd(a) 
>>> D = np.zeros_like(a) 
>>> idx = np.arange(a.shape[1]) 
>>> D[idx, idx] = d 
>>> np.allclose(a, u.dot(D).dot(v)) 
True 
>>> v[2] *= -1 
>>> np.allclose(a, u.dot(D).dot(v)) 
True 

其實,你只能通過-1在現實域倍增的v行,但在複雜情況下,您可以將它們乘以任何複數絕對值1:

>>> vv = v.astype(np.complex) 
>>> vv[0] *= (1+1.j)/np.sqrt(2) 
>>> np.allclose(a, u.dot(D).dot(v)) 
True 
+0

謝謝Jaime!我使用v來旋轉點,就像在PCA中一樣。那麼,我認爲使用從Armadillo獲得的V對此沒有任何傷害? –

+0

是的,您的座標軸的對齊方式不會改變,唯一的區別是[基準方向](http://en.wikipedia.org/wiki/Orientation_(vector_space)),它不應該是一個相關的問題在多數情況下。請注意,至少在這種情況下,它是通常的右手方向的基礎。再次,我認爲差異應該與調整數據相關。 – Jaime