【问题标题】:Looping over matrix elements more efficiently in Matlab在 Matlab 中更有效地循环矩阵元素
【发布时间】:2012-10-02 04:30:43
【问题描述】:

我正在编写一些 matlab 代码并编写了一个有效的算法,但我认为它不是特别有效。由于我正在努力提高我的编程技能,我想知道是否有更有效的方法来做到这一点。

我有一个(相当大的 ~ E07)值矩阵,这些值是无序的,但在 [-100, 100] 范围内。我想使用以下规则在第一个矩阵的基础上创建第二个矩阵:

  1. 如果点的值> 70,那么点的值应该设置为70。
  2. 如果点的值
  3. 所有其他值应四舍五入到最接近的 5 倍数。

这是我目前正在做的事情:

data = 100*(-1+2*rand(1,10000000)); % create random dataset for stackoverflow
new_data = zeros(1,length(data));

for i = 1:length(data)
    if (data(i) > 70)
        new_data(i) = 70;
    elseif (data(i) < -70)
        new_data(i) = -70;
    else
        new_data(i) = round(data(i)/5.0)*5.0;
    end
end

有没有更有效的方法?我认为应该有一种方法可以使用逻辑索引来做到这一点,但这些对我来说是一个新发现......

【问题讨论】:

    标签: matlab loops matrix


    【解决方案1】:

    你根本不需要循环:

    data = 100*(-1+2*rand(1,10000000)); % create random dataset for stackoverflow
    new_data = zeros(1,length(data)); % note that this memory allocation is not necessary at this point
    
    new_data = round(data/5.0)*5.0;
    new_data(data>70) = 70;    
    new_data(data<-70) = -70;
    

    【讨论】:

    • 这正是我想要的!谢谢:)
    【解决方案2】:

    H.Muster 和 woodchips 的两个答案当然是这样做的方法,但仍有一些小的改进有待发现。如果你追求性能,你可能想利用你的问题的细节。例如,您的输出数据是整数-100 &lt;= x &lt;= 100。这显然适用于 8 位有符号整数数据类型。此代码(注意从任意双精度数据显式转换为 int8

    % your double precision input data
    data = 100*(-1+2*rand(1,10000000));
    
    % cast to int8 - matlab does usual round here
    data = int8(data);
    new_data = 5*(max(-70,min(70,data))/5);
    

    最快有两个原因:

    • 1 个数据元素占用 1 个字节,而不是 8 个字节。内存带宽是这里的一个限制因素,因此您会得到很多改进
    • 不再需要轮回

    以下是 H.Muster、木片和我的小修改的代码中的一些时间:

    H.Muster    Elapsed time is 0.235885 seconds.
    woodchips   Elapsed time is 0.167659 seconds.
    my code     Elapsed time is 0.023061 seconds.
    

    差异非常显着。尽管 MATLAB 在任何地方都使用双精度数,但您应该尽可能尝试使用整数数据类型。

    编辑 这是因为 matlab 如何实现整数运算。与 C 不同,将 double 转换为 int 意味着 round 操作:

    a = 0.1;
    int8(a)
    
    ans =
      0
    
    a = 0.9;
    int8(a)
    
    ans =
      1
    

    【讨论】:

    • 很有趣,谢谢。我实际处理的数据不是整数集——它们都是双精度数。
    • @FakeDIY 我显然不够清楚:) 运行与其他相同的双输入数据的代码。它给出了相同的结果。您的输入数据不需要是整数 - 主要是您的 输出 数据是。我使用显式转换为uint8,它进行初始舍入并且是该方法的一部分。简而言之,对于您生成的测试数据,所有方法都会产生相同的结果。
    • 啊,明白了。数据类型不是我很了解的东西——不过那是一个非常好的方法。 :-)
    【解决方案3】:

    更简单的是使用最大值和最小值。只需一行即可完成。

    new_data = round(5*max(-70,min(70,data)))/5;
    

    【讨论】:

    • 不错。我更喜欢@H.Muster 答案的可读性,但我认为这一行的计算效率更高。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2014-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-31
    相关资源
    最近更新 更多