人気ブログランキング | 話題のタグを見る

車輪を二度発明しないためには

「車輪を二度発明してはいけない」とよく言われる。

動作のテストが済んだプログラムが既にある場合はそちらを利用したほうが効率がいいはずだからだ。しかし、それはそのプログラムを使用できるようになるためのコストを除外しているような気がする。ちょっとした用途に使うのに分厚いマニュアルを読まないといけなくなるようでは、費用対効果がいいとはいえないのではないだろうか。

また、自分が作ったプログラムもしばらくすると使い方すら忘れてしまう。そういえば利用できそうなプログラムを以前作っていたなと思いだしても、使い方すら忘れているので、結局ソースを読み直すことになる。スニペットのような短いものなら、それも簡単だが、長いものだとうんざりするし、ロジックを読み取ることすら困難な場合もある。

単機能のスニペットをたくさん作っておくというのはいいアイディアだ。しかし、あるスニペットと別のスニペットのデータ構造が違うため、このふたつを単につなぎ合わせても動かないことがある。二つを一つのプログラムに統合すればよいかもしれないが、思いもかけないデバッグの作業が発生し、泥沼に陥ることも多い。

便利なスクリプトを作ったのに案外使わないのは、再利用の手間が馬鹿にならないからだ。

これらの問題を解決する方法として考えてみたのが、対話的にRubyを実行できる環境で、必要になったらそのつどスニペットを呼び出しながら使っていくというやり方だ。データ構造の整合性がない場合は、そのつどデータ変換の小さなプログラムを作りながら既存のスニペットを利用するのだ。

このブログで掲載した、edb.rb を使ってその辺の事情を実験してみた。

edb.rb はテキストベースのフラットファイルのデータを並べ変えたり、検索したりするために作ったプログラムだ。また、stat.rb は一次元配列のデータの統計処理をするためのスニペットだ。

もくろみは、データ構造の違う edb.rb と stat.rb をつなげて、テストの成績の統計的な分析をしてみようというものだ。この際、edb.rb と stat.rb の変更はせず、コマンドプロンプト上でデータの変換を行って、両者の機能をつなげてしまいたい。

実行例は次のようになる。

まずフラットファイルデータベースの edb.rb を立ち上げる。下の例では、生徒の数学、国語、英語のデータ表を読み込んで、数学の成績順に並べ替えている。

C:\Users\********\Ruby>ruby edb.rb
easydb> seiseki = Edb.new('seiseki.txt')
easydb> seiseki.dump
name sugaku kokugo eigo
A 90 65 55
B 46 50 50
C 63 63 58
D 50 40 48
E 55 32 40
easydb> seiseki.sort(:sugaku).reverse.dump
name sugaku kokugo eigo
A 90 65 55
C 63 63 58
E 55 32 40
D 50 40 48
B 46 50 50

今度は各教科のデータを、配列の統計処理のスニペット stat.rb で処理したいのだが、次の例のように、edb 備え付けの表から配列をとりだすメソッド to_array ではデータが列方向の2次元配列になってしまう。sugaku の点数を取り出してみると、縦方向の二次元配列になっているのがわかる。

easydb> p sugaku = seiseki.to_array('sugaku')
[[90], [46], [63], [50], [55]]

一方、stat.rb が処理するのは一次元配列なので、縦方向の配列を横方向に変換することが必要になってくる。必要なものは作ればいいので、mk_c2r 変数に edb.rb の edit コマンドでプログラムを作成する。

easydb> mk_c2r = edit

mk_c2r プログラムは下のようになる。

easydb> puts mk_c2r
class Array
  def c2r
   &bsp;self.collect{|x| x[0]}
  end
end

このプログラムを eval で実行すると、Array クラスに対し、縦方向の配列を横方向の配列に変換するメソッドを追加することができる。

easydb> eval mk_c2r

このメソッドを先ほど作った sugaku 配列に適用してみるとうまくいっているのが分かる。

easydb> p sugaku = sugaku.c2r
[90, 46, 63, 50, 55]

そこで、国語や英語の点数も一次元配列にして取り出すことにする。

easydb> kokugo = seiseki.to_array('kokugo').c2r
easydb> eigo = seiseki.to_array('eigo').c2r

準備ができたのでいよいよ、stat.rb を require して統計処理を行う。

easydb> load 'stat.rb'

まず、各教科の生徒数、得点の合計、平均、標準偏差を計算する。

easydb> p sugaku.stat
[5, 304, 60.8, 17.5128524232919]
easydb> p kokugo.stat
[5, 250, 50.0, 14.3003496460751]
easydb> p eigo.stat
[5, 251, 50.2, 6.94262198308391]

次に各教科の間の相関係数をとってみる。

easydb> p sugaku.cor(kokugo)
0.517884396596487
easydb> p sugaku.cor(eigo)
0.25276578505604
easydb> p kokugo.cor(eigo)
0.953858389080128

これを見ると、数学と英語の点数の相関が低く、英語と国語の得点の相関が高いことがわかる。

ここで、まにあわせで作った c2r メソッドは、いろいろな場合に使えそうなので、ファイルにして保存しておくことにする。

easydb> save('c2r.rb', mk_c2r)

この例の場合は、Rubyを対話的に使う環境として、このブログの edb.rb を使ったが、もちろん irb や、このブログの minirb も使うことができる。

もっといいやり方はもちろんあるだろうが、Ruby を対話的に使える環境で、使いたいデータやスニペットを呼び出しながら、ミニプログラムで繋げていくというやり方は、車輪を二度発明しないようにするためには便利な方法ではないかと思う。
by tnomura9 | 2008-09-23 09:31 | Ruby | Comments(0)
<< スニペット活用環境 srb 統計計算スニペット >>