find()与for循环的性能

时间:2010-10-21 23:32:59

标签: matlab optimization loops

我有一组大的(4000个值)未分类的,正常分布的点。我将这些数据点中的每一个都放入限制在BinLimit数组中的容器中。然后我将每个bin中的值数量列表。

X是原始数据的数组,N是数据点的数量。所需的箱数(TotalBins)由用户指定。

方法#1

for i=1:TotalBins
    Freq(i) = length(find(X >= BinLimit(j) & X <= BinLimit(j+1)));
    j = j + 1;
end

方法#2:

sort(X);

for i=1:N
    if (X(i) >= BinLimit(j) && X(i) <= BinLimit(j+1))
        Freq(j) = freq(j) + 1;
    elseif (j < TotalBins)
        Freq(j+1) = freq(j+1) + 1;
        j = j + 1;
    end
end

现在,我知道第一个解决方案速度较慢 - 对于总Bins(25-50)的正常值,它慢了大约8倍但是我想知道是否有比我正在做的更快,更有效的解决方案方法#2。

3 个答案:

答案 0 :(得分:4)

使用histc

  

N = HISTC(X,EDGES),对于向量X,   计算X中的值的数量   介于EDGES中的元素之间   矢量(必须包含   单调非递减值)。   N是含有的LENGTH(EDGES)载体   这些都很重要

     

N(k)将计算   值X(i)如果EDGES(k)&lt; = X(i)&lt;   边缘(K + 1)。最后一个垃圾箱将计数   与EDGES匹配的任何X值(结束)。   EDGES中值之外的值是   不计算在内。使用-inf和inf in   EDGES包括所有非NaN值。

E.g。

BinLimit = sort(rand(50,1));
X = rand(4000,1);
Freq = histc(X,BinLimit);

为了好玩:

%%# Generating data
X = rand(1000000,1);
BinLimit = sort(rand(50,1));

%%# OP's method
disp('Method #1');
disp('=========');
tic;
j =1;
TotalBins = numel(BinLimit)-1;
for i=1:TotalBins
    Freq(i) = length(find(X >= BinLimit(j) & X <= BinLimit(j+1)));
    j = j + 1;
end
toc

%%# histc
disp('histc');
disp('=====');
tic;
histc(X,BinLimit);
toc

%%# My method
disp('Alternative');
disp('===========');
tic;
TotalBins = numel(BinLimit)-1;
Freq = zeros(TotalBins,1);
for i = 1:TotalBins
    Freq(i) = sum(X >= BinLimit(i) & X <= BinLimit(i+1));
end
toc

经过几次热身后:

Method #1
=========
Elapsed time is 0.803120 seconds.
histc
=====
Elapsed time is 0.030633 seconds.
Alternative
===========
Elapsed time is 0.704808 seconds.

答案 1 :(得分:2)

除了使用HISTC之外,这里还有一个矢量化的单行解决方案:

X = randn(4000,1);                %# column vector
BinLimits = linspace(-4,4,10);    %# row vector

Freq = sum( bsxfun(@ge, X, BinLimits(1:end-1)) & bsxfun(@le, X, BinLimits(2:end)) )

请注意,它不是 space - 因为它创建了一个大小的矩阵: length(X) by length(BinLimits)-1

答案 2 :(得分:0)

我认为在检查X是否属于bin时可能会出错。对于落在BinLimits上的X值,您可能会获得多个容器。

X >= BinLimit(j) & X <= BinLimit(j+1)

无论如何,既然你要求一个循环解决方案,那么这个方法比你的方法2表现更好。

j=1;
i=1;
while i<=N
    while i<=N && X(i)<=BinLimit(j+1)
        i=i+1;
    end
    Freq(j) = i-1;
    j = j+1;
end
Freq=diff([0 Freq]);

它需要对X进行排序,就像在代码中一样。下面是排序X数组讨论的所有方法的时间(histc对于排序X也更快,因此这是一个公平的比较):

Sort
===========
Elapsed time is 0.019205 seconds.
Method #1
=========
Elapsed time is 0.209979 seconds.
histc
=====
Elapsed time is 0.009595 seconds.
Alternative
===========
Elapsed time is 0.228400 seconds.
Method 2
===========
Elapsed time is 0.025400 seconds.
my method
===========
Elapsed time is 0.011920 seconds.
bsxfun by Amro
===========
Elapsed time is 0.179937 seconds.

如您所见,此循环结构的表现几乎与histc一样(25%更差)。

那是针对排序的X(排序时间也在上面的结果中给出)。这是未排序数组的histc结果(与上面相同的X,随机置换排列)

histc
=====
Elapsed time is 0.030367 seconds.

如您所见,对排序数组进行排序和histc的时间与在未排序数组上运行histc类似。