MATLAB中ismember()函数的快速版本

时间:2017-09-25 11:19:55

标签: matlab performance

我的问题是如何以更快的方式在MATLAB中找到ismember()所做的替代方法。

这是我的问题:

M [92786253*1]  (a: roughly 100M rows)
x [749*1]       (b: # of rows can vary from 100 to 10K)

我想在b中找到共存于a中的行(a的行索引)。对于不同版本的b此操作需要重复约10M次

正常方法:

 tic
 ind1 = ismember(M,x);
 toc

 Elapsed time is 0.515627 seconds.

快速方法:

 tic
 n = 1;
 ind2 = find(any(all(bsxfun(@eq,reshape(x.',1,n,[]),M),2),3));
 toc

 Error using bsxfun
 Requested 92786253x1x749 (64.7GB) array exceeds maximum array size preference. 
 Creation of arrays greater than this limit may take a long time and cause MATLAB to become unresponsive.
 See array size limit or preference panel for more information.

 Error in demo_ismember_fast (line 23)
 ind2 = find(any(all(bsxfun(@eq,reshape(x.',1,n,[]),M),2),3))

第二种方法通常比正常方法快15-20倍,但在这种情况下,我不能将其用于内存限制。有什么建议加快这个操作吗?感谢您与我分享专家意见!

2 个答案:

答案 0 :(得分:1)

如果您可以使用已排序的a,这里有两种替代方法。在开始100M迭代之前,一些必需的输入变量和输出变量ind被初始化,并且在每次迭代ind被修改,并且最后它的所有元素都被设置为false;

<强> interp1:

s=sort(M);
edge = [-Inf s(2:end) Inf];
v = [1:numel(M) numel(M)];
ind = false(size(M));
%for ... 100M iterations
    tic
    bin = interp1(edge,v,x,'previous');
    ind(bin)= ind(bin)==x;
    toc
    %...
    ind(bin) = false;%at the end of each loop set all elements of ind to 0;
%end

<强> histcounts:

s=sort(M);
edge= [-Inf s(2:end) Inf];
ind = false(size(M));
%for ... 100M iterations
    tic
    [~,~,bin]=histcounts(x,edge);
    ind(bin)= ind(bin)==x;
    toc
    %...
    ind(bin) = false;
%end

答案 1 :(得分:1)

您可能会发现内部(内置)ismembc函数很有用 - 它比ismember快一个数量级:http://UndocumentedMatlab.com/blog/ismembc-undocumented-helper-function

请注意,ismembc仅适用于已排序的非稀疏非Nan数字数据。