在Java中计算截断奇异值分解的最佳方法

4
我希望能够对计算截断奇异值分解(truncated singular value decomposition, SVD)的最佳2到3个库进行基准测试,即仅保留k个最大奇异值的SVD。此外,我有以下限制条件:
  • 必须是Java库
  • 我的矩阵是稀疏的(大约1%的非零值)
  • 我的矩阵相当大(通常为10k x 5k)
  • 我的矩阵也可能比高度更大(5k x 10k)
我找到了很多库,但例如,对于Colt,我甚至不知道SVD算法是否考虑了我的矩阵是稀疏的这一事实。另外,我没有找到一个可以直接计算截断解的库(这应该会快得多)。实际上,我最感兴趣的是从截断SVD获得的近似矩阵。
谢谢您的帮助,
Romain Laroche

Colt 在我的设置中明显太慢了。我将尝试 Jama,但从我目前所读的资料来看,它应该不会更好。 - Maveric78f
Colt太慢了,但更重要的是,它只适用于高于宽的矩形矩阵。 - Maveric78f
我正在尝试使用EJML,在遵循矩阵Java库的基准测试建议后。只要Java内存不超出堆空间,它比Colt表现更好。 - Maveric78f
同样的问题@Maveric。我想在稀疏矩阵中运行SVD,但没有成功。我发现apache.common.math可以工作,但它返回所有矩阵的NaN值。 - Gaurav Koradiya
2个回答

5
我遇到了完全相同的问题,我的解决方案是:
  1. 使用Apache Commons Math对您的矩阵运行SVD
  2. 将对角线矩阵截断,仅保留前k个奇异值
  3. 通过仅采用第一个矩阵的前k列和最后一个矩阵的前k行来截取其他两个矩阵
  4. 将三个矩阵相乘
您得到的是原始矩阵的截断SVD。
以下是完整解决方案,已在具有数千行/列的矩阵中进行了测试。
public static double[][] getTruncatedSVD(double[][] matrix, final int k) {
    SingularValueDecomposition svd = new SingularValueDecomposition(new Array2DRowRealMatrix(matrix));

    double[][] truncatedU = new double[svd.getU().getRowDimension()][k];
    svd.getU().copySubMatrix(0, truncatedU.length - 1, 0, k - 1, truncatedU);

    double[][] truncatedS = new double[k][k];
    svd.getS().copySubMatrix(0, k - 1, 0, k - 1, truncatedS);

    double[][] truncatedVT = new double[k][svd.getVT().getColumnDimension()];
    svd.getVT().copySubMatrix(0, k - 1, 0, truncatedVT[0].length - 1, truncatedVT);

    RealMatrix approximatedSvdMatrix = (new Array2DRowRealMatrix(truncatedU)).multiply(new Array2DRowRealMatrix(truncatedS)).multiply(new Array2DRowRealMatrix(truncatedVT));

    return approximatedSvdMatrix.getData();
}

这里我得到的组件都是NaN值,可能的解决方案是什么? - Gaurav Koradiya
1
@GauravKoradiya 我六年前发布了这个,老实说我不记得了 :) - Alphaaa

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接