2009年2月1日

リファクタリング-2-

リファクタリングとして数多くのことをする必要があるが、とりあえず最初にやるべきことは、Math::NumberCruncher のコードから、今回必要なルーチンをコピーして持ってくることだろう。Correlation()関数を呼び出す回数は O(n2) になるが、Wikipediaの「相関係数」のページによると相関係数を求める式はこのようになっている:

分母が特に「列」単位で独立して計算できる事がわかる。列単位ならば計算はO(n)で済む。このような最適化がかけられるかどうか、調べるには元のソースが無くてはいけない。
幸い、CPANには perl のソースが .pm ファイルとしてついてくる。それをコピーしてみたが、全部 perl で書かれているようだ。これならば最適かもかけられよう。

次に、x と y のラベル名を読み込むコードを変更する。旧来:
our $i = 0;
our @x_tagname = ();
while (<COMPARE_X>) {
$_ =~ s/^\"//;
$_ =~ s/\"\n$//;
$x_tagname[$i] = $1;
$i++;
}
close COMPARE_X;
となっていたのだが、

  1. push()関数を使えばインデックスの $i は不要になる。

  2. ラベル名に " がついたままでもいいじゃないか。どうせ x, y だけでなくデータのラベルも " がついたままなのだから。文字列比較の際に " がついたまま比較すればいい

と考えるた。結果、このように簡単になる:
our @x_tagname = ();
while (<COMPARE_X>) {
$_ =~ s/^\s*(".*")\s*$/\1/;
push @x_tagname, ( $_ );
}
close COMPARE_X;
同じ変更は COMPARE_Y を読み込む部分についても行う。DATAFILEの最初の1行目を読んだ部分に関してはもっと極端だ。
# Read first line of .
# This should be the list of TAG-NAME.
$line = <DATAFILE>;
@tagname = split /\t/, $line;
for ( $i = 0; $i < scalar( @tagname ); $i++ ) {
my $val;
$val = $tagname[$i];
$val =~ s/^\s*"//;
$val =~ s/"\s*$//;
$tagname[$i] = $val;
}
というこれは
$line  = <DATAFILE>;
@tagname = split /\t/, $line;
for ( my $i = 0; $i < scalar( @tagname ); $i++ ) {
$tagname[$i] =~ s/^\s*(".*")\s*$/\1/g;
}
とできる。

次に。今回のリファクタリングで、BestFit() を呼び出し、回帰直線の傾きと切片を求めるのをやめる。この計算も結構な高コストである上に、相関係数を求めた結果として、重要と思われたものについてのみ必要な数値だからだ。これらは、計算すべきターゲットが見つかってから計算するのでも間に合う。