見通しの良いファイル構成 ~ パッケージ、使ってますか？ ~

# はじめに

このポストでは、matlabコーディングにおいて利用可能な「パッケージ」について軽く紹介します。みなさん制御とか最適化とかの話題を書いていて恐縮なのですが、コードの書き方について参考になると幸いです。

僭越ながら[Matlab Advent Calendar 2019](https://qiita.com/advent-calendar/2019/matlab)の13日目です。@k_hashikoさんの[MATLABのGlobal Optimization Toolboxの使い方（GA実践編）](https://qiita.com/k_hashiko/items/c1506fc00e1ab852755d)に続く投稿となります。

## なぜ書くのか

Matlabの利点のひとつに、数理手法がサクサク書ける点があります。
一方で、Mathworks社謹製のtoolboxesなら良いですが研究者の書くスクリプトやオレオレライブラリはコードが汚くなりがちです。

管理できないソースコードを書いても、誰にも引き継がれずお蔵入り・・・となること間違えなしなので、管理しやすい(**第三者が後日ライブラリを見ても十分扱える**&**必要に応じて改善できる**)状況にしておくのは、研究成果を実応用していくという観点では重要であると思います。

マジックナンバーだらけのコードや、何を指しているか全然分からない変数の命名など(`Ond`が実は「温度」を指している等)、悲劇が起きてしまいます(起きてしまいました)。
今日あなたが気をつければ後日誰かが助かるかもしれないので、きれいなライブラリを作っていきましょう。

なお命名規則は以前訳したものなどがあるのでこちらをご参考になさってください。

- [[#matlab] Matlabのベスト・プラクティス - Qiita](https://qiita.com/sshojiro/items/bd2ce703e605ffc9451e)
- [『MATLAB対応 ディジタル信号処理』のサポートページ - PDF](http://www.mk.ecei.tohoku.ac.jp/dsptext/MatlabStyle2book_Japanese.pdf)
- [MATLAB Style Guidelines 2.0 - File Exchange](https://jp.mathworks.com/matlabcentral/fileexchange/46056-matlab-style-guidelines-2-0) 原著。

## パッケージって何？

Matlabのパッケージは、どこに何があるのかわかりやすくする仕組みです。
[パッケージによる名前空間の作成](https://jp.mathworks.com/help/matlab/matlab_oop/scoping-classes-with-packages.html) 
`+package_name/functionName.m`などというふうに、フォルダの頭に`+`マークを付けることで、matlabコンソール上で`package_name.functionName()`といった形で呼び出すことができます。

## 何が嬉しいの？？ - 名前空間が作れる

物理的な階層を指定することが出来て、関数ファイルがどこにいるのか常に自明となります。(なお、コンソールで`which FUNCTION_NAME`と打ち込めば関数ファイルの場所はわかります)

スクリプトに以下のように書いてあるとき、確実に関数の出どころが分かります。

```matlab:sample.m
mml.metrics.r2score(Y, Ypred)
```

明らかに、`+mml/+metrics/r2score.m`なんだなとすぐ分かります。そうすると、プログラムを書いている段階で、`mml.metrics`というパッケージに何やら`r2score`と似た目的で使用する関数があるんだな・・・といった類推が可能になります。

これは、後からスクリプトを読む人にとって非常に分かりやすくなります。（どこに何のファイルがあるのか分からないとイライラしてしまいますよね。いちいち`which`コマンド使うのものなあ・・・みたいな）

## 何が嬉しいの？？その２ - 同じ役割の関数に同じ名前がつく

これはクラスでも代替できる性質ですが、同じ役割の名前に同じ名前が付きます。

例えば、3層のニューラルネットワークとカーネルPLSを自作したとしましょう。どちらも
1. モデル学習(model fit)
2. モデルを使った予測(predict)
を行います。これを、名前空間が切れないと
- `neuralnetwork_modelfit.m`, `neuralnetwork_predict.m`
- `kernelpls_modelfit.m`, `kernelpls_predict.m`
という、長い名前の関数名になってしまいます。正しいといえば正しいのですが、これがスクリプト上に書いてあると

```matlab:modelFitting.m
function modelFitting
% モデルを学習する
...
model = neuralnetwork_modelfit(X, y);
ypred = neuralnetwork_predict(model, X);
...
```

こんな感じになってしまうことでしょう。長くて文字を打つ方も疲れてしまいます。
これを、パッケージを使うと以下のように作れます。

```bash 
$ ls -lt ./{+neuralnetwork,+kernelpls}
+neuralnetwork:
total 2
-rw-r--r-- 1 nyoron 197121 259 2月  27  2019 modelfit.m
-rw-r--r-- 1 nyoron 197121 865 2月  20  2019 predict.m

+kernelpls:
total 2
-rw-r--r-- 1 nyoron 197121 228 2月   2  2019 modelfit.m
-rw-r--r-- 1 nyoron 197121 151 2月   2  2019 predict.m
```

少し見通しが良くなりました。スクリプトで呼ぶときは以下のようにします。

```matlab:callPackages.m
...
model = kernelpls.modelfit(X, y);
ypred = kernelpls.predict(model, X);
...
% あるいは
import kernelpls.*; % +kernelpls/ 以下の全ての関数をロード
model = modelfit(X, y);
ypred = predict(model, X);
```

`import`を使うと末尾の関数だけ指定して呼び出せます。ちょっと便利ですね :)

## パッケージを使ったライブラリの例

ちょっと、これ以上例を上げていく時間的余裕がないのでここらで御暇します。代わりと言ってはなんですが、自作しているライブラリを上げておきます(上の方)。Pythonのscikit-learnのmatlabミラーを作っています。

下の同様のライブラリと比べて、パッケージを使う分上の方が利用しやすい・よりscikit-learnの使用感に近いものとなっています(本当に手前味噌)。

|内容|リンク|
|:---|:---|
|パッケージ有りのscikit-learnミラー|[MatlabMachineLearning - github](https://github.com/MatlabML/MatlabMachineLearning) |
|パッケージ無しのscikit-learnミラー|[sklearn-matlab - github](https://github.com/steven2358/sklearn-matlab) |


## その他の参考ポスト

以下の記事もご参考までに。

|内容|リンク|
|:---|:---|
|Matlabのクラス| 1. [Objective-Oriented Matlab](https://qiita.com/sshojiro/items/6e837d3bfef493ea11b0)<br />2. [Matlabのオブジェクトの値渡し](https://qiita.com/sshojiro/items/eb9c19e5060f52a615b1)|
|Matlabの解析フォルダの構成|[解析のためのフォルダ構成](https://qiita.com/sshojiro/items/2f2720ba7697e8758855)|



## 終わりに

ということで、パッケージの使い方を見てきました。情報量ゼロかもしれませんが、参考にしてもらえると幸いです...！