blu*_*ubb 9 matlab logical-operators matrix-indexing
我给出了一个索引列表,例如i = [3 5]一个向量v = 1:6.我需要一个函数f,它返回v给定索引的向量的逻辑映射i,例如:
f(i, length(v)) = [0 0 1 0 1 0]
Run Code Online (Sandbox Code Playgroud)
由于我将这个功能称为几百万次,我想尽快做到这一点.是否有内置函数执行此任务?
我知道我已经迟到了,但我真的很想找到一个更优雅的解决方案ismember.确实有一个使用无证ismembc功能:
ismembc(v, i)
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
这是我得到的:
Elapsed time is 1.482971 seconds.
Elapsed time is 6.369626 seconds.
Elapsed time is 2.039481 seconds.
Elapsed time is 0.776234 seconds.
Run Code Online (Sandbox Code Playgroud)
令人惊讶的是,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.
Run Code Online (Sandbox Code Playgroud)
有趣的是,Jonas的解决方案不适合我,因为我收到了Index exceeds matrix dimensions.错误...
由hoogamaphone编辑:
值得注意的是,ismembc需要两个输入都是数字,排序,非稀疏,非NaN值,这是源文档中很容易遗漏的细节.
只需创建逻辑索引向量,并将所需位置设置为true/false
idx = false( size( v) );
idx( i ) = true;
Run Code Online (Sandbox Code Playgroud)
这可以包含在这样的函数中:
function idx = getLogicalIdx(size, i)
idx = false(size);
idx(i) = true;
end
Run Code Online (Sandbox Code Playgroud)
如果您需要为每个百万个操作分配相同大小的索引向量,则将向量分配一次,然后在每次迭代时对其进行操作:
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
Run Code Online (Sandbox Code Playgroud)
如果你真的需要性能,你可以编写一个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;
}
}
Run Code Online (Sandbox Code Playgroud)
在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;
Run Code Online (Sandbox Code Playgroud)
您可以使用 ismember
i = [3 5];
v = 1:6;
ismember(v,i)
Run Code Online (Sandbox Code Playgroud)
将返回
ans =
0 0 1 0 1 0
Run Code Online (Sandbox Code Playgroud)
对于可能更快的版本,您可以尝试
builtin('_ismemberoneoutput', v, i)
Run Code Online (Sandbox Code Playgroud)
请注意,我仅对您指定的行向量进行了测试.