PCA与SVD应用中负号问题

最近应用pca时遇到一个问题:自己写的pca过程和调用sklearn中的pca最后得到转换空间后的矩阵总有负号差异,后来通过读源码,常识,发现了问题原因:

简单说一下pca的实现,首先对于一个矩阵X,我们计算X·XT,显然这个一个半正定矩阵,可以做特征值分解,然后取出k个最大的特征值及其对应的特征向量就可以表达整个原矩阵。若X·XT=p-1Λp,因为p是单位矩阵,所以p-1=pT,即X·XT=p-1·Λ1/2·(p-1·Λ1/2)T,也就是降维的X后用来p-1·Λ1/2表示。其实从SVD的角度来理解也是一样的,若X=UΣVT,则X·XT=UΣ2UT,同样我们用来UΣ来表示原X。

当我看sklearn的文档时,文档并没有具体解释它的方法得到的结果在数学上的表示什么,钻研了半天,看了源码后才知道。

sklearn中的PCA分解时的方法是通过SVD来实现的。(自己写的PAC使用eig_val, eig_vec = np.linalg.eig(scatter_matrix),方法不同最后分解得到的值也就不同,svd的代码如下)发现方法用的这个不同后,自己又改成SVD的方法去做,结果就是还是相差负号,功夫不如有心人,还是发现了少了一步,在sklearn中的pAC中分解完后进行翻转特征向量符号以强制执行确定性输出操作(svd_flip,这才是相差负号的原因。我们看一下fit中的部分关键代码。

...
self.mean_ = np.mean(X, axis=0)
X -= self.mean_
U, S, V = linalg.svd(X, full_matrices=False)
U, V = svd_flip(U, V)
components_ = V
...
self.components_ = components_[:n_components]
...

 

经过了这个svd_flip函数处理后负号问题就解决了。应用sklearn中的PCA接口实现和我自己写的PAC得到的矩阵结果是完全一致的了

 

posted @ 2018-08-22 19:00  深海里的猫  阅读(2897)  评论(1编辑  收藏  举报