【MATLAB】配列内のユニークな要素、それぞれの数を数える方法


使用環境

MATLAB R2017a

課題

例えば

v = [1,2,3,4,2,2,1];

という配列があった時に、1が2つ、2が3つ、、というように数え上げるとします。

意外と分かりやすい名前の関数がなく、泣く泣くforループでプログラムを組んでいました。こんな感じ。

v = [1,2,3,4,2,2,1];
vq = unique(v);
N = length(vq);

numvq = zeros(N,1);
tic
for ii=1:N
    numvq(ii) = sum(v==ii);
end
toc

やりたいことは実現できているんですが、配列数が巨大になると時間がかかるし、なにより美しくない
そこで、forループを使わずに実現できないかと調べた3つの方法を紹介します。

それぞれの方法で計算にかかった時間の目安として、手元のlaptopで tic/toc を使用して計測した時間を書いておきます。

関数名 処理時間
arrayfun 0.16 秒
accumarray 0.0013 秒
histcounts 0.0016 秒

for ループ 使用した場合は 0.18 秒程度でした。accumarray 関数いいですね。

実行時間計測のために、1から1000までの整数をランダムに持つ 10万 x 1 のベクトル v を作って、それぞれの整数が何回現れるかを求めてみました。

以下それぞれのコードです。

arrayfun 関数

N = 1e5;
v = randi(1000,N,1);
numvq = arrayfun(@(x) sum(v == x), unique(v));

これは for ループは避けられましたが、速度はいまいち。

accumarray 関数

N = 1e5;
v = randi(1000,N,1);
numvq = accumarray(v,1);

関数の挙動を理解するのに時間がかかりましたが、計算速度はこれが最も速かった。

histcounts 関数

N = 1e5;
v = randi(1000,N,1);
numvq = histcounts(v,'BinMethod','integers');

histcounts 関数は R2014b で導入された比較的新しい関数ですが、このオプションは意識したことありませんでした。

参考

Q&AサイトMATLAB Answersより
- how can I count the number of elements on a vector?
- Can I use UNIQUE to get a count of the number of times each element is repeated?
- How can I count the number of elements of a given value in a matrix?
を参照しました。