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

时间:2016-02-03 18:09:59

标签: arrays matlab

我有一个大型的浮动三维数据集,大约有5亿个元素(3000 x 300 x 600)。

我想使低于或高于特定阈值的元素为零。逻辑索引可以做到这一点,例如

__INT64_TYPE__

问题是这对我来说非常缓慢,数据量大。上面的代码需要240秒才能在我的计算机上运行。有没有更快的方法可以做到这一点?

非常感谢

1 个答案:

答案 0 :(得分:0)

正如@rayryeng和@AndrasDeak在对你的问题的评论中指出的那样,逻辑索引通常是最快的,尽管你的运行时表明你可能受到内存的限制(并且被迫交换到磁盘上)而不是实际的速度。索引。

在这种情况下可以胜出的一个令人惊讶的替代方案是循环。这是因为逻辑索引需要三次遍历数组(每次不等式测试一次,一次更改数据),而for循环只需要一次遍历数组。

基准

所以我在具有8 GB内存的机器上运行这些测试(并且意外地将数组大小加倍):

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

使用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.

使用逻辑索引:

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

只是为了笑(有一些时间在我的手上等待基准运行),这里是一个编译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;
    }
}

基准测试:

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

要记住的一点是,我们在一个访问交换空间是性能主要瓶颈的制度下运行,因此即使在同一台机器内,基准测试结果也会有所不同,具体取决于当前主存储器中的内容(与需要交换的内容相比,以及正在运行的后台进程。