我给出了一个索引列表,例如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.
错误......
hoogamaphone 编辑:
值得注意的是,ismembc
要求两个输入都是数字的、排序的、非稀疏的、非 NaN 值,这是源文档中很容易遗漏的细节。
只需创建一个逻辑索引向量并将所需位置设置为真/假
idx = false( size( v) );
idx( i ) = true;
这可以包装在这样的函数中:
function idx = getLogicalIdx(size, i)
idx = false(size);
idx(i) = true;
end
如果您需要为每百万次操作中的每个操作分配一次相同大小的索引向量,然后在每次迭代中对其进行操作:
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;
您可以使用ismember
i = [3 5];
v = 1:6;
ismember(v,i)
将返回
ans =
0 0 1 0 1 0
对于可能更快的版本,您可以尝试
builtin('_ismemberoneoutput', v, i)
请注意,我仅针对您指定的行向量对此进行了测试。
只需使用 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
你能简单地做 v(i) =1 吗?
例如,如果您说 x = zeros(1,10); 和 a = [1 3 4];
x(a) = 1 将返回 1 0 1 1 0 0 0 0 0 0