奇异值分解SVD计算原理及JAVA代码

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个,将左奇异向量一列一列排起来就得到了U,将又奇异向量一列一列排起来再进行转置就得到了V.T。

图片来自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);
	}

}

 

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值