用java实现奇异值分解(SVD)

首先奇异值分解(Singular Value Decomposition,以下简称SVD)描述如下:

奇异值分解(Singular Value Decomposition)是线性代数中一种重要的矩阵分解,奇异值分解则是特征分解在任意矩阵上的推广。在信号处理,统计学等领域有重要应用。

假设M是一个m×n阶矩阵,其中的元素全部属于域 K,也就是实数域或复数域。如此则存在一个分解使得

其中U是m×m阶矩阵;Σ是半正定m×n阶对角矩阵;而V*,即V的共轭转置,是n×n阶矩阵。这样的分解就称作M的奇异值分解。Σ对角线上的元素Σi,其中Σi即为M的奇异值。

常见的做法是为了奇异值由大而小排列。如此Σ便能由M唯一确定了。(虽然U和V仍然不能确定)

直观的解释

在矩阵M的奇异值分解中

·U的列(columns)组成一套对M的正交"输入"或"分析"的基向量。这些向量是MM*的特征向量。

·V的列(columns)组成一套对M的正交"输出"的基向量。这些向量是M*M的特征向量。

·Σ对角线上的元素是奇异值,可视为是在输入与输出间进行的标量的"膨胀控制"。这些是M*M及MM*的奇异值,并与U和V的列向量相对应。

我们用java实现如下:

首先我们需要用到特征分解,可以参考我之前写的一篇文章,里面使用了雅克比(Jacobi)算法进行特征分解

https://blog.csdn.net/luohualiushui1/article/details/88342768

然后我们实现SVD主方法如下:

	public static DenseMatrix64F[] runSVD(DenseMatrix64F A) {
		
		//求输入矩阵的转置
		DenseMatrix64F A_T = new DenseMatrix64F(A.numCols,A.numRows);
		
		CommonOps.transpose(A, A_T);
		
		//求A.T*A
		DenseMatrix64F ATA = new DenseMatrix64F(A.numCols,A.numCols);
		
		CommonOps.mult(A_T,A,ATA);
		
		
		
		
		//求A*A.T
		DenseMatrix64F AAT = new DenseMatrix64F(A.numRows,A.numRows);
		
		CommonOps.mult(A,A_T,AAT);
		
		
		
		
		EDInfo ATA_de = Jacobi.JacobiCount(ATA,0.001,1000);
		
		EDInfo AAT_de = Jacobi.JacobiCount(AAT,0.001,1000);
		
		
		
		//计算奇异值
		DenseMatrix64F singulars = new DenseMatrix64F(A.numRows,A.numCols);
		
		singulars.zero();
		
		for(int i=0;i

然后我们开始测试

		double[][] datas = {{0,1},{1,1},{1,0}};
		
		 DenseMatrix64F[] usv = runSVD(new DenseMatrix64F(datas));
		 
		 System.out.println(usv[0]);
		 System.out.println(usv[1]);
		 System.out.println(usv[2]);

测试结果如下:

这里我们用一个简单的例子来说明矩阵是如何进行奇异值分解的。我们的矩阵A定义为:

 

用java实现奇异值分解(SVD)_第1张图片

矩阵依次是U,Σ,V

你可能感兴趣的:(java,AI,算法,深度学习,机器学习,数据挖掘,矩阵运算)