最近應用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得到的矩陣結果是完全一致的了