データ分析をなりゆきで進めると起こる問題
データ分析を行う際に、最後まできれいな環境を維持することってなかなか難しくないでしょうか。
分析を進めるとにつれて、見たい部分が増えてくるため、扱いたいパラメータもどんどん増えてしまいます。その結果、たかが引数の定義ですが、変更するだけで大きな労力を割く必要が出てきてしまいます。
分析を進めるうちに、労力が増大していってしまうやり方は極力避けたいところです。このようなカオスな状況にならないように、私なりに考える簡潔で、柔軟な(自由度の高い)関数の定義方法を紹介しようと思います。
MATLABの基本的な関数定義
まずは、一般的な関数の引数の定義から紹介します。
よくある通常の関数は次のようになります。
myfunction1.m
function [out] = myfunction1 (in1, in2)
***
評価したい計算 out = in1 + in2; 等
***
ここで引数を増やすと次のように、in3を加えることになります。
myfunction2.m
function [out] = myfunction2 (in1, in2, in3)
***
評価したい計算 out = in1 + in2 + in3; 等
***
4,5個くらいの引数であれば、このやり方で問題ないと思います。ただ、100個くらいの引数を考えた場合、このやり方で一つ一つ入力することは現実的ではないです。
仮に書ききったとしても、可読性も下がり、意図しないエラーに繋がってしまいそうで、できれば避けたいところです。
以前、MATLABで引数の数が可変の関数を定義するで紹介した、vararginを使う方法もありますが、何番目の引数を取り出すかを確認しながら使う必要があり、数値、文字列、同じ数値でも単位がことなるもの等をまとめて引数に入れようとすると、煩雑になりがちです。
状況に合わせて関数を柔軟に定義していくためにやりたいこと
これまでの話を踏まえると、次の要件を満たす関数が作れたら便利そうですよね。
ー要件ー
- 引数の数:可変(後からいくらでも変えられる)
- 引数の種類:文字列、数値(整数、少数)、スカラー、ベクトル、N次元マトリックス、とにかくなんでもつっこみたい
柔軟な関数を定義するには
どれだけ含まれるかわからない引数は、一つにまとめてしまうと扱いが楽になりそうです。
詳しい方からすると、当たり前だと言われてしまうかもしれませんが、ひとつにまとめる(パッケージングする)という考え方は、扱うプログラムの煩雑性を抑えながら規模を大きくしていく上では非常に重要な考え方です。
沢山あるパラメータを1つにまとめる簡単な方法は構造体(struct)を使うことです。
次に例を示します。
main.m
st.p1 = 3.14; % 数値
st.p2 = [2, 4, 6, 8, 10]; % 数値の配列
st.p3 = "文字列1"; %文字列
st.p4 = ["文字列10", "文字列11", "文字列12"]; %文字配列
st.p5 = [2, 4, 6, 8, 10; 1,3,5,7,9;]; %行列
out = myfunction(st) % 引数はstのみ
myfunction.m
out = myfunction(st_in)
%引数の構造体(st_in)からパラメータを取り出す
p1 = st_in.p1
p2 = st_in.p2
p3 = st_in.p3
p4 = st_in.p4
p5 = st_in.p5
引数を全て構造体とすることのメリット/デメリット
このような定義の仕方は多くのメリットがあります。
○ 見た目がシンプル
myfunctionの引数は、パラメータセットの構造体(st)のみでよくなります。パラメータの数が100くらいに増えても問題ありません。これ以上ないくらいシンプルなため、ここで記述エラーを起こすことはほぼゼロになると思います。
○ 後からいくらでも変更可能
後々st.p6, st.p7を付け加えたとしても、関数の引数定義を変える必要がありません。
プログラム(関数)の大きな構造を維持したまま、パラメータを増やしていけます。
○ 変数名で呼び出すため、引数の順番も考慮不要
更に、引数の名前で呼び出すことができるため、vararginとは異なり、欲しいパラメータは何番目の引数だったっけ?と悩む必要がなくなります。
○ 引数の全体像を簡単に確認可能
stはMATLABの構造体のため、MATLABのツールで開けば、中の変数名と値がずらっと並べて表示させることができるため、全体像が見えやすいことも特徴的です。
△ 抽象度が高くなり、所見で伝わり辛い
引数がstのみだと、これが何を表すのかパット見では検討がつかなくなります。
他の方とコードを共有する際には、どのような意味のデータを引数として持っているのかを、別の場所に明記する必要がでてくるかもしれません。
まとめ
関数の引数が多く煩雑な場合は、全て構造体に入れてから引数とすることで、表記も簡略化しつつ、柔軟性を上げることができるという内容でした。
真面目にデータ分析を繰り返し行っていくような状況においては、私は非常に便利でかつ簡単に実装できる方法ではないかと考えています。これからMATLAB使う方、今MATLABを使っていて、パラメータの数が膨大で扱いに困っている方ぜひ一度試してみてください。
更に真面目に柔軟な関数を定義していくには
MATLABで大きなシステムを組むことは、そこまで想定していないことが多い気もします。
このため、今回のように関数レベルで、簡単かつ簡潔にデータ分析していける方が、メリットが多いかもしれません。
とはいえ、更にclass定義まで踏み込むことで、自分の用途に合った環境を作っていくことができると思います。
こちらはまた別の機会にまとめられたらと思います。