LoginSignup
98
95

More than 5 years have passed since last update.

[#matlab] Matlabのベスト・プラクティス

Last updated at Posted at 2016-11-10

はじめに

Matlabの記述方法、何が良いのかなとふと不安になったので、次のドキュメントを訳して見ようかなと思います。
Matlab Style Guideline 2.0

書き方

1. camelCaseで書こう

matlabでは基本的に、変数も関数名もcamelCaseで書きます。
matlab使いは、数式を投影したものをコードに書きがちですが、意味を持った変数で実装する際には意味のわかる変数名にしましょう。

recommend not recommend
wage = hourlyRate * nHours z = x * y

2. 単数・複数の違いは、明示的に

英語だとword, wordsなどとしがちですが、ミスを誘発するので、明示的に変えましょう。

recommended
point, pointArray, pointList

3. 単一の数字を指すときはsuffixまたはprefixをつける

tableNo, employeeNoのように、Numberの略称を単語の後につけるか、
次のfor loopのようにprefixを単語の前につけると良いです。

for iFile = 1 : nFile
   files(iFile) = ..
end

iFileでiteratorを、nFileでファイルの数(number of file)を指します。

4. 論理型変数は肯定形が良い

論理型は、主語を抜かした形で書くことが多く、matlabにもisstructといった関数が標準実装されています。

is*形式で書くと、if文と合わせたときに

if isstruct(Struct1)
  ...
end

と書けるので可読性が上がります。その際、否定を含めた変数名定義はやめましょう。

recommend not recommend
isFound and ~isFound ~isNotFound

5. 略語(abbreviation)もcamelCaseで

camelCaseの慣習を崩すので、手法の略称を大文字で続けるのは避けましょう、とあります。(ホントかなぁ?)

recommend not recommend
html, isUsaSpecific, checTiffFormat() hTML, isUSASpecific, checkTIFFFormat()

機械学習の分野でいえば、Pls, Pcaとかってなります...

6. 予約語とかぶらないように

当然ですが、matlabの予約語とかぶると後々バグの温床となるのでやめましょう。

not_recommended_words
alpha, angle, axes, axis, balance, beta, ...

7. Hungarian notationは避けよう

recommend not recommend
thetaDegrees uint8thetaDegrees

8. 定数は大文字で

他の言語でもやる方法ですが、定数は大文字で定義します。あと、短ければ良いというものでもなく、具体的に書きましょう

recommend not recommend
MAX_ITERATIONS TEN, MAXIT

複数並べる際には、より一般的な単語が上位に来るように命名します。

COLOR_RED   = 'r';
COLOR_GREEN = 'g';
COLOR_BLUE  = 'b';% color specs
% 構造体も良いかと.
COLOR.RED   = 'r';
COLOR.GREEN = 'g';
COLOR.BLUE  = 'b';% color specs

9. 関数により毎回定数を返す場合は、全部小文字かcamelCaseで書く

matlabでたまに実装されていますが、関数として固定の出力をする場合には大文字以外で命名しましょう。
例: pi

10. 構造体は大文字始まり

多分C++とかの思想だと思いますが、構造体は大文字始まりです...
あと、field名に構造体名を含まないようにしましょう。

recommend not recommend
Segment.length Segment.segmentLength

11. 関数名は小文字か、camelCase

先程も書きましたが、全て小文字か、camelCaseで定義します。rubyやpythonのようなsnake_caseは推奨されてないです。多分、ベースがjavaだからではないでしょうか。

名前が長くなるときはcamelCaseが良いでしょう。

12. 意味のある関数名にしよう

意味わかんない関数名をつけると、保守性が下がりますので、やめましょう。

recommend not recommend
computeTotalWidth compwid

13. アウトプットが1つの関数は、そのアウトプットの名前を関数名としてください

computeRmseなんてクドい関数名は、やめようということですね...

例: mean, standardError

14. 関数は基本的には動詞で始めます

i. get/setはgetter/setterがあるので注意

クラスやオブジェクトを使える人はご存知かと思いますが、matlabもsetter, getterが予約語として存在します。安易にgetNumberとせずに、getObj, setPropertyなど、オブジェクトやプロパティへのアクセスのみに利用してください。

ii. 計算する関数は, computeなどで統一

統一したほうが可読性が上がるので、calcRmseなどと適当につけずに全てcomputeRmse, computeResponsibilityなどと統一しましょう。

iii. indexを返す関数の際にはfindがよいです

rubyのactive recordでも、条件を満たすデータを探す際にClassName.find(:id)などと検索をします。それにならって、findとしましょう。getを使わずに済みますね。
例: findOldestRecord, findTallestMan

15. その他関数の名前の注意

i. initじゃなくてinitializeにしよう

動詞で明示的に書いたほうが可読性が上がります。アメリカ英語のinitializeの方が、イギリス英語のinitialiseよりも良いです。
例: initializeProblemState

ii. 論理型を返す関数はisで始める

例: isOverpriced, iscomplete

iii. is以外にも、yes/noで答えられそうな名前にしよう

例: hasLicense, canEvaluate, shouldSort

16. スクリプト冒頭で変数・インスタンスを呼びましょう

コメントもつけると親切です。他の言語でもこの慣習があって、インプットは一箇所にまとめると可読性が上がります。

example
THRESHOLD = 10; % Maximum noise level found.

17. グローバル定数・変数は極力減らそう

.mファイルで定数・変数を呼ぶと実行速度が落ちます。
.matファイルから定数・変数を読み出すときには定数・変数の更新がしづらくなります。
なので、できるだけグローバル定数・変数は減らしましょう。

18. iteration前に変数は定義しておく

メモリ利用の観点から、先にresult変数を定義すべきです。

result = nan(nnEntries, 1); % define a variable that keep results
for iEntry = 1 : nEntries
  result(iEntry) = foo(iEntry);
end% end for loop of iteration for entries

for loop中のbreak, continueの使用は最小限にとどめ、endの直後に、何が終了したか書きましょう。

19. 条件文は分割して見やすく

if文横にまとめて書こうとせず、論理型変数を定義してスッキリさせましょう。

badCase

if (value>=lowerLimit) & (value<=upperLimit)...
                       & ~ismember(value, valueArray)
...
end

goodCase
isvalid = (value>=lowerLimit) & (value<=upperLimit);
isNew   = ~ismember(value, valueArray);
if (isValid & isNew)
...
end

20. if statement直後には比較的良く起きる場合を、else以降はたまに起きる場合を記述

これも、可読性向上の為。珍しい事象が冒頭に来ると、読み手は少し動揺します。

fid = fopen(fileName);
if (fid ~= -1)
% よく起きる
else
% 珍しい事象
...
end

21. switch文ではotherwiseを極力定義

エラーが生じて落ちるのを防ぐために、otherwise処理を書き足しましょう。

switch-statement
switch (condition)
case ABC
    statement1;
case DEF
    statement2;
otherwise
    statementException;% this part is important to avoid errors
end

ちなみに、変数の内容(文字列とか)で切り替える場合はswitchを、条件文で分岐を書く場合にはif文を使いましょう。

22. 常識的なところ

i. 括弧をつけよう

matlabは括弧を外した表現を許容していますが、括弧は付けましょう

disp('testMessage'); % good
disp testMessage     % avoid

ii. 小数は0を書こう

桁数を読み間違えたりするので、書きましょう。

THRESHOLD = 0.5; % good
THRESHOLD = .5;  % avoid

iii. 比較は分かりやすく

iSample>=maxSamples;  % use
~(iSample<maxSamples) % dead

23. 変数の型チェックはvalidateattributesinputParserを使う

ここではvalidateattributesのみ載せますが、inputParserも使いやすいと思います。特に、関数の入力をチェックするときにはとても便利です。

example
>> s = @(x) x.^2;% function handle
>> validateattributes(s, {'function_handle'}, {'nonempty'});% ok
>> validateattributes([1 2], {'function_handle'}, {'nonempty'}); % raise error
Expected input to be one of these types:

function_handle

Instead its type was double.

25. 見やすいところで「コード上は」改行すること

...をつけると、コード上での改行が可能になります。処理の上では一行とみなされますので、...を駆使することで、読みやすく書き換える事が可能です。

inline
totalSum = a + b + c + ...
           d + e;
function(param1, param2, ...
         param3)
instance.setText(['Long line split'...
         'into two parts']);

個人的には、演算子は改行後に含めたほうが好きです。twitter bootstrapのjavascript部分がこんな感じの実装でした。

inline
totalSum = a + b + c ...
         + d + e;
function(param1, param2 ...
       , param3)
instance.setText(['Long line split'...
         'into two parts']);

26. inline if-statement

if, while, forが1行で書けますよ、というもの。

one-liner
if(condition), statement; end
while(condition), statement; end
for iTest = 1:nTest, statement; end

27. スペース推奨

関数の入力をギュウギュウに書く人がいますが、空白があったほうが読みやすいです。

simpleAverage = (firstTerm + secondTerm) / two; % good
simpleAverage=(firstTerm+secondTerm)/two;       % not good

foo(alpha, beta, gamma)% good
foo(alpha,beta,gamma)  % bad

28. 字下げを揃える

開始箇所を揃えると見やすくなったります。これはもうmatlabとか関係なく、プログラミング言語一般に対していえます。

value = (10 * nDimes) + ...
        (5  * nNickels) + ...
        (1  * nPennies);% 開始箇所を揃えた

29. write comments in English!

matlabが親切にも日本語版を出していて、しかもencodingがShift-JISだったりします。
しかし、英語環境でそれを開くと、日本語で記述された箇所は文字化けします。死にます。なので、コメントは(フォルダ名も)基本的には英語で書きましょう。もう一度言います、死にます。

30. .mファイルは関数化したほうが良い

スクラッチしているときはスクリプト形式で良いのですが、基本的には関数化すると良いです。それは、不要な変数を誤って使い、解析結果が無意味になるのを防ぐ意味があります。

他にも、parallel toolboxを使う際には関数化してある必要があります。

おまけ

matlabをきれいに書くtipsを書きます。ご参考までに。

I. 改行

[]で作れる行列、{}で作れるcellは、セミコロンを打たずに改行すると縦ベクトル/縦セルが作れます。

>> mat = [1
          2
          3]
mat =
     1
     2
     3
>> colorspec = {'-'
                '--'
                '.-'}
colorspec = 
    '-'
    '--'
    '.-'
>> size(mat), size(colorspec)
ans =
     3     1
ans =
     3     1
>> matrixA = [1 2
              3 4
              5 6]% 2x2 matrix
matrixA =
     1     2
     3     4
     5     6

これをうまく取り入れると、ピリオド3つ(...)の
インライン処理を書かずにコード上で開業したことになるので、おすすめです。

一行で定義したセルを作りたい場合は、transposeすると良いです。

>> colorspec = {'-'
                '--'
                '.-'}' % transpose
colorspec = 
    '-'    '--'    '.-'

II. 構造体のforeach

このセクション末のサンプルコードに例を示しながら説明します。
構造体Rmseに対して、fieldnames(Rmse)'で構造体の子要素をセルで取得できます。取得したセルをそのままiteration変数に入れたforループを回すと、子要素名が1x1のセルとしてiteration変数childStructに入ります。

そこで、childStruct{1}とすればセルから子要素名が取得できるのですが、ここで元々の構造体Rmseに対してRmse.(childStruct{1})(すなわち、Rmse.('pls')などとするのと同等)とすると、構造体の子要素にアクセスできます。

>> Rmse.pls = 0; Rmse.svr = 0;% initialize
>> for childStruct = fieldnames(Rmse)'% for loop
    Rmse.(childStruct{1}) = 10;
end
>> Rmse
Rmse = 
    pls: 10
    svr: 10
>> Rmse.('pls') % allow struct.(STRING) access
ans =
    10
>> Rmse.('svr')
ans =
    10

こんな感じです。ご質問・修正すべき点などあれば、コメントいただければと思います。

2019/03/19 追記

2017年に同じ文献を日本語訳したカッチリ版が出てました...
強そう!

98
95
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
98
95