i = [3 5]
インデックスのリスト、例えば、ベクトルを与えましたv = 1:6
。インデックスが与えられf
たベクトルの論理マップを返す関数が必要です。例:v
i
f(i, length(v)) = [0 0 1 0 1 0]
この関数を数百万回呼び出すので、できるだけ速くしたいと思います。このタスクを実行する組み込み関数はありますか?
i = [3 5]
インデックスのリスト、例えば、ベクトルを与えましたv = 1:6
。インデックスが与えられf
たベクトルの論理マップを返す関数が必要です。例:v
i
f(i, length(v)) = [0 0 1 0 1 0]
この関数を数百万回呼び出すので、できるだけ速くしたいと思います。このタスクを実行する組み込み関数はありますか?
ゲームに遅れていることはわかっていますが、と同じくらいエレガントな、より高速なソリューションを見つけたかったのismember
です。そして確かに、文書化されていないismembc
機能を採用しているものがあります。
ismembc(v, i)
N = 7;
i = [3 5];
%// slayton's solution
tic
for ii = 1:1e5
clear idx;
idx(N) = false;
idx(i) = true;
end
toc
%// H.Muster's solution
tic
for ii = 1:1e5
v = 1:N;
idx = ismember(v, i);
end
toc
%// Jonas' solution
tic
for ii = 1:1e5
idx = sparse(i, 1, true, N, 1);
end
toc
%// ismembc solution
tic
for ii = 1:1e5
v = 1:N;
idx = ismembc(v, i);
end
toc
これが私が得たものです:
Elapsed time is 1.482971 seconds.
Elapsed time is 6.369626 seconds.
Elapsed time is 2.039481 seconds.
Elapsed time is 0.776234 seconds.
驚くべきことに、ismembc
確かに最速です!
編集:
の値が非常に大きい場合N
(つまり、v
が大きい配列の場合)、より高速なソリューションは実際にはslayton(さらに言えばHebeleHododo)です。さまざまな戦略から選択できます。慎重に選んでください:)
H.Musterによる編集:
以下を含むベンチマーク結果があります_ismemberoneoutput
:
Slayton's solution:
Elapsed time is 1.075650 seconds.
ismember:
Elapsed time is 3.163412 seconds.
ismembc:
Elapsed time is 0.390953 seconds.
_ismemberoneoutput:
Elapsed time is 0.477098 seconds.
Index exceeds matrix dimensions.
興味深いことに、エラーが発生したため、Jonasのソリューションは実行されません...
hoogamaphoneによる編集:両方の入力が数値、ソート済み、非スパース、非NaN値である必要があることに注意してください。これは、ソースドキュメントでは簡単に見落とされる可能性のある
詳細です。ismembc
使用できますismember
i = [3 5];
v = 1:6;
ismember(v,i)
戻ります
ans =
0 0 1 0 1 0
おそらくより高速なバージョンについては、試すことができます
builtin('_ismemberoneoutput', v, i)
あなたが指定したような行ベクトルに対してのみこれをテストしたことに注意してください。
論理インデックスのベクトルを作成し、目的の位置を true/false に設定するだけです
idx = false( size( v) );
idx( i ) = true;
これは、次のように関数でラップできます。
function idx = getLogicalIdx(size, i)
idx = false(size);
idx(i) = true;
end
100 万回の操作ごとに同じサイズのインデックス ベクトルが必要な場合は、ベクトルを 1 回割り当ててから、反復ごとに操作します。
idx = false(size(v)); % allocate the vector
while( keepGoing)
idx(i) = true; % set the desired values to true for this iteration
doSomethingWithIndecies(idx);
idx(i) = false; % set indices back to false for next iteration
end
本当にパフォーマンスが必要な場合は、mex 関数を記述してこれを行うことができます。これは、私が書いた非常に基本的なテストされていない関数で、他の方法よりも約 2 倍高速です。
#include <math.h>
#include <matrix.h>
#include <mex.h>
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
double M;
double *in;
M = mxGetScalar(prhs[0]);
in = mxGetPr(prhs[1]);
size_t N = mxGetNumberOfElements(prhs[1]);
plhs[0] = mxCreateLogicalMatrix( M,1 );
mxLogical *out= mxGetLogicals( plhs[0] );
int i, ind;
for (i=0; i<N; i++){
out[ (int)in[i] ] = 1;
}
}
matlab でベクトルを割り当てる方法はいくつかあります。いくつかは他のものよりも高速です。適切な要約については、この文書化されていない Matlab の投稿を参照してください。
さまざまな方法を比較する簡単なベンチマークを次に示します。最後の方法は断然最速ですが、操作ごとに同じサイズの論理インデックス ベクトルを使用する必要があります。
N = 1000;
ITER = 1e5;
i = randi(5000,100,1);
sz = [N, 1];
fprintf('Create using false()\n');
tic;
for j = 1:ITER
clear idx;
idx = false( N, 1 );
idx(i) = true;
end
toc;
fprintf('Create using indexing\n');
tic;
for j = 1:ITER
clear idx;
idx(N) = false;
idx(i) = true;
end
toc;
fprintf('Create once, update as needed\n');
tic;
idx = false(N,1);
for j = 1:ITER
idx(i) = true;
idx(i) = false;
end
toc;
fprintf('Create using ismembc\n');
a = ones(N,1);
tic;
for j = 1:ITER
idx = ismembc(1:N, i);
end
toc;
idx 行列を使用して新しい変数をアドレス指定するだけで、ゼロが埋められます。
idx = [3 5];
a(idx) = true
末尾のゼロも必要でない限り、関数や長さを渡す必要はありません。
@slayton のソリューションが最速だと思います。ただし、ベクトルが大きい場合、少なくともメモリを節約できるワンライナーの代替手段があります。
vecLen = 6;
logicalIdx = sparse(idx,1,true,vecLen,1);
次のような関数を書くことができます:
function logicalIdx = getLogicalIdx(idx, v)
logicalIdx = zeros(1,size(v,2));
logicalIdx(idx) = 1;
end
関数を呼び出す場合:
v = 1:6;
idx = [3 5];
getLogicalIdx(idx,v)
出力は次のようになります。
ans =
0 0 1 0 1 0