Найдите все локальные максимумы и минимумы, когда значения x и y заданы в виде массивов numpy

У меня есть два массива x и y как:

x = np.array([6, 3, 5, 2, 1, 4, 9, 7, 8])
y = np.array([2, 1, 3, 5, 3, 9, 8, 10, 7])

Я нахожу индекс локальных минимумов и максимумов следующим образом:

sortId = np.argsort(x)
x = x[sortId]
y = y[sortId]
minm = np.array([])
maxm = np.array([])
while i < y.size-1:
   while(y[i+1] >= y[i]):
      i = i + 1

   maxm = np.insert(maxm, 0, i)
   i++
   while(y[i+1] <= y[i]):
      i = i + 1

   minm = np.insert(minm, 0, i)
   i++

В чем проблема в этом коде? Ответ должен быть индексом minima = [2, 5, 7] и индексом maxima = [1, 3, 6].


person prtkp    schedule 26.06.2015    source источник
comment
что ты делаешь с sortId=np.argsort(x); x=x[sortId]?   -  person fferri    schedule 26.06.2015
comment
Это решение с двойным циклом while будет очень медленным (и я даже не говорю о np.insert, который в значительной степени перераспределяет массивы minm/nmax на каждой итерации). См. stackoverflow.com/questions/4624970/, чтобы правильно сделать это в numpy.   -  person rth    schedule 26.06.2015
comment
@mescalinum: я сортирую значения x, и соответствующие индексы будут храниться в sortId. так что я могу расположить значения y в этом порядке.   -  person prtkp    schedule 26.06.2015
comment
@Cleb: я хочу пики и впадины.   -  person prtkp    schedule 26.06.2015
comment
@rth: На самом деле в моем наборе данных точки очень смежны, поэтому метод, упомянутый в вашей ссылке, также дает несколько дополнительных точек вокруг максимумов и минимумов.   -  person prtkp    schedule 26.06.2015
comment
@Cleb: если вы построите график с этими значениями x и y, вы получите пики в точках x[1],x[2],x[3] и впадины в точках x[2],x[5],x [7]. это индексы пиков и впадин   -  person prtkp    schedule 26.06.2015
comment
@Cleb: абсолютно, сэр ... почему я говорил, что индекс максимумов равен 1,3,6, а точки - (2,5), (4,9) и (7,10) ... аналогично индексу минимумы 2,5,7 точки (3,1), (6,2) и (8,7).   -  person prtkp    schedule 26.06.2015
comment
@Cleb: не могли бы вы найти ошибку в этом коде или можете предоставить новый код для этого ..... проблема в том, что у меня есть большой набор данных со значениями x и y, которые очень смежны, поэтому найти точные пики сложно.   -  person prtkp    schedule 26.06.2015
comment
@prtkp: Не уверен, что пойдет не так в цикле while, но ниже я добавил альтернативное решение, которое должно быть намного более эффективным, чем цикл for, и которое возвращает желаемый результат. Дайте мне знать, подходит ли вам это или нужно пересмотреть!   -  person Cleb    schedule 28.06.2015


Ответы (3)


Вам вообще не нужен этот цикл while. Код ниже даст вам желаемый результат; он находит все локальные минимумы и все локальные максимумы и сохраняет их в minm и maxm соответственно. Обратите внимание: когда вы применяете это к большим наборам данных, обязательно сначала сгладьте сигналы; в противном случае вы получите массу экстремумов.

import numpy as np
from scipy.signal import argrelextrema
import matplotlib.pyplot as plt

x = np.array([6, 3, 5, 2, 1, 4, 9, 7, 8])
y = np.array([2, 1, 3 ,5 ,3 ,9 ,8, 10, 7])

# sort the data in x and rearrange y accordingly
sortId = np.argsort(x)
x = x[sortId]
y = y[sortId]

# this way the x-axis corresponds to the index of x
plt.plot(x-1, y)
plt.show()
maxm = argrelextrema(y, np.greater)  # (array([1, 3, 6]),)
minm = argrelextrema(y, np.less)  # (array([2, 5, 7]),)

Это должно быть намного эффективнее, чем описанный выше цикл while.

Сюжет выглядит так; Я сдвинул значения x так, чтобы они соответствовали возвращенным индексам в minm и maxm):

введите здесь описание изображения

Начиная с SciPy версии 1.1, вы также можете использовать find_peaks:

from scipy.signal import find_peaks

peaks, _ = find_peaks(y)

# this way the x-axis corresponds to the index of x
plt.plot(x-1, y)
plt.plot(peaks, y[peaks], "x")
plt.show()

Это дает

введите описание изображения здесь

Приятно то, что теперь вы также можете легко установить минимальную высоту пика (например, 8):

peaks, _ = find_peaks(y, height=8)

# this way the x-axis corresponds to the index of x
plt.plot(x-1, y)
plt.plot(peaks, y[peaks], "x")
plt.show() 

введите описание изображения здесь

Обратите внимание, что теперь исключается первый пик, так как его высота меньше 8.

Кроме того, вы также можете установить минимальное расстояние между пиками (например, 5):

peaks, _ = find_peaks(y, distance=5)

# this way the x-axis corresponds to the index of x
plt.plot(x-1, y)
plt.plot(peaks, y[peaks], "x")
plt.show()

введите описание изображения здесь

Теперь средний пик исключен, так как его расстояние до двух других пиков меньше 5.

person Cleb    schedule 26.06.2015
comment
да .... это работает нормально ... мое решение, приведенное ниже, также дает тот же ответ .... но проблема заключается в большом наборе данных, который дает много экстремумов, как вы сказали в моем втором вопросе и предложили чтобы сгладить сигнал перед поиском экстремумов... кстати, спасибо - person prtkp; 29.06.2015
comment
Извините, что добавляю это как комментарий, но не знаю, как сформулировать вопрос при поиске. Что вы подразумеваете под сглаживанием сигналов? Что бы вы использовали для этого? Спасибо. - person datahappy; 16.02.2016
comment
@datahappy: Вы можете искать плавный сигнал scipy, а также скользящее среднее значение, которое должно направить вас на правильный путь. Сглаживание избавляет от многих локальных экстремумов, что помогает найти фактические пики. - person Cleb; 16.02.2016
comment
Привет! Можно получить минимумы, используя peaks, _ = find_peaks(-y). - person Echan; 12.11.2019

x=np.array([6,3,5,2,1,4,9,7,8])
y=np.array([2,1,3,5,7,9,8,10,7])

sort_idx = np.argsort(x)
y=y[sort_idx]
x=x[sort_idx]
minm=np.array([],dtype=int)
maxm=np.array([],dtype=int)
length = y.size
i=0

while i < length-1:
    if i < length - 1:
        while i < length-1 and y[i+1] >= y[i]:
            i+=1

        if i != 0 and i < length-1:
            maxm = np.append(maxm,i)

        i+=1

    if i < length - 1:
        while i < length-1 and y[i+1] <= y[i]:
            i+=1

        if i < length-1:
            minm = np.append(minm,i)
        i+=1


print minm
print maxm

minm и maxm содержат индексы минимумов и максимумов соответственно.

person prtkp    schedule 28.06.2015

Это будет работать нормально.

Python использует += вместо ++.

Прежде чем использовать i в цикле while, вы должны присвоить какое-то значение - в данном случае 0 - , таким образом инициализируя его, чтобы избежать ошибки.

import numpy as np

x=np.array([6,3,5,2,1,4,9,7,8])
y=np.array([2,1,3,5,3,9,8,10,7])


sortId=np.argsort(x)
x=x[sortId]
y=y[sortId]
minm = np.array([])
maxm = np.array([])
i = 0
while i < y.size-1:
   while(y[i+1] >= y[i]):
      i+=1

   maxm=np.insert(maxm,0,i)
   i+=1
   while(y[i+1] <= y[i]):
      i+=1

   minm=np.insert(minm,0,i)
   i+=1

print minm, maxm
person Geeocode    schedule 26.06.2015
comment
в результате [ 7. 5. 2.] [ 6. 3. 1.] - person Geeocode; 26.06.2015
comment
Вам удалось его запустить? Игнорируя исходную техническую проблему, поскольку цикл while и перераспределение, может ли кто-нибудь запустить мое решение, чтобы проверить, не дает ли индекс ошибки вне границ? - person Geeocode; 26.06.2015
comment
когда я выполняю, появляется ошибка. если вы выполняете третий цикл while, вы не проверяете привязку индекса. Возьмите другой пример, а затем попробуйте выполнить - person prtkp; 26.06.2015
comment
сценарий достигает 3-го цикла while, конечно, и парсер python выдал бы мне сообщение об ошибке, если бы это было так, но это НЕ так. Пожалуйста. пришлите мне полный код, который вы запускаете, чтобы проверить его. Что-то не так на вашей стороне. - person Geeocode; 26.06.2015