プログラミング初心者の失敗談

(著)ざっきぃ

こんにちは。普段は芸術系のエッセイを書いているのですが、先日ドライの研究(脳波解析)をしていて思うところがあったので、備忘録的に書いておきたいと思います。僕はプログラミング経験者ではありませんので、初心者目線の内容になります。気軽にお読みください。

脳波の基本的な解析に「周波数解析」があります。これは、脳波データをフーリエ変換して、どの帯域の波が(α、βなど)どの時間帯に出ているのか調べるものです。

いま、15秒間の脳波データxがあります。1秒あたり1000ポイントのデータがあるので、合計15000ポイント。ここで、1Pt目~1000Pt目のデータをフーリエ変換し、出てきた複素数の絶対値を求めます。同じことを、2Pt目~1001Pt目、3Pt目~1002Pt目…、14001Pt目~15000Pt目について行います。すると、1000個のデータが14001組出てくるはずなので、これを14001*1000行列に格納します。

これをするのに、僕はMATLABでこのようなプログラムを書きました(かなり単純化しています)。MATLABというソフトはマイナーですが、雰囲気でわかると思います。

for k=1 : 14001
 y = fft(x);     %フーリエ変換
 s = abs(y);     %絶対値
 freq(k,:) = s; %freqという行列に格納
end

ところが、実際は脳波データxは、一人当たり18個あります。すなわち一人の脳波を解析するのに、14001回のフーリエ変換を18セットやらなければいけない。これには30分ほどかかります。これを数十人やるとなると、数日がかりです。にしても、あまりに時間がもったいない。まあ仕方ないので、時間をかけてこの解析を終わらせたのですが・・・

その後偶然ネット上で、プログラミングの時間短縮方法を見付けました。その方法に従ってみると、なんと、今まで30分かかっていた計算が、

1分30秒で終わったのです。

え、嘘やろ、と思って計算結果を比べてみると、前のと一致しています。今までかけた時間は何だったんだと、このときはかなりショックを受けました。

実は、その時間短縮方法とは非常に簡単なもので、前に一行付け加えるだけなのです。

freq = zeros(14001,1000)    %freqは14001*1000の零行列である

おわかりでしょうか。最初のプログラムでは、freqという行列の次元が、for文の度に変わっていて、それが非効率のもとだったらしいのです。行列の「連結」にパワーを使うのでしょうか。一方、行列の次元を最初に定義しておくと、その中の値をゼロから何かに変えるのには、そこまでの手間がいりません。

後で、このHPの管理人である友人に聞いてみると、前者を「動的なメモリ確保」、後者を「静的なメモリ確保」と言うそうです。実は演算よりも時間を食うのがメモリアクセスで、動的な場合だと、一旦全体の配列を削除して再度メモリ領域を確保しているので、無駄な時間を使ってしまうのだとか。

にしても、それだけで時間が20分の1まで減るとは・・・。普段プログラムを書く時には、効率の悪い書き方をしていても、やらせていることが単純なので、それに気付かないだけなのかもしれません。計算量が多くなると、コンマ一秒の違いでも積もり積もって大きなものになっていきます。こんな簡単なプログラムでも、書き方の巧拙が表れるのだなあ、もっと勉強しよう、と思ったのでした。