find_peaks не определяет пик в начале массива - PullRequest
7 голосов
/ 06 февраля 2020

Я пытаюсь найти векторизованный подход поиска первой позиции в массиве, где значения не превышают максимум из n предыдущих чисел. Я думал об использовании метода find_peaks scipy.signal, чтобы найти локальный максимум. Я думаю, что это именно так, если вы определяете расстояние, скажем, 10 n равно 10. Но, к сожалению, условие для расстояния должно выполняться в обоих направлениях - предыдущие и будущие числа. Есть ли какой-либо другой метод или подход к поиску такой вещи?

Пример:

arr1 = np.array([1.        , 0.73381293, 0.75649351, 0.77693474, 0.77884614,
       0.81055903, 0.81402439, 0.78798586, 0.78839588, 0.82967961,
       0.8448    , 0.83276451, 0.82539684, 0.81762916, 0.82722515,
       0.82101804, 0.82871127, 0.82825041, 0.82086957, 0.8347826 ,
       0.82666665, 0.82352942, 0.81270903, 0.81191224, 0.83180428,
       0.84975767, 0.84044236, 0.85057473, 0.8394649 , 0.80000001,
       0.83870965, 0.83962262, 0.85039371, 0.83359748, 0.84019768,
       0.83281732, 0.83660132])

from scipy.signal import find_peaks
peaks, _ = find_peaks(arr1, distance=10)

В этом случае он находит позиции 10 и 27. Но также позицию 0 имеет 10 следующих элементов, которые не выше. Как я могу найти их?

Ответы [ 3 ]

2 голосов
/ 06 февраля 2020
def rolling_window(a, window):
    shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
    strides = a.strides + (a.strides[-1],)
    return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)

def get_peaks(arr, window):
    maxss = np.argmax(rolling_window(arr1, window), axis=1)
    return np.where(maxss == 0)[0]
>>> arr1 = np.array([1.        , 0.73381293, 0.75649351, 0.77693474, 0.77884614,
       0.81055903, 0.81402439, 0.78798586, 0.78839588, 0.82967961,
       0.8448    , 0.83276451, 0.82539684, 0.81762916, 0.82722515,
       0.82101804, 0.82871127, 0.82825041, 0.82086957, 0.8347826 ,
       0.82666665, 0.82352942, 0.81270903, 0.81191224, 0.83180428,
       0.84975767, 0.84044236, 0.85057473, 0.8394649 , 0.80000001,
       0.83870965, 0.83962262, 0.85039371, 0.83359748, 0.84019768,
       0.83281732, 0.83660132])
>>> get_peaks(arr1, 10)
array([ 0, 10, 27])

Кредит на функцию скользящего окна: Скользящее окно для одномерных массивов в Numpy?

1 голос
/ 06 февраля 2020

Мы можем использовать 1D sliding-windowed max filter from SciPy. Кроме того, кажется, вы сравниваете с n предыдущими элементами. Поскольку первый элемент не будет иметь никакого предыдущего элемента, мы должны игнорировать его.

Следовательно, у нас будет реализация, например, так:

from scipy.ndimage.filters import maximum_filter1d

def peaks_previousN(a, n):
    W = (n-1)//2
    return np.flatnonzero(a[1:]>=maximum_filter1d(a, n, origin=W)[:-1])+1

Пример запуска с заданным массив образцов -

In [107]: peaks_previousN(arr1, n=10)
Out[107]: array([25, 27])
1 голос
/ 06 февраля 2020

К сожалению, find_peaks() работает путем сравнения соседних значений - поэтому не будет определять пики, которые возникают в начале или конце массива. Одним из обходных путей является использование np.concatenate() для вставки минимального значения массива в начале и конце, а затем вычитание 1 из переменной пиков:

>>> import numpy as np
>>> peaks, _ = find_peaks(np.concatenate(([min(arr1)],arr1,[min(arr1)])), distance=10)
>>> peaks-1
array([ 0, 10, 27], dtype=int64)
...