【问题标题】:Vectorizing nested if-statements向量化嵌套的 if 语句
【发布时间】:2016-07-01 17:07:34
【问题描述】:

问题 目前我正在处理大约 1800 万个点数据集,这些数据集通过不同的流程运行。通过配置文件查看器,我发现我的瓶颈之一是这部分代码,因此我想知道是否可以向量化多个 if 语句。

代码

WA=zeros(size(NB_list_z,1),3);
for i=1:size(NB_list_z,1);
    if (NB_list_z(i,2)==0||NB_list_z(i,3)==0);        
    WA(i,1)=BMLS(NB_list_z(i,1),5);

    else
       if (BMLS(NB_list_z(i,3),5)>=COG);
       WA(i,1)=(BMLS(NB_list_z(i,3),5)+BMLS(NB_list_z(i,2),5)+BMLS(NB_list_z(i,1),5))/3;    
            if (WA(i,1)<COG);
                if (BMLS(NB_list_z(i,2),5)>=COG);
               WA(i)=(BMLS(NB_list_z(i,2),5)+BMLS(NB_list_z(i,1),5))/2;                           
                    if (WA(i,1)<COG);
                  WA(i,1)=BMLS(NB_list_z(i,1),5);                  
                    end 
                else
                WA(i,1)=BMLS(NB_list_z(i,1),5);                
                end 
            end 
        else
             if (BMLS(NB_list_z(i,2),5)>=COG);
               WA(i,1)=(BMLS(NB_list_z(i,2),5)+BMLS(NB_list_z(i,1),5))/2;

                  if (WA(i,1)<COG);
                  WA(i,1)=BMLS(NB_list_z(i,1),5);                 
                 end 
             else
                WA(i,1)=BMLS(NB_list_z(i,1),5);               
             end          
       end
    end  
end 

代码说明

NB_list_z 包含第一列中点的邻居的索引(在 z 方向 - 每个点最多可以有两个点以上。) BMLS 包含我要检查的阈值。 COG 是阈值。 考虑最低的块 = Block1 ,上面的块 = Block2 ,上面的块 = Block3。

如果上面不存在邻居,则第一个 if 子句将值设置为 Block1 的值。

之后,我想以对我来说最有利可图的方式组合块。 这意味着如果块 3+2+1 高于阈值,我想将它们全部包括在内,但最高块(此处为块 3)也必须单独超过阈值。 如果不是,则 2+1 条件相同,如果不是,则只有 1。 上面的代码在小数据集上工作得很好,但对于更大的数据集开始需要很多时间。

问题

我刚开始接触“代码优化”和“矢量化”。我发现了一些关于删除 for 循环等的条目,但我找不到任何要删除的内容或只是多个 if 子句。因此问题是是否可以向量化嵌套的 if 子句?

【问题讨论】:

    标签: performance matlab vectorization


    【解决方案1】:

    代码有点太长,无法在这个论坛上重写,而且如果没有针对具有预期输出的测试数据进行测试,代码肯定太长了。但是,让我写一点关于“矢量化”的内容。

    什么是矢量化?

    所以,当我们谈论 MATLAB 中的向量化时,我们通常指的是我们对向量应用某些操作,而不是向量中的每个元素。有点过于简单化了,我们可以把它看作是,我们不是对向量中的每个元素应用一个操作,而是使用将向量作为输入的函数。为此,该操作需要有 MATLAB 支持。我的意思是,繁重的工作应该由编译文件(mex-file)来执行。

    怎么做的?

    当你想将它应用于向量中的所有元素时,它真的很简单。例如,而不是做,

    a = 1:2:20;
    total = 0;
    for k = a %(range-based)
        total = total + a;
    end
    %for ind = 1:length(a) %(same result)
    %    total = total + a(ind);
    %end
    

    也可以这样做,

    a = 1:2:20;
    total = sum(a);
    

    如果循环中有 if 语句,仍然可以对其进行向量化。假设你想分别对所有小于 11 和大于 11 的元素求和,

    a = 1:2:20
    total1 = sum(a(a<11));
    total2 = sum(a(a>11));
    

    但是,如果您嵌套了 if 语句,它会变得更加复杂。您可能需要将操作拆分为多个表达式。 if 语句的每个分支都需要单独处理。每个嵌套的 if 语句都将被视为外部 if 语句的子集。因此可以使用and (&amp;) 处理。

    b = rand(10);
    c = zeros(10);
    c(b<0.5) = 0;
    c(b>=0.5 & b<0.8) = 2*(c(b>=0.5 & b<0.8).^2);
    c(b>=0.8) = 1;
    

    何时进行矢量化

    如果一个函数只使用了几次并且“足够快”地执行,它可能不值得向量化。在此之后,它成为复杂性和效率之间的权衡。如果在执行期间调用 10000 次,则在 100 秒内执行的函数可能仍需要优化。通常,更通用的函数需要优化,因为它们似乎会吸引更多的函数调用。此外,如果您在循环之间存在依赖关系的情况下运行嵌套 for 循环,这些函数往往很难矢量化。

    a = 2:2:20;
    for (m=1:length(a))
        for (n=1:length(a))
            if (m~=n)
                a(n) = a(n)/2; 
            end
        end
        a(a>5) = 2*a(a>5);
    end
    

    这变得相当复杂,其中内循环取决于外循环的特定迭代。它可能仍然可以解决,但您将遇到类似于找到双积分的正交参数化的问题。如果不是绝对必要,则可能不值得付出努力,即使将其向量化至关重要,但仍值得以比向量化这些循环更可向量化的方式重新定义问题。

    一些遗言

    请注意,对于大型数据集,矢量化可能会生成大量元素的副本。确保您没有修改函数的输入,因为 Matlab 使用写时复制。

    【讨论】:

    • 感谢您的回答。您能否更详细地解释一下您的“遗言”?我不太清楚你的意思! :)
    • 还有没有办法代替矢量化来使用逻辑运算来减少运行时间?还是会变得复杂? 100 谢谢!
    • @KiW 将参数传递给函数有不同的技术。 Matlab 使用一种称为“写时复制”的技术。如果您想了解更多关于它的信息,您可以在网上找到一些文章。它的意思基本上是如果你将一个变量传递给一个函数而不修改它,Matlab 只会传递一个对变量的引用。但是,如果您修改变量,Matlab 将改为将副本传递给函数。这将使函数无法修改调用者中的变量,但也会使matlab复制大量数据。
    • 所以如果我理解正确,如果我没有在函数 matlab 中修改我的输入变量,则不需要复制变量,因此运行速度会更快?
    • @KiW 到第二条评论,这并不完全相关。矢量化意味着您将数组传递给函数,而不是在 Matlab 中编写 for 循环。您可以使用逻辑运算来推断要传递给函数的数组的哪一部分。而不是if(myvar(i)&gt;3) 给出结果true, false, true, true,而是在case 1,3,4 中输入if 语句并修改索引1,3,4。你可以改为q = myvar(myvar&gt;3); (which return [true,false,true,true]); res = alg(myvar(q)) 。如果变量足够大,修改函数中的变量实际上可能会导致内存溢出。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-01
    • 1970-01-01
    相关资源
    最近更新 更多