2010-01-18 153 views
3

我使用jama来计算SVD。它工作得很好。如果我通过方阵。例如2x2或3x3等矩阵。但是当我通过像2x3或4x8这样的东西时,它会给出 错误。我用他们所有的例子。他们有不同的构造函数来执行这项工作。也是我的第二个问题是,我usded 3x3矩阵,它给了java jama矩阵问题

double[][] vals = {{1.,1.,0},{1.,0.,1.},{1.,3.,4.},{6.,4.,8.}}; 
    Matrix A = new Matrix(vals); 

它产生以下错误:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3 

我thaught使用另一个构造函数是遵循

double[][] vals = {{1.,1.,0,4},{1.,0.,1.,2},{1.,3.,4.,8},{1.,3.,4.,8}}; 
    Matrix A = new Matrix(vals,4,3); 
之后

它产生以下输出:

A = 
1.0 1.0 0.0 
1.0 0.0 1.0 
1.0 3.0 4.0 
6.0 4.0 8.0 

A = U S V^T 

U = 
0.078 -0.115 -0.963 
0.107 -0.281 0.260 
0.402 0.886 -0.018 
0.906 -0.351 0.060 

Sigma = 
11.861881 0.000000 0.000000 
0.000000 2.028349 0.000000 
0.000000 0.000000 1.087006 

V = 
0.507705 -0.795196 -0.331510 
0.413798 0.562579 -0.715735 
0.755650 0.226204 0.614675 

rank = 3 
condition number = 10.912437186202627 
2-norm = 11.86188091889931 
singular values = 
11.861881 2.028349 1.087006 

它适用于非方矩阵。但是它对svd产生了错误的结果,因为V和S没有相同的行= 4(如果因为我是SVD新手而无法正确分析结果,我很抱歉)。任何想法? 我该怎么办?

回答

4

这里要小心,JAMA支持SVD主要为满秩矩阵,如果你看过“自述”你会发现,行为是不是亏秩(M < n)的矩阵不一定正确。

从本质上说,是什么原因导致的ArrayIndexOutOfBounds你的例外是线486 SingularValueDecomposition

return new Matrix(U,m,Math.min(m+1,n)); 

此更改为:

return new Matrix(U); 

将解决这个问题。最终在封面下发生的事情(至少对于维卡特库的例子)是你注入了一个m=4n=5的矩阵,但注意在实际输出U的尺寸为m=4n=4。如果你读了SingularValueDecomposition类的顶部它指出:

For an m-by-n matrix A with m >= n, the singular value decomposition is an m-by-n orthogonal matrix U, an n-by-n diagonal matrix S, and an n-by-n orthogonal matrix V so that A = USV'.

但是这并不能在这种情况下举行的,因为m=4n=5意味着m<n。所以,现在既然你传递一个秩亏矩阵U具有比SVD类的正常调用情况不同的尺寸,这样的声明:

new Matrix(U, m, Math.min(m+1,n)) 

将创建的m假定行的矩阵,这里是4(这是正确的)并假设列n,这里Math.min(4+1,5)=5(这是不正确的)。所以:当你打印矩阵并且打印例程调用getColumnDimension时,U矩阵返回5,这大于实际的后备阵列维度。

总之,切换到上面粘贴的行将检测U的尺寸,并因此返回一个有效的结果,而不管等级如何。

+0

感谢您的解决方案。我想用jama运行多重回归,并有同样的问题。也许我的问题很奇怪,但我不能编辑SingularValueDecomposition类。这意味着netbeans不允许我编辑jama代码。 – MTT 2013-06-05 22:54:31

1

阅读wiki article on SVD。以下代码是代表性的例子的第2节中

import Jama.Matrix; 
import Jama.SingularValueDecomposition; 

public class JAMATest { 

    static public void printMatrix(Matrix m){ 
     double[][] d = m.getArray(); 

     for(int row = 0; row < d.length; row++){ 
      for(int col = 0; col < d[row].length; col++){ 
       System.out.printf("%6.4f\t", m.get(row, col)); 
      } 
      System.out.println(); 
     } 
     System.out.println(); 
    } 

    public static void main(String[] args) { 
     double[][] vals = { {1., 0., 0., 0., 2.}, 
          {0., 0., 3., 0., 0.}, 
          {0., 0., 0., 0., 0.}, 
          {0., 4., 0., 0., 0.} 
          }; 
     Matrix A = new Matrix(vals);   
     SingularValueDecomposition svd = new SingularValueDecomposition(A); 

     System.out.println("A = "); 
     printMatrix(A); 

     System.out.println("U = "); 
     printMatrix(svd.getU()); 

     System.out.println("Sigma = "); 
     printMatrix(svd.getS()); 

     System.out.println("V = "); 
     printMatrix(svd.getV()); 
    } 
} 

,并产生所述outputL:

A = 
1.0000 0.0000 0.0000 0.0000 2.0000 
0.0000 0.0000 3.0000 0.0000 0.0000 
0.0000 0.0000 0.0000 0.0000 0.0000 
0.0000 4.0000 0.0000 0.0000 0.0000 

U = 
0.0000 0.0000 -1.0000 0.0000 
0.0000 1.0000 -0.0000 0.0000 
0.0000 0.0000 -0.0000 1.0000 
1.0000 0.0000 -0.0000 0.0000 

Sigma = 
4.0000 0.0000 0.0000 0.0000 0.0000 
0.0000 3.0000 0.0000 0.0000 0.0000 
0.0000 0.0000 2.2361 0.0000 0.0000 
0.0000 0.0000 0.0000 0.0000 0.0000 
0.0000 0.0000 0.0000 0.0000 0.0000 

V = 
0.0000 -0.0000 -0.4472 -0.8944 -0.0000 
0.0000 -0.0000 -0.0000 -0.0000 -0.0000 
0.0000 1.0000 -0.0000 -0.0000 -0.0000 
0.0000 -0.0000 -0.0000 -0.0000 1.0000 
1.0000 -0.0000 -0.8944 0.4472 -0.0000 

希望这有助于。此外,FWIW这里是Matlab的同样的问题输出:

>> A = [1.0000, 0.0000, 0.0000, 0.0000, 2.0000; 0, 0, 3, 0, 0; 0, 0, 0, 0, 0; 0, 4, 0, 0, 0]; 
>> A 

A = 

    1  0  0  0  2 
    0  0  3  0  0 
    0  0  0  0  0 
    0  4  0  0  0 

>> [U, S, V] = svd(A); 
>> U 

U = 

    0  0  1  0 
    0  1  0  0 
    0  0  0 -1 
    1  0  0  0 

>> S 

S = 

    4.0000   0   0   0   0 
     0 3.0000   0   0   0 
     0   0 2.2361   0   0 
     0   0   0   0   0 

>> V 

V = 

     0   0 0.4472   0 -0.8944 
    1.0000   0   0   0   0 
     0 1.0000   0   0   0 
     0   0   0 1.0000   0 
     0   0 0.8944   0 0.4472 

至于第一个问题,下面的代码不会产生错误:

import Jama.Matrix; 

public class JAMATest { 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 
     double[][] vals = {{1.,1.,0},{1.,0.,1.},{1.,3.,4.},{6.,4.,8.}}; 
     Matrix A = new Matrix(vals); 

    } 
} 

所以别的东西,你正在做的事情必须引起它有一个例外。尝试使用我的printMatrix方法代替你正在使用的任何东西,看看它是否有帮助。

+0

我很抱歉,但我无法理解你的答案。你认为我在我的问题中写的输出是正确的吗?有多少V和S有3排?你能解释一下吗?我很抱歉,我不是数学专家:( – user238384 2010-01-18 18:05:47

+0

修改我以前的程序上面。我包括我的printMatrix功能。请注意,我有一个类似的异常,因为你尝试使用m.getRowDimension()和m.getColumnDimension()它们对于svd.getU()方法来说看起来并不准确,将矩阵转换为double [] []似乎有诀窍。 – vicatcu 2010-01-18 18:31:43

+0

在另一个注释中,矩阵的SVD不是唯一的。引用维基百科的文章:“还应该指出的是,这种特殊的奇异值分解不是唯一的。”当你乘以U * S * V时,你将得到原始的矩阵返回。所以我们的原始矩阵是[4 x 5] = [4 x 4] * [4 x 5] * [5 x 5],并且您留下了外部的两个维度([4 .. x ..] 5])在你必须认识到只有前四行Sigma是基于这些属性的实际矩阵 – vicatcu 2010-01-18 18:36:21

0

U,S和V的尺寸不需要与A的尺寸相同.U将具有相同的行数并且V^T将具有相同的列数。这足以通过矩阵乘法的规则重新创建A.

其他维度(U的列,V^T的行和S的行/列)将是A的“等级”(在您的示例3中)。粗略地说,这是数据的维度......需要多少个轴来唯一地表示A中的一列或一行。它最多只能是min(rows, cols),但通常会少得多。那没问题。

0

贾马不支持全SVD但只减少SVD。它等同于Matlab svd(B,0)或svd(B,'econ')。再见