在Matlab中更有效地循环矩阵元素

时间:2012-10-11 13:32:45

标签: matlab loops matrix

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

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

  1. 如果该点的值是> 70,那么该点的值应设为70。
  2. 如果该点的值是< -70,那么该点的值应设置为-70。
  3. 所有其他值应四舍五入为最接近的5的倍数。
  4. 以下是我目前正在做的事情:

    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
    

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

3 个答案:

答案 0 :(得分:8)

根本不需要循环:

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;

答案 1 :(得分:5)

更容易使用max和min。只需一行即可。

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

答案 2 :(得分:2)

H.Muster和woodchips的两个答案当然是这样做的方法,但仍然有一些小改进。如果您在演出后可能想要利用问题的具体细节。例如,您的输出数据是整数-100 <= x <= 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