【问题标题】:Logical indexing on large matrix takes too long大型矩阵的逻辑索引耗时太长
【发布时间】:2016-08-11 23:34:15
【问题描述】:

我有 400 万 x 15 的表格。我正在应用这样的蒙版:

curData = data(curCodeMask & curEstDateMask,:);

掩码通常一次提取大约 5 条记录。我正在遍历数据中的 686,000 个唯一标识符并应用一系列函数。

我刚刚运行了分析器,发现这条线占用了 71.6% 的时间来运行这个函数。这看起来很奇怪。运行 1000 个标识符需要 3 分钟,这意味着我无法在合理的时间内通过 686,000 个。

有任何加快流程的建议或解释为何此面具难以应用?

编辑

test = repmat(cell2table(repmat({'AAA'},1,15)),4000000,1);
test([5500,60000,292404,290014,205802],1) = {'BBB'};
mask = strcmp(test.Var1,{'BBB'});
tic;test(mask,:);toc;
tic;test(find(mask),:);toc;

第一行耗时 0.078991 秒,第二行耗时 0.004005 秒。我现在正在更改我的代码以使用 find 。任何人都可以解释为什么逻辑索引需要这么长时间?

【问题讨论】:

  • 您要求 MATLAB 对每次循环迭代的 800 万个元素进行逻辑比较,显然这会增加很多时间。如果没有任何关于您正在做什么操作以及为什么选择这样做的上下文,那么实际上不可能回答您的问题。至少我会建议提供minimal reproducible example,我还要说这可能更适用于Code Review
  • 只是提供了一个很好的例子。结果很困惑。

标签: matlab indexing


【解决方案1】:

似乎使用find 引用矩阵更快,因为当将逻辑向量传递给subsref 时(当您使用A(b) 表示法引用数组的一部分时,Matlab 调用的函数),它必须如果它是零或一,则对每个值执行检查。如果为 1 则获取值,如果为 0 则什么也不做。执行的这些检查的数量始终相同:在您的示例中为4e6。另一方面,当您使用find 时,在您的示例中,您向subsref5 传递的索引数量要少得多,完成任务所需的操作数量要少得多。这可以通过以下基于您的示例的代码来说明:

N = 4000000; 
test_ = repmat(cell2table(repmat({'AAA'},1,15)),N,1);

for i = 1000:50000:1000000
    test = test_;
    test(randi(N, i,1),1) = {'BBB'};
    mask = strcmp(test.Var1,{'BBB'});
    tic;test(mask,:);toc;
    tic;test(find(mask),:);toc;
    fprintf('\n');
end

在这里,我们逐渐增加掩码中1s 的数量,并使用find 测量逻辑索引和显式索引的时间。如果你运行它,你会注意到第二个操作如何随着每次迭代而显着增加,而第一个操作保持在相同的数量级(尽管确实随着掩码数组中1s 的数量而增加):

Elapsed time is 0.139837 seconds.
Elapsed time is 0.008691 seconds.

Elapsed time is 0.157868 seconds.
Elapsed time is 0.052939 seconds.

Elapsed time is 0.202240 seconds.
Elapsed time is 0.072856 seconds.

Elapsed time is 0.251927 seconds.
Elapsed time is 0.107802 seconds.

Elapsed time is 0.273101 seconds.
Elapsed time is 0.115091 seconds.

Elapsed time is 0.304513 seconds.
Elapsed time is 0.140899 seconds.

Elapsed time is 0.320670 seconds.
Elapsed time is 0.145321 seconds.

Elapsed time is 0.363253 seconds.
Elapsed time is 0.147760 seconds.

Elapsed time is 0.351677 seconds.
Elapsed time is 0.183472 seconds.

Elapsed time is 0.365312 seconds.
Elapsed time is 0.174972 seconds.

Elapsed time is 0.410181 seconds.
Elapsed time is 0.182656 seconds.

Elapsed time is 0.410353 seconds.
Elapsed time is 0.220691 seconds.

Elapsed time is 0.424916 seconds.
Elapsed time is 0.194585 seconds.

Elapsed time is 0.451175 seconds.
Elapsed time is 0.212605 seconds.

Elapsed time is 0.471104 seconds.
Elapsed time is 0.218952 seconds.

Elapsed time is 0.495794 seconds.
Elapsed time is 0.233784 seconds.

Elapsed time is 0.513798 seconds.
Elapsed time is 0.257506 seconds.

Elapsed time is 0.523019 seconds.
Elapsed time is 0.262233 seconds.

Elapsed time is 0.540470 seconds.
Elapsed time is 0.281143 seconds.

Elapsed time is 0.543509 seconds.
Elapsed time is 0.283295 seconds.

因此,总而言之,当您知道mask 中等于1sum(mask) 的成员数量与数组的总大小相比时,使用test(find(mask),:)@987654337 @。你问有多小?您将不得不在您的机器上针对您的具体情况进行一些试验。但是,从上面的玩具示例看来,对于足够大的数组,find 比直接逻辑要好(至少对于 table 类)。

【讨论】:

    猜你喜欢
    • 2015-07-30
    • 2017-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-10
    相关资源
    最近更新 更多