Matlab索引到逻辑索引

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)

由于我将这个功能称为几百万次,我想尽快做到这一点.是否有内置函数执行此任务?

Eit*_*n T 9

我知道我已经迟到了,但我真的很想找到一个更优雅的解决方案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值,这是源文档中很容易遗漏的细节.


sla*_*ton 5

只需创建逻辑索引向量,并将所需位置设置为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)


H.M*_*ter 5

您可以使用 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)

请注意,我仅对您指定的行向量进行了测试.