【MATLAB】ループ処理を高速化するスクリプトの書き方

MATLABスクリプトのループ処理は工夫しないと処理速度が使用に耐えられないレベルで遅くなってしまいます。

ループ数が少なければ問題ありませんが、膨大な数のループになると露骨に影響が出てきます。

サンプルとして0から1までランダムな数値が 1000000 個入った配列の中から0.5より大きな数値だけ抜き出すという処理が完了するまでの時間を確認してみます。

処理1

まずは特に何も考えず以下のような処理でやってみます。

dataArray = rand(1000000, 1);
for icnt = 1 : length(dataArray)
    if  dataArray(icnt) > 0.1
        ret1(cnt, 1) = dataArray(icnt, 1);
        cnt = cnt + 1;
    end
end

c言語等であれば配列を格納する変数の要素数を事前に定義する必要がありますが、MATLABは配列数を勝手に拡張してくれるのでこのように書いても良い感じにやってくれます。

ただし、この処理をMATLABのエディタに記載すると赤波線が表示されました。そこにマウスカーソルを当てると・・・

ret1のサイズがループ中に大きくなっていくからその度にメモリ割り当て起こって遅くなるよという旨の警告が記載されているようです。

一旦警告を無視してこの処理を実行してみます。処理時間計測の関数ticを使用して処理時間を計ってみたところ、以下のようになりました。

実行はできましたが、MATLABから直々に 処理が 遅くなるよ怒られてしまう処理なので改善の仕様がありそうです。

処理2

処理1のネックはループのたびに配列の要素数が大きくなっていくためその度にメモリ割り当てを行ってしまうというものでした。

そこでループ処理の前にメモリを事前に割り当ててしまうことを考えます。

dataArray = rand(1000000, 1);
retTmp = zeros(length(dataArray), 1);
cnt = 0;
for icnt = 1 : length(dataArray)
    if  dataArray(icnt) > 0.5
        retTmp(icnt, 1) = dataArray(icnt, 1);
        cnt = cnt + 1;
    end
end
ret2 = zeros(cnt, 1);
for icnt = 1 : cnt
    ret2(icnt, 1) = retTmp(icnt, 1);
end

ランダム数値が入った配列の中にどれだけ条件を満たす値が含まれているか分からないので、一旦ランダム数値が入っている配列と同じサイズの配列をzeros関数で準備します。

zeros関数は中身が全て0の配列を作成する関数です 。好きなサイズを指定できるので事前に配列を割り当てる際によく使用します。

その後は処理1と同じようにループ処理を行います。ループが終了した時点で条件を満たす値が配列中にどれだけあったか確定します。

仮に格納した配列retTmpですが、最初のほう(1からcnt番目まで)には条件を満たす値が入っていますが、後半部分(cnt番目から1000000番目まで)には余分な0が詰められている状態です。そこで改めてループを行い、必要な要素だけを抜き出します。

このようなループの仕方はC言語等でよく見かける処理ではないでしょうか?

さて、この処理を実行してみます。処理時間計測の関数ticを使用して処理時間を計ってみたところ、以下のようになりました。

処理1に比べ高速に処理されました。逆に言えばメモリの再割り当ては非常に重い処理であるということです。

ループ処理を考える場合には可能な限り事前メモリ割り当てを行う必要があります。

処理3

今まではループ処理で条件を満たす値を取得しましたが、実はループ処理しなくても同じことができてしまいます。ここがMATLABスクリプト、というよりMATLABの特徴的な部分だと思います。

具体的には以下のような記載です。

retTmp = dataArray > 0.5;
ret3 = dataArray(retTmp);

c言語等では見慣れない書き方ですが、とりあえず実行してみます。

処理2よりも処理速度が早くなっています。さらにコードもわずか2行で非常にスッキリしました。

更に、中間変数を使用しなければ1行でも記載できます。

ret3 = dataArray(dataArray > 0.5);

これは、MATLABの配列に関する以下の性質を利用しています。

  • 配列と数値(スカラ)の比較を行うと配列内に格納されている値と数値を比較した結果が配列と同じサイズのbooleanの配列として返ってくる
  • 配列要素の指定に配列と同じサイズのboolean配列を指定するとtrueの要素だけ抜き出す

このようにMATLABの配列を使用した処理には独特な仕様があります。

初めのうちは慣れないかもしれませんが、使いこなせば処理速度の向上が見込めますし、ソースコードを複数行書くという手間も省けますのぜ是非試してみてください。

コメント

タイトルとURLをコピーしました