简体   繁体   English

Matlab:过滤大型数组元素,更快地替代逻辑索引吗?

[英]Matlab: filtering large array elements, quicker alternative to logical indexing?

I have a large, three-dimensional dataset of floats, roughly 500 million elements (3000 x 300 x 600). 我有一个大型的三维浮点数据集,大约有5亿个元素(3000 x 300 x 600)。

I want to make elements that are below or above certain thresholds zero. 我想将低于或高于某些阈值的元素设为零。 Logical indexing can do this, eg 逻辑索引可以做到这一点,例如

cut_in = 0.5
cut_out = 6
Hs(Hs<cut_in) = 0 ;
Hs(Hs>cut_out) = 0 ;

The problem is that this is painfully slow for me, what with the large data size. 问题在于,对于大数据量来说,这对于我来说是缓慢的。 The above code takes 240 seconds to run on my computer. 上面的代码需要240秒才能在我的计算机上运行。 Is there a quicker way I can do this? 有没有更快的方法可以做到这一点?

Many thanks 非常感谢

As @rayryeng and @AndrasDeak point out in comments to your question, logical indexing is usually fastest, though your runtimes suggest that you are probably limited by memory (and being forced to swap onto disk) rather than by the actual speed of the indexing. 正如@rayryeng和@AndrasDeak在对问题的注释中指出的那样,逻辑索引通常是最快的,尽管您的运行时建议您可能受内存(并被强制交换到磁盘)的限制,而不是受索引实际速度的限制。

One surprising alternative that can win out in this case is for loops. 在这种情况下可以胜出的一种令人惊讶的替代方法是for循环。 This is because logical indexing requires three passes through the array (once for each inequality test, and once to change the data), whereas a for loop only requires one pass through the array. 这是因为逻辑索引需要遍历该数组三遍(每个不等式测试一次,一次更改数据),而for循环仅需要遍历该数组一次。

Benchmarks 基准

So I ran these tests (and accidentally doubled the array size) on a machine with 8 GB memory: 因此,我在内存为8 GB的计算机上运行了这些测试(并意外地使数组大小增加了一倍):

>> A = randn(6000,300,600);
>> cut_in = -1;
>> cut_out = 1;

Using a for loop: 使用for循环:

>> tic; for i=1:numel(A), if A(i)<cut_in || A(i)>cut_out, A(i)=0; end; end; toc
Elapsed time is 597.384884 seconds.

Using logical indexing: 使用逻辑索引:

>> tic; A(A<cut_in | A>cut_out) = 0; toc
Elapsed time is 1619.105332 seconds.

And just for laughs (had some time on my hands waiting for the benchmarks to run), here is a compiled for loop: 只是为了笑(我花了一些时间等待基准测试运行),这是一个编译的for循环:

#include "mex.h"

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    double *A = mxGetPr(prhs[0]);
    size_t N = mxGetNumberOfElements(prhs[0]);
    double cut_in = *mxGetPr(prhs[1]);
    double cut_out = *mxGetPr(prhs[2]);
    // You're not supposed to do in-place operations! Don't do this!
    for (ptrdiff_t ii=0; ii<N; ii++) {
        if ((A[ii]<cut_in) || (A[ii]>cut_out))
            A[ii] = 0;
    }
}

And benchmarked: 并进行基准测试:

>> mex -v CXXOPTIMFLAGS="-O3 -DNDEBUG" -largeArrayDims apply_threshold.cpp
>> tic; apply_threshold(A,cut_in,cut_out); toc
Elapsed time is 529.994643 seconds

One thing to keep in mind is that we are operating in a regime where accessing the swap space is the main bottleneck in performance, and so benchmark results can vary, even within the same machine, depending on what's currently in main memory (vs. what needs to be swapped in) and what kind of background processes are running. 要记住的一件事是,我们在一种操作环境中进行操作,其中访问交换空间是性能的主要瓶颈,因此,即使在同一台机器上,基准测试结果也可能有所不同,具体取决于主内存中的当前内容(与之相对)。需要交换)以及正在运行哪种后台进程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM