3

jamaを使用して SVD を計算しています。それは非常にうまく機能します。正方行列を渡す場合。たとえば、2x2 または 3x3 などのマトリックス。しかし、この 2x3 または 4x8 のようなものを渡すと、エラーが発生します。私は彼らの例をすべて使用しました。それらは、ジョブを実行するための異なるコンストラクターを持っています。また、私の2番目の質問は、私は3x3マトリックスを使用していて、それは与えました

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

その後、次のような別のコンストラクターを使用することを考えました

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

非正方行列で機能しました。しかし、V と S には同じ行 = 4 がないため、svd に対して間違った結果が生成されました (私は SVD が初めてなので、結果を適切に分析できなかったら申し訳ありません)。何か案が?私は何をすべきか?

4

4 に答える 4

4

ここで注意してください。JAMA は主にフル ランク行列の SVD をサポートしています。「readme」を読むと、ランク不足 (m < n) 行列の動作が必ずしも正しいとは限らないことに気付くでしょう。

本質的に、ArrayIndexOutOfBounds 例外の原因は の 486 行目ですSingularValueDecomposition

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

これを次のように変更します。

return new Matrix(U);

問題を解決します。カバーの下で起こる究極のこと (少なくとも vicatcu の例では) は、行列にm=4andを挿入することですn=5が、実際の出力Uには次元m=4とがあることに注意してn=4ください。クラスのトップを読むと、次のSingularValueDecompositionように述べられています。

m >= n の m 行 n 列の行列 A の場合、特異値分解は m 行 n 列の直交行列 U、n 行 n 列の対角行列 S、および n 行 n 列の直交行列 V です。 A = U S V' となります。

しかし、これはこの場合には当てはまりませm=4ん。したがって、ランク落ち行列を渡しているため、U は SVD クラスの通常の呼び出しケースとは異なる次元を持ち、そのようなステートメントは次のようになります。n=5m<n

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

ここmでは 4 の行 (正しい) と仮定された列(これは正しくありません)の行列を作成します。したがって、行列を印刷し、印刷ルーチンが を呼び出すと、U 行列は を返します。これは、実際のバッキング配列の次元よりも大きくなります。nMath.min(4+1,5)=5getColumnDimension5

つまり、上で貼り付けた行に切り替えると、U の次元が検出されるため、ランクに関係なく有効な結果が返されます。

于 2010-01-18T19:53:27.543 に答える
1

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());
    } 
} 

そして出力Lを生成します:

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メソッドを使用してみて、それが役立つかどうかを確認してください.

于 2010-01-18T17:55:09.360 に答える
0

U、S、および V の次元は、A と同じ次元である必要はありません。U は同じ数の行を持ち、V^T は同じ数の列を持ちます。行列の乗算の規則によって A を再作成するには、これで十分です。

他の次元 (U の列、V^T の行、および S の行/列) は、A の「ランク」になります (例 3)。これは、大まかに言えば、データの次元です... A の列または行を一意に表すために必要な軸の数ですmin(rows, cols)。多くても、それよりもはるかに少ない場合があります。それは大丈夫です。

于 2010-01-18T19:16:16.593 に答える