Java - 最小二乗法!

Updated:


※この記事は10年以上前に投稿されたもので、情報が古い可能性があります。

これまで、C++, Ruby, Fortran による「最小二乗法」のアルゴリズムを紹介しました。

今回は、同じアルゴリズムを Java で実現してみました。アルゴリズムについては、上記リンクの記事を参照してください。

0. 前提条件Permalink

  • Linux Mint 13 Maya (64bit) での作業を想定。
  • コンパイラ・ランタイムは、 Oracle Java 1.7.0_51 を想定。
  • 最小二乗法についての説明は割愛。(「C++ - 最小二乗法!」を参照)

1. Java ソースコード作成Permalink

File: LeastSquaresMethod.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/**************************************
 最小二乗法 ( LeastSquaresMethod.java )
 **************************************/

/*
 * 計算クラス
 */
class Calc {
    // 定数定義
    static final byte N = 7;  // データ数
    static final byte M = 5;  // 予測曲線の次数
    static final double X[] = {-3, -2, -1,  0, 1, 2, 3};  // 測定データ x
    static final double Y[] = { 5, -2, -3, -1, 1, 4, 5};  // 測定データ y

    // 変数宣言
    double s[]   = new double[2 * M + 1];
    double t[]   = new double[M + 1];
    double a[][] = new double[M + 1][M + 2];

    // コンストラクタ
    Calc() {
        // s[] 初期化
        for (int i = 0; i <= 2 * M; i++)
            s[i] = 0;
        // t[] 初期化
        for (int i = 0; i <= M; i++)
            t[i] = 0;
    }

    // 最小二乗法
    void calcLeastSquaresMethod() {
        try {
            // s[], t[] 計算
            calcST();

            // a[][] に s[], t[] 代入
            insST();

            // 掃き出し
            sweepOut();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    // s[], t[] 計算
    private void calcST() {
        for (int i = 0; i < N; i++) {
            for (int j = 0; j <= 2 * M; j++)
                s[j] += Math.pow(X[i], j);
            for (int j = 0; j <= M; j++)
                t[j] += Math.pow(X[i], j) * Y[i];
        }
    }

    // a[][] に s[], t[] 代入
    private void insST() {
        for (int i = 0; i <= M; i++) {
            for (int j = 0; j <= M; j++)
                a[i][j] = s[i + j];
            a[i][M + 1] = t[i];
        }
    }

    // 掃き出し
    private void sweepOut() {
        for (int k = 0; k <= M; k++) {
            double p = a[k][k];
            for (int j = k; j <= M + 1; j++)
                a[k][j] /= p;
            for (int i = 0; i <= M; i++) {
                if (i != k) {
                    double d = a[i][k];
                    for (int j = k; j <= M + 1; j++)
                        a[i][j] -= d * a[k][j];
                }
            }
        }
    }

    // y 値計算&結果出力
    void display() {
        try {
            for (int k = 0; k <= M; k++)
                System.out.printf("a%d = %10.6f\n", k, a[k][M + 1]);
            System.out.println("    x    y");
            for (double px = -3; px <= 3; px += .5) {
                double p = 0;
                for (int k = 0; k <= M; k++)
                    p += a[k][M + 1] * Math.pow(px, k);
                System.out.printf("%5.1f%5.1f\n", px, p);
            }
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

/*
 * メイン
 */
class LeastSquaresMethod {
    public static void main (String[] args) {
        Calc obj = new Calc();

        try {
            // 最小二乗法計算
            obj.calcLeastSquaresMethod();

            // 結果出力
            obj.display();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

2. Java ソースコードコンパイルPermalink

$ javac LeastSquaresMethod.java

何も出力されなければ成功。

3. 実行Permalink

実際に、実行してみる。

$ java LeastSquaresMethod
a0 =  -1.259740
a1 =   2.100000
a2 =   0.424242
a3 =  -0.083333
a4 =   0.030303
a5 =  -0.016667
    x    y
 -3.0  5.0
 -2.5  0.3
 -2.0 -2.1
 -1.5 -2.9
 -1.0 -2.8
 -0.5 -2.2
  0.0 -1.3
  0.5 -0.1
  1.0  1.2
  1.5  2.6
  2.0  3.9
  2.5  4.9
  3.0  5.0

C++ 版、Ruby 版、Fortran 版と同じ結果になるはず。


「昔取った杵柄」で Java でも実装してみた次第です。

以上。





 

Sponsored Link

 

Comments