Нахождение островов нулей в последовательности

Предположите, что у Вас есть очень длинная последовательность. Что является самым эффективным способом найти интервалы, где последовательность является всеми нулями (или более точно последовательность спадает до почти нулевых значений abs(X)):

Для простоты, позволяет, принимают следующую последовательность:

sig = [1 1 0 0 0 0 1 1 1 1 1 0 1 0 0 0 1 1 1 1 1 1 1 1 0 0 1 1 1 0];

Я пытаюсь получить следующую информацию:

startIndex   EndIndex    Duration
3            6           4
12           12          1
14           16          3
25           26          2
30           30          1

затем с помощью этой информации, мы находим интервалы с продолжительностью> = к некоторому заданному значению (сказать 3) и возврат индексов значений во всех этих объединенных интервалах:

indices = [3 4 5 6 14 15 16];

Та последняя часть связана с предыдущим вопросом:

MATLAB: векторизованное создание массива из списка запускает/заканчивает индексы

Это - то, что я имею до сих пор:

sig = [1 1 0 0 0 0 1 1 1 1 1 0 1 0 0 0 1 1 1 1 1 1 1 1 0 0 1 1 1 0];
len = length(sig);
thresh = 3;

%# align the signal with itself successively shifted by one
%# v will thus contain 1 in the starting locations of the zero interval
v = true(1,len-thresh+1);
for i=1:thresh
    v = v & ( sig(i:len-thresh+i) == 0 );
end

%# extend the 1's till the end of the intervals
for i=1:thresh-1
    v(find(v)+1) = true;
end

%# get the final indices
v = find(v);

Я надеюсь векторизовать/оптимизировать код, но я открыт для других решений. Я должен подчеркнуть, что эффективность пространства и времени очень важна, так как я обрабатываю большое количество длинных биосигналов.

34
задан Community 23 May 2017 в 12:10
поделиться

4 ответа

Вот шаги, которые я бы предпринял для решения вашей проблемы векторизованным способом, начиная с заданного вектора sig :

  • Сначала задайте порог вектора, чтобы получить вектор tsig нулей и единиц (нули, где абсолютное значение сигнала падает достаточно близко к нулю, единицы в другом месте):

     tsig = (abs (sig)> = eps); % # Использование eps в качестве порога
    
  • Затем найдите начальные и конечные индексы и продолжительность каждой строки нулей с помощью функций DIFF и FIND :

     dsig = diff ([1 tsig 1 ]);
    startIndex = найти (dsig <0);
    endIndex = найти (dsig> 0) -1;
    продолжительность = endIndex-startIndex + 1;
    
  • Затем найдите строки нулей с длительностью, большей или равной некоторому значению (например, 3 в вашем примере):

     stringIndex = (duration> = 3);
    startIndex = startIndex (stringIndex);
    endIndex = endIndex (stringIndex);
    
  • Наконец, используйте метод из моего ответа на связанный вопрос , чтобы сгенерировать окончательный набор индексов:

     indices = zeros (1, max (endIndex) +1);
    индексы (startIndex) = 1;
    индексы (endIndex + 1) = индексы (endIndex + 1) -1;
    индексы = найти (cumsum (индексы));
    
33
ответ дан 27 November 2019 в 17:05
поделиться
function indice=sigvec(sig,thresh)
    %extend sig head and tail to avoid 0 head and 0 tail

    exsig=[1,sig,1];
    %convolution sig with extend sig
    cvexsig=conv(exsig,ones(1,thresh));
    tempsig=double(cvexsig==0);

    indice=find(conv(tempsig,ones(1,thresh)))-thresh;
1
ответ дан 27 November 2019 в 17:05
поделиться

Вы можете решить это как задачу поиска строк, находя строки нулей длиной thresh (функция STRFIND очень быстрая)

startIndex = strfind(sig, zeros(1,thresh));

Обратите внимание, что более длинные подстроки будут помечены в нескольких местах, но в конечном итоге будут объединены, когда мы добавим промежуточные места от интервалов, начинающихся в startIndex и заканчивающихся в start+thresh-1.

indices = unique( bsxfun(@plus, startIndex', 0:thresh-1) )';

Обратите внимание, что вы всегда можете заменить этот последний шаг на решение CUMSUM/FIND от @gnovice из связанного вопроса.

10
ответ дан 27 November 2019 в 17:05
поделиться

Я думаю, что наиболее MATLAB/"векторизованный" способ сделать это - вычислить свертку вашего сигнала с фильтром типа [-1 1]. Вы должны посмотреть документацию функции conv. Затем на выходе conv используйте find для получения соответствующих индексов.

-1
ответ дан 27 November 2019 в 17:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: