2013-11-21 22 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