3

同じサイズのベクトルとセル配列 (文字列の繰り返し) があります。cell 配列はグループを定義します。各グループのベクトルで最小/最大値を見つけたいです。

例えば:

value = randperm(5) %# just an example, non-unique in general
value =
     4     1     2     3     5
group = {'a','b','a','c','b'};
[grnum, grname] = grp2idx(group);

これにはACCUMARRAY関数を使用します。

grvalue = accumarray(grnum,value,[],@max);

grnameしたがって、一意のグループ名 ( ) と新しいベクトル ( )を持つ新しいセル配列がありgrvalueます。

grname = 
    'a'
    'b'
    'c'
grvalue =
     4
     5
     3

しかし、新しいベクトルに含まれている古いベクトルから値の位置インデックスを見つける必要もあります。

gridx = 1 5 4

何か案は?accumarray を使用する必要はありませんが、高速なベクトル化ソリューションを探しています。

4

2 に答える 2

1

私が見ることができる最良のベクトル化された答えは次のとおりです。

gridx = arrayfun(@(grix)find((grnum(:)==grix) & (value(:)==grvalue(grix)),1),unique(grnum));

しかし、これを「高速な」ベクトル化されたソリューションとは言えません。 arrayfun本当に便利ですが、一般的にループより速くはありません。


ただし、最速の答えは常にベクトル化されているわけではありません。あなたが書いたようにコードを再実装したが、より大きなデータセットを使用した場合:

nValues = 1000000;
value = floor(rand(nValues,1)*100000);
group = num2cell(char(floor(rand(nValues,1)*4)+'a'));
tic;
[grnum, grname] = grp2idx(group);
grvalue = accumarray(grnum,value,[],@max);
toc;

私のコンピュータは私に0.886秒のtic/toc時間を与えます。(1回限りのpcode生成を避けるために、すべてのtic / tock時間は、ファイルで定義された関数の2回目の実行からのものであることに注意してください。)

「ベクトル化された」(実際にはarrayfun)1行のgridx計算を追加すると、0.975秒のチック/タック時間が発生します。悪くはありませんが、追加の調査によると、ほとんどの時間が通話に費やされていgrp2idxます。

gridxこれを、次のように、計算を含む、ベクトル化されていない単純なループとして再実装すると、次のようになります。

tic
[grnum, grname] = grp2idx(group);
grvalue = -inf*ones(size(grname));
gridx = zeros(size(grname));
for ixValue = 1:length(value)
    tmpGrIdx = grnum(ixValue);
    if value(ixValue) > grvalue(tmpGrIdx)
        grvalue(tmpGrIdx) = value(ixValue);
        gridx(tmpGrIdx) = ixValue;
    end
end
toc

tic / toc時間は約0.847秒で、元のコードよりわずかに高速です。


これをもう少し進めてみると、ほとんどの場合、セルアレイのメモリアクセスで失われているように見えます。例えば:

tic; groupValues = double(cell2mat(group')); toc  %Requires 0.754 seconds
tic; dummy       =       (cell2mat(group')); toc  %Requires 0.718 seconds

最初にグループ名を数値配列として定義すると(たとえば、groupValues上記で定義したとおりに使用します)、同じコードを使用しても、時間が大幅に短縮されます。

groupValues = double(cell2mat(group'));  %I'm assuming this is precomputed
tic
[grnum, grname] = grp2idx(groupValues);
grname = num2cell(char(str2double(grname))); %Recapturing your original names
grvalue = -inf*ones(size(grname));
gridx = zeros(size(grname));
for ixValue = 1:length(value)
    tmpGrIdx = grnum(ixValue);
    if value(ixValue) > grvalue(tmpGrIdx)
        grvalue(tmpGrIdx) = value(ixValue);
        gridx(tmpGrIdx) = ixValue;
    end
end
toc

これにより、0.16秒のチック/トック時間が生成されます。

于 2013-03-15T20:38:36.617 に答える