测试滑动间隔内的中间点是否为其最大值

时间:2019-06-05 12:39:12

标签: matlab performance max vectorization windowing

lengthData = 1500;
data = rand(lengthData,1);
result = zeros(floor(lengthData/2),lengthData);
for i = 1:floor(lengthData/2)-1
    for j = 1+i:length(data)-i
        if data(j) == max(data(j-i:j+i))
            result(i,j)=1;
        end
    end
end

我有一个指定的lengthData数据点存储在变量data中。现在,我试图在指定的间隔中找到最大值,其中间隔长度在增加。

一个快速的观察结果是,随着间隔大小的增加,result中特定行中的条目数正在减少。以下是sum(result,2)的图表,用于验证代码是否按预期工作。

enter image description here

但是,此代码需要很长时间才能执行。对于较大的lengthData(约为6000),花费的时间将近22秒(而lengthData为1500时为0.4秒)。

有没有其他方法可以实现我的逻辑或对其进行向量化,从而以某种方式加快速度?

3 个答案:

答案 0 :(得分:3)

基于this comment

  

Maxima出现在我的代码实现的窗口中间。可能是我在问题描述中不清楚。我正在寻找各种最大值。只有一个全局最大值,但有许多局部最大值。现在,只有当局部最大值大于其附近的数字时,局部最大值才能存在。我正在考虑将此区域作为移动窗口的长度。当滑动窗口为5时,特定值可能是局部最大值,但是当滑动窗口增加到10时,它可能不是局部最大值。(...)

我建议看一下findpeaks(),它确实做到了:找到局部最大值。然后,您的“滑动窗口长度”将合并到'MinPeakDistance'名称-值对中,而您在问题中提到的最小高度将由'MinPeakHeight'给出。

答案 1 :(得分:2)

我使用vectorization solutionfindpeaks()运行代码。此功能可提供更好的时间性能,并达到预期效果,请参见以下基准测试:

tic;
lengthData=6000;
data=rand(lengthData,1);
result=zeros(floor(lengthData/2),lengthData);
for i=1:floor(lengthData/2)-1
    for j=1+i:length(data)-i
        if(data(j)==max(data(j-i:j+i)))
            result(i,j)=1;
        end
    end
end
toc;

tic;
result1=zeros(floor(lengthData/2),lengthData);
for i=1:floor(lengthData/2)-1
    del = 2*i+1;
    ind_arr = [];
    ind_arr(:,1) = 1:lengthData+1-del;
    ind_arr(:,2:del) = 1;
    ind_arr = cumsum(ind_arr,2);
    data_arr = data(ind_arr);
    [~,max_ind] = max(data_arr,[],2);
    result1(i,1+i:length(data)-i) = max_ind==(i+1);
end
toc;


tic;
result2=zeros(floor(lengthData/2),lengthData);

for i=1:floor(lengthData/2)-1

    [~,locs]=findpeaks(data,'MinPeakDistance',i);
    result2(i,1:length(locs))=locs;
end
toc;

结果:

Elapsed time is 23.317170 seconds.   % Original
Elapsed time is 312.340804 seconds.  % Vectorized
Elapsed time is 3.053548 seconds.    % findpeaks()

我在具有32GB RAM的Xeon 3.4处理器上使用MATLAB R2018a。

答案 2 :(得分:0)

我能够通过以下方式向量化内部循环...

lengthData=1500;
data=rand(lengthData,1);
result=zeros(floor(lengthData/2),lengthData);

for i=1:floor(lengthData/2)-1

    del = 2*i+1;
    ind_arr = [];
    ind_arr(:,1) = 1:lengthData+1-del;
    ind_arr(:,2:del) = 1;
    ind_arr = cumsum(ind_arr,2);

    data_arr = data(ind_arr);

    [~,max_ind] = max(data_arr,[],2);

    result(i,1+i:length(data)-i) = max_ind==(i+1);

end

可能有一种更清洁的方法来构建ind_arr,但这似乎可以为原始代码提供匹配的结果。

通过R2014b中的事件探查器运行它

  time   calls  line
             1    1 lengthData=1500; 
             1    2 data=rand(lengthData,1); 
             1    3 result=zeros(floor(lengthData/2),lengthData); 
             1    4 result2 = result; 
                  5 
             1    6 t1ID = tic; 
                  7 
             1    8 for i=1:floor(lengthData/2)-1 
           749    9     for j=1+i:length(data)-i 
  3.66  561750   10         if(data(j)==max(data(j-i:j+i))) 
< 0.01    4276   11             result(i,j)=1; 
          4276   12         end 
  0.70  561750   13     end 
           749   14 end 
                 15 
             1   16 fprintf('Original Time: %g\n',toc(t1ID)); 
                 17 
             1   18 t2ID = tic; 
                 19 
             1   20 for i=1:floor(lengthData/2)-1 
                 21     
           749   22     del = 2*i+1; 
  0.02     749   23     ind_arr = []; 
< 0.01     749   24     ind_arr(:,1) = 1:lengthData+1-del; 
  0.45     749   25     ind_arr(:,2:del) = 1; 
  0.51     749   26     ind_arr = cumsum(ind_arr,2); 
                 27 
  1.42     749   28     data_arr = data(ind_arr); 
                 29 
  0.52     749   30     [~,max_ind] = max(data_arr,[],2); 
                 31 
  0.05     749   32     result2(i,1+i:length(data)-i) = max_ind==(i+1); 
                 33     
           749   34 end 
                 35 
             1   36 fprintf('Single Loop Time: %g\n',toc(t2ID));
Original Time: 4.53376
Single Loop Time: 2.81267