2010-01-18 172 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')。再見