Проверьте, является ли средняя точка в интервале скольжения максимальной - PullRequest
0 голосов
/ 05 июня 2019
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 секунды (по сравнению с 0,4 секундами с lengthData, равным 1500).

Есть ли альтернативный способ реализации моей логики или ее векторизации, чтобы как-то ускорить ее?

Ответы [ 3 ]

3 голосов
/ 05 июня 2019

На основании этого комментария :

Максимумы возникают в середине окна в моей реализации кода.Может быть, я не был понятен в описании проблемы.Я ищу различные максимумы.Существует только один глобальный максимум, но есть много локальных максимумов.Теперь там локальные максимумы могут существовать только тогда, когда они больше, чем числа в их непосредственной близости.Эта окрестность я рассматриваю как длину движущегося окна.Конкретное значение может быть локальными максимумами, когда скользящее окно равно 5, но оно не может быть локальными максимумами, когда скользящее окно увеличивается до 10. (...)

Я предлагаю взглянуть на findpeaks(), который делает именно это: поиск локальных максимумов.Ваша «длина скользящего окна» будет затем включена в пару «имя-значение» 'MinPeakDistance', а минимальная высота, которую вы упоминаете в вопросе, будет определена как 'MinPeakHeight'.

2 голосов
/ 05 июня 2019

Я запустил код, используя решение для векторизации , а также findpeaks().Эта функция дает мне желаемый результат с лучшей производительностью по времени, см. Следующий тест:

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()

Я использую MATLAB R2018a на процессоре Xeon 3.4 сОперативная память 32 ГБ.

0 голосов
/ 05 июня 2019

Мне удалось векторизовать внутренний цикл следующим образом ...

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
...