概要
MATLABでは関数の複数出力をインラインで取り出す方法がありません。
複数出力を取り出す際は1行使って次のように書くのが通例です。
>> [A, B] = func(x)
しかし、この方法だとarrayfun
やcellfun
とすこぶる
相性が悪いです。cellfun
を利用することを考えましょう。
cell
に格納した変数(データ)を端から関数func
に渡します。
>> cellfun(@func, data)
しかし、cellfun
はfunc
の第1出力しか取れません。
非常に厄介です。{func(data{1})}
で全ての出力を取れると良いのですが、そんなことはできません。
そこで、第N出力だけを取り出すwrapperが必要となります。
以下に実装を書いていきます。
実装
最初すごい適当に書いたものが1つ目の実装です。
第1出力も念の為取り出すことができます。しかしパッと見分かりづらいです。
function out = outN(fun, N, varargin)
assert(N>=1, "indicate 1st~ output");
eval(['[' repmat('~,', 1, N-1) 'out] = fun(varargin{:});']);
end
2つ目の実装は、少し読みやすい風に作ってありますが1つ目と同じです。
また、cell
の初期値設定などが使用してあり少し教育的ですね。
function out = outN(fun, N, varargin)
assert(N>=2,"indicate after 1st output");
omit = cell(1, N-1);
omit(:) = {'~'};
ignore = join(omit, ',');
eval(['[' ignore{1} ',out] = fun(varargin{:});']);
end
実際にコンソールで実行してみたのが次の例です。
ismember
メソッドの第2出力が取れていることが分かります。
>> [A,B]=ismember(1,[0,1,2,3,4,5])
A =
logical
1
B =
2
>> outN(@ismember,2,1,[0,1,2,3,4,5]) % get the second output
ans =
2
私自身が実現したかったのは予測モデルをcell
に保存しておいて、モデルをデータXtest
に適用するという点でした。
すなわち、models{1}.predict(Xtest)
, ..., models{end}.predict(Xtest)
を一括適用したかったのです。必要なのは第2出力でした。
上記のいづれかのoutN
を使うと、任意の出力を取り出せます。組み合わせると次のように書けます。
>> cellfun(@(m)outN(@m.predict, 2, Xtest), models)
% models{1}.predict(Xtest)の第2出力だけを取り出す
もしoutN
が使えなければ次のようなコードを書いていたことでしょう。
複数行使わなくてはいけませんし、見通しが悪く、不要な変数も増えます。
これは避けたいところでした。
outputs = cell(1, length(models));
for iModel = 1 : length(models)
[~, out] = models{iModel}.predict(Xtest);
outputs{iModel} = out;
end
まとめ
任意の出力を取り出すためのwrapper関数を調べ作りました。
複数行書く必要があったところをcellfun
と組み合わせ1行で書くことができました。
MATLABのFile Exchangeにも公開しているのでご利用ください。
outN - File Exchange