我已经给出了一个索引列表,例如 i = [3 5]
和一个向量v = 1:6
。 我需要一个函数f
,该函数返回给定索引i
的逻辑映射结果,针对向量v
,例如:
f(i, length(v)) = [0 0 1 0 1 0]
由于我将调用此函数数百万次,因此希望尽可能快地运行它。是否有一个内置函数可以执行此任务?
我已经给出了一个索引列表,例如 i = [3 5]
和一个向量v = 1:6
。 我需要一个函数f
,该函数返回给定索引i
的逻辑映射结果,针对向量v
,例如:
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.
有趣的是,Jonas的解决方案对我来说无法运行,因为我遇到了Index exceeds matrix dimensions.
错误...
由hoogamaphone编辑:
值得注意的是,ismembc
要求两个输入都是数字、排序、非稀疏、非NaN值,这是一些细节,在源文档中很容易被忽略。
_ismemberoneoutput
,发现它比 ismembc
稍微慢一些。这对 @blubb 也可能是有趣的信息。 - H.Musterismembc
函数运行良好,否则它将失败。 - hoogamaphonev
已经排序。 - Eitan T只需创建一个逻辑索引向量,然后将所需位置设置为true/false即可。
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)
v
,那么这将会很慢,因为每次调用此函数时都需要分配一个包含1:N
的向量。 - slaytonismember
一样好,但速度明显更快。接受他的答案似乎是公平的,而不是我的。 - H.Musterv
是一个大数组时,它比 slayton 的解决方案要慢。 - Eitan Tismember
而不是slayton的解决方案,尽管它更慢。因此,他应该更喜欢你的解决方案... - H.Musteridx = [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
i= [3 5]
,逻辑映射难道不应该是[0 0 1 0 1 0]
吗? - H.Musterfind(ismember(v,i))
返回i
。 - TTT