代码之家  ›  专栏  ›  技术社区  ›  Radu

find()与for循环的性能

  •  1
  • Radu  · 技术社区  · 14 年前

    我有一大组(4000个值)的未排序的、正态分布的点。我将把这些数据点中的每一个放入限制在binlimit数组中的容器中。然后我把每一个箱子里的数值列成表格。

    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
    

    现在,我知道第一个解决方案是慢的-对于总箱(25-50)的正常值,大约慢8倍,但我想知道是否有比我在方法2中所做的更快、更有效的解决方案。

    3 回复  |  直到 12 年前
        1
  •  4
  •   Jacob    14 年前

    使用 histc .

    n=历史(x,边),对于向量x, 以x为单位计算 落在边缘的元素之间 矢量(必须包含 单调非递减值)。 n是包含 这些计数。

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

    例如。

    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.
    
        2
  •  2
  •   Amro    14 年前

    除了使用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)) )
    

    注意它不是 空间 -尽管如此,由于它创建了一个大小矩阵: length(X) by length(BinLimits)-1

        3
  •  0
  •   angainor    12 年前

    我想你在检查X是否属于垃圾箱时可能会出错。对于属于binlimits的x值,您可能会得到多个bin。

    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的(排序时间也在上面的结果中给出)。以下是非排序数组的历史结果(与上面相同的x,用随机排列排列排列)

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

    如您所见,将排序数组上的排序和histc放在一起的时间类似于在未排序数组上运行histc。