奇異值分解SVD計算原理及JAVA程式碼
阿新 • • 發佈:2019-02-08
SVD是什麼?
SVD是針對非方陣的特徵降維方法,對於方陣通常用PCA來進行降維。設A是一個m*n矩陣 m>=n。那麼對A進行奇異值分解的結果就表示為(V.T的大小是r*n):
其中矩陣U中的列向量被稱為左奇異向量,V中的行向量被成為右奇異向量,Σ是一個對角矩陣,裡面的對角線上的值就是奇異值(特徵值)。
那麼如何分解呢?
先將A.T乘A,得到一個m*m的矩陣,再對這個方陣進行特徵值分解。
這裡的Vi就是上述的右奇異向量,它是列向量,n行1列,在構成V矩陣的時候要注意轉置,並且還可以得到:
這裡就是對應的奇異值,就是對應的左奇異向量,也是一個列向量,總共會分解出來r個
圖片來自SVD分解及其應用,這也是一篇很好的文章。
如何通過SVD來降維?
分解出奇異值後得到矩陣Σ,每個奇異值都對應一個右奇異向量、左奇異向量,奇異值的大小就代表了特徵的重要程度,往往前10%甚至前1%個奇異值之和佔總的奇異值之和就達到了85%或者更高,所以只需要選取這些奇異值代表的奇異向量就可以最大程度上降低維度且沒有損失太多資料資訊。
最後會得到哪些資料?
最後得到的就是Σ U V。Σ是奇異值對角矩陣,包含了每個特徵的奇異值(可以看成是這個特徵的重要程度)。U是左奇異向量構成的矩陣,V是右奇異向量構成的矩陣,這兩個矩陣可以互相轉化,所以選取新的特徵的時候用其中的一個就可以。並且在SVD的時候對特徵進行了壓縮,原矩陣A 為m*n,但是奇異值只有r個,壓縮後的左右奇異向量也各只有r個,然後還需要根據閾值再從r個特徵中選出佔比高的。
如何用程式碼實現?
python中scikit-learn庫可以實現SVD,JAVA中使用jama包可以實現SVD。對於JAVA先從jama官網上下載jama.jar再匯入工程中,使用的示例程式碼如下。
import Jama.Matrix; import Jama.SingularValueDecomposition; import java.text.SimpleDateFormat; public class TestSVD { public static void main(String[] args){ // create M-by-N matrix that doesn't have full rank int M = 8, N = 5; Matrix B = Matrix.random(5, 3); Matrix A = Matrix.random(M, N).times(B).times(B.transpose()); System.out.print("A = "); A.print(9, 6); // compute the singular vallue decomposition System.out.println("A = U S V^T"); System.out.println(); long start = System.currentTimeMillis(); //進行奇異值分解 SingularValueDecomposition s = A.svd(); long end = System.currentTimeMillis(); System.out.println("Singular Value Decomposition elapsed time: "+(end-start)); Matrix U = s.getU(); Matrix S = s.getS(); Matrix V = s.getV(); System.out.print("U = "); U.print(9, 6); System.out.print("Sigma = "); S.print(9, 6); System.out.print("V = "); V.print(9, 6); System.out.println("rank = " + s.rank()); System.out.println("condition number = " + s.cond()); System.out.println("2-norm = " + s.norm2()); // print out singular values System.out.print("singular values = "); Matrix svalues = new Matrix(s.getSingularValues(), 1); svalues.print(9, 6); } }