mk-mode BLOG

このブログは自作の自宅サーバに構築した Debian GNU/Linux で運用しています。
PC・サーバ構築等の話題を中心に公開しております。(クローンサイト: GitHub Pages

ブログ開設日2009-01-05
サーバ連続稼働時間
Reading...
Page View 合計
Reading...
今日
Reading...
昨日
Reading...

Ruby - 最小二乗法!

[ プログラミング, 数学 ] [ Ruby ]

こんばんは。

前回は、C++ による「最小二乗法」のアルゴリズムを紹介しました。

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

以下、Ruby によるサンプルスクリプトです。

0. 前提条件

  • Linux Mint 13 Maya (64bit) での作業を想定。
  • Ruby 2.1.0-p0 を使用。
  • 最小二乗法についての説明は割愛。(「C++ - 最小二乗法!」を参照)

1. Ruby スクリプト作成

今回作成した Ruby ソースは以下の通りです。

least_squares_method.rb
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
# ***************************************
# 最小二乗法
# ***************************************

# 計算クラス
class Calc
  # 定数
  N, M = 7, 5                    # データ数, 予測曲線の次数
  X = [-3, -2, -1,  0, 1, 2, 3]  # 測定データ x
  Y = [ 5, -2, -3, -1, 1, 4, 5]  # 測定データ y

  def initialize
    # a, s, t データ
    @a = Array.new(M + 1).map{Array.new(M + 2, 0.0)}
    @s = Array.new(2 * M + 1, 0.0)
    @t = Array.new(M + 1, 0.0)
  end

  # 最小二乗法
  def calc_least_squares_method
    # s, t 計算
    calc_st

    # a に s, t 代入
    ins_st

    # 掃き出し
    sweap_out

    # y 値計算&結果出力
    display
  end

  private

  # s, t 計算
  def calc_st
    0.upto(N - 1) do |i|
      0.upto(2 * M) { |j| @s[j] += (X[i] ** j) }
      0.upto(M) { |j| @t[j] += (X[i] ** j) * Y[i] }
    end
  end

  # a に s, t 代入
  def ins_st
    0.upto(M) do |i|
      0.upto(M) { |j| @a[i][j] = @s[i + j] }
      @a[i][M + 1] = @t[i]
    end
  end

  # 掃き出し
  def sweap_out
    0.upto(M) do |k|
      p = @a[k][k]
      k.upto(M + 1) { |j| @a[k][j] /= p }
      0.upto(M) do |i|
        unless i == k
          d = @a[i][k]
          k.upto(M + 1) { |j| @a[i][j] -= d * @a[k][j] }
        end
      end
    end
  end

  # y 値計算&結果出力
  def display
    0.upto(M) { |k| printf("a%d = %10.6f\n", k, @a[k][M + 1]) }
    puts "    x    y"
    -3.step(3, 0.5) do |px|
      p = 0
      0.upto(M) { |k| p += @a[k][M + 1] * (px ** k) }
      printf("%5.1f%5.1f\n", px, p)
    end
  end
end

# インスタンス化&実行
Calc.new.calc_least_squares_method

2. 実行

実際に、実行してみる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ ruby least_squares_method.rb
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++ 版と同じ結果になるはず。


色々と数値や次数を変えてみるのもよいでしょう。

以上。

Comments