Как найти локальные максимумы в питоне

There exists a bulit-in function argrelextrema that gets this task done:

import numpy as np
from scipy.signal import argrelextrema
    
a = np.array([1,2,3,4,5,4,3,2,1,2,3,2,1,2,3,4,5,6,5,4,3,2,1])

# determine the indices of the local maxima
max_ind = argrelextrema(a, np.greater)

# get the actual values using these indices
r = a[max_ind]  # array([5, 3, 6])

That gives you the desired output for r.

As of SciPy version 1.1, you can also use find_peaks. Below are two examples taken from the documentation itself.

Using the height argument, one can select all maxima above a certain threshold (in this example, all non-negative maxima; this can be very useful if one has to deal with a noisy baseline; if you want to find minima, just multiply you input by -1):

import matplotlib.pyplot as plt
from scipy.misc import electrocardiogram
from scipy.signal import find_peaks
import numpy as np

x = electrocardiogram()[2000:4000]
peaks, _ = find_peaks(x, height=0)
plt.plot(x)
plt.plot(peaks, x[peaks], "x")
plt.plot(np.zeros_like(x), "--", color="gray")
plt.show()

enter image description here

Another extremely helpful argument is distance, which defines the minimum distance between two peaks:

peaks, _ = find_peaks(x, distance=150)
# difference between peaks is >= 150
print(np.diff(peaks))
# prints [186 180 177 171 177 169 167 164 158 162 172]

plt.plot(x)
plt.plot(peaks, x[peaks], "x")
plt.show()

enter image description here

It sounds like you want to find the last local maxima in the array. I.e. in your example there are two local maxima of 8 and 5. at positions 4 and 9 respectively (0 based array counting). So you are looking for an answer of 5., 9. Assuming I’ve interpreted this correctly then just grabbing the max values isn’t going to get you the answer. You need to find the maxima as the values go up and down along the vector.

You can use argrelextrema from scipy.signal to find the maxima. However it does not handle nan values without some treatment.

Assuming the nan values should not affect the outcome then you could safely replace them by interpolating between adjacent values e.g. using a simple average. e.g. in your example array you could process it to replace np.nan with (5.3 + 3)/2. Giving 4.15 (this ensures you don’t promote a nan to a minima or maxima accidentally which could happen if you assume either a very small or very large value to replace them). Once you have done this you can apply argrelextrema easily:

import numpy as np
from scipy.signal import argrelextrema
# array processed to replace nan values
b = np.array([3, np.nan, 5.3, 7., 8,5., 0, 1, 3, 5., 2.4, .1, .3, 0.5])
mask = np.isnan(data)
b[mask] = np.interp(np.flatnonzero(mask), np.flatnonzero(~mask), b[~mask])
c = argrelextrema(b, np.greater)
maxIdx = c[-1] #last element of c
maxVal = b[maxIdx]

0 / 0 / 0

Регистрация: 04.11.2022

Сообщений: 12

1

Написать программу поиска всех локальных минимумов и максимумов в списке

10.11.2022, 22:21. Показов 1116. Ответов 2


Студворк — интернет-сервис помощи студентам

Есть список целыми положительными числами, лежащими в диапазоне от 0 до 50 включительно. Написать программу поиска всех локальных
минимумов и максимумов в списке (элемент называется локальным
минимумом/максимумом, если у него нет соседей, которые меньше/больше его).



0



T0desengel

1 / 1 / 0

Регистрация: 10.11.2022

Сообщений: 2

11.11.2022, 10:51

2

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from random import randint
 
a = []
minim = []
maxim = []
n = int(input('Введите длину списка: '))
for i in range(n):
    a.append(randint(0, 50))
print(a)
for i in range(1, n - 1):
    if a[i] < a[i + 1] and a[i] < a[i - 1]:
        minim.append(a[i])
    if a[i] > a[i + 1] and a[i] > a[i - 1]:
        maxim.append(a[i])
if len(minim) == 0:
    print('Локальных минимумов нет')
else:
    print('Локальные минимумы:', minim)
if len(maxim) == 0:
    print('Локальных максимумов нет')
else:
    print('Локальные максимумы: ', maxim)



0



1125 / 294 / 74

Регистрация: 16.03.2020

Сообщений: 924

11.11.2022, 12:37

3

емае не так условие прочитал



0



Вопрос:

Можете ли вы предложить функцию модуля из numpy/scipy, которая может найти локальные максимумы/минимумы в массиве 1D numpy? Очевидно, что самый простой подход – это взглянуть на ближайших соседей, но я хотел бы иметь принятое решение, которое является частью дистрибутива numpy.

Лучший ответ:

Если вы ищете все записи в массиве 1d a меньше, чем их соседи, вы можете попробовать

numpy.r_[True, a[1:] < a[:-1]] & numpy.r_[a[:-1] < a[1:], True]

Вы также можете smooth ваш массив до этого шага с помощью numpy.convolve().

Я не думаю, что для этого есть специальная функция.

Ответ №1

В SciPy >= 0.11

import numpy as np
from scipy.signal import argrelextrema

x = np.random.random(12)

# for local maxima
argrelextrema(x, np.greater)

# for local minima
argrelextrema(x, np.less)

Производит

>>> x
array([ 0.56660112,  0.76309473,  0.69597908,  0.38260156,  0.24346445,
0.56021785,  0.24109326,  0.41884061,  0.35461957,  0.54398472,
0.59572658,  0.92377974])
>>> argrelextrema(x, np.greater)
(array([1, 5, 7]),)
>>> argrelextrema(x, np.less)
(array([4, 6, 8]),)

Обратите внимание, что это индексы x, которые являются локальными max/min. Чтобы получить значения, попробуйте:

>>> x[argrelextrema(x, np.greater)[0]]

scipy.signal также обеспечивает argrelmax и argrelmin для нахождения максимумов и минимумов соответственно.

Ответ №2

Для кривых с не слишком большим шумом я рекомендую следующий небольшой фрагмент кода:

from numpy import *

# example data with some peaks:
x = linspace(0,4,1e3)
data = .2*sin(10*x)+ exp(-abs(2-x)**2)

# that the line, you need:
a = diff(sign(diff(data))).nonzero()[0] + 1 # local min+max
b = (diff(sign(diff(data))) > 0).nonzero()[0] + 1 # local min
c = (diff(sign(diff(data))) < 0).nonzero()[0] + 1 # local max


# graphical output...
from pylab import *
plot(x,data)
plot(x[b], data[b], "o", label="min")
plot(x[c], data[c], "o", label="max")
legend()
show()

+1 важен, поскольку diff уменьшает исходный номер индекса.

Ответ №3

Другой подход (больше слов, меньше кода), который может помочь:

Расположение локальных максимумов и минимумов также является местом пересечения нуля первой производной. Как правило, гораздо легче найти пересечения нуля, чем непосредственно находить локальные максимумы и минимумы.

К сожалению, первая производная имеет тенденцию “усиливать” шум, поэтому, когда в исходных данных присутствует значительный шум, первая производная лучше всего использовать только после того, как исходные данные имеют некоторую степень сглаживания.

Поскольку сглаживание в простейшем смысле является фильтром нижних частот, сглаживание часто лучше всего (ну, что наиболее легко) выполняется с использованием ядра свертки, и “формирование” этого ядра может обеспечить удивительное количество сохраняющих функцию/повышение возможностей. Процесс нахождения оптимального ядра может быть автоматизирован с использованием различных средств, но лучшим может быть простая грубая сила (достаточно много для поиска небольших ядер). Хорошее ядро ​​будет (как и предполагалось) массивно искажать исходные данные, но не будет влиять на местоположение интересующих вас пиков/долин.

К счастью, довольно часто подходящее ядро ​​может быть создано с помощью простого SWAG ( “образованное предположение” ). Ширина сглаживающего ядра должна быть немного шире, чем самый ожидаемый “интересный” пик в исходных данных, и его форма будет напоминать этот пик (одномасштабный вейвлет). Для ядер, сохраняющих среднее значение (каким должен быть любой хороший сглаживающий фильтр) сумма элементов ядра должна быть точно равна 1.00, а ядро ​​должно быть симметричным относительно своего центра (что означает, что у него будет нечетное число элементов.

Учитывая оптимальное сглаживающее ядро ​​(или небольшое количество ядер, оптимизированных для различного содержимого данных), степень сглаживания становится фактором масштабирования для ( “усиления” ) ядра свертки.

Определение “правильной” (оптимальной) степени сглаживания (усиление ядра свертки) может быть даже автоматизировано: сравните стандартное отклонение данных первой производной со стандартным отклонением сглаженных данных. Как отношение двух стандартных отклонений изменяется с изменением степени сглаживания кулачка, чтобы предсказать эффективные значения сглаживания. Необходимо выполнить несколько ручных операций с данными (которые действительно являются репрезентативными).

Все предыдущие решения, вышеперечисленные выше, вычисляют первую производную, но они не рассматривают ее как статистическую меру и не выполняют вышеуказанные решения для выполнения функции сохранения/улучшения сглаживания (чтобы помочь тонким пикам “прыгать выше” шума).

Наконец, плохая новость: поиск “реальных” пиков становится королевской болью, когда шум также имеет функции, которые выглядят как реальные пики (перекрывающиеся полосы пропускания). Следующее более комплексное решение, как правило, должно использовать более длинное сверточное ядро ​​( “более широкую апертуру ядра” ), которое учитывает взаимосвязь между смежными “реальными” пиками (такими как минимальные или максимальные скорости для возникновения пика) или использовать множественные свертки передаются с использованием ядер разной ширины (но только в том случае, если они быстрее: фундаментальная математическая истина состоит в том, что линейные свертки, выполняемые в последовательности, всегда могут быть свернуты вместе в одну свертку). Но часто гораздо легче сначала найти последовательность полезных ядер (различной ширины) и свернуть их вместе, чем напрямую находить последнее ядро ​​за один шаг.

Надеемся, это даст достаточно информации, чтобы позволить Google (и, возможно, хороший текст статистики) заполнить пробелы. Мне очень жаль, что у меня не было времени предоставить обработанный пример или ссылку на него. Если кто-то наткнулся на один онлайн, отправьте его здесь!

Ответ №4

Почему бы не использовать встроенную функцию Scipy signal.find_peaks_cwt для выполнения этой работы?

from scipy import signal
import numpy as np

#generate junk data (numpy 1D arr)
xs = np.arange(0, np.pi, 0.05)
data = np.sin(xs)

# maxima : use builtin function to find (max) peaks
max_peakind = signal.find_peaks_cwt(data, np.arange(1,10))

# inverse  (in order to find minima)
inv_data = 1/data
# minima : use builtin function fo find (min) peaks (use inversed data)
min_peakind = signal.find_peaks_cwt(inv_data, np.arange(1,10))

#show results
print "maxima",  data[max_peakind]
print "minima",  data[min_peakind]

Результаты:

maxima [ 0.9995736]
minima [ 0.09146464]

С уважением

Ответ №5

Начиная с версии SciPy 1.1, вы также можете использовать find_peaks. Ниже приведены два примера, взятых из самой документации.

Используя аргумент height, можно выбрать все максимумы выше определенного порога (в этом примере все неотрицательные максимумы; это может быть очень полезно, если приходится иметь дело с шумной базовой линией; если вы хотите найти минимумы, просто умножьте ввод -1):

import matplotlib.pyplot as plt
from scipy.misc import electrocardiogram
from scipy.signal import find_peaks
import numpy as np

x = electrocardiogram()[2000:4000]
peaks, _ = find_peaks(x, height=0)
plt.plot(x)
plt.plot(peaks, x[peaks], "x")
plt.plot(np.zeros_like(x), "--", color="gray")
plt.show()

enter image description here

Еще один чрезвычайно полезный аргумент – это distance, которое определяет минимальное расстояние между двумя пиками:

peaks, _ = find_peaks(x, distance=150)
# difference between peaks is >= 150
print(np.diff(peaks))
# prints [186 180 177 171 177 169 167 164 158 162 172]

plt.plot(x)
plt.plot(peaks, x[peaks], "x")
plt.show()

enter image description here

Ответ №6

Update:
Я был недоволен градиентом, поэтому я нашел более надежным использование numpy.diff. Пожалуйста, дайте мне знать, если он делает то, что вы хотите.

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

import numpy as np
from matplotlib import pyplot

a=np.array([10.3,2,0.9,4,5,6,7,34,2,5,25,3,-26,-20,-29],dtype=np.float)

gradients=np.diff(a)
print gradients


maxima_num=0
minima_num=0
max_locations=[]
min_locations=[]
count=0
for i in gradients[:-1]:
count+=1

if ((cmp(i,0)>0) & (cmp(gradients[count],0)<0) & (i != gradients[count])):
maxima_num+=1
max_locations.append(count)

if ((cmp(i,0)<0) & (cmp(gradients[count],0)>0) & (i != gradients[count])):
minima_num+=1
min_locations.append(count)


turning_points = {'maxima_number':maxima_num,'minima_number':minima_num,'maxima_locations':max_locations,'minima_locations':min_locations}

print turning_points

pyplot.plot(a)
pyplot.show()

Ответ №7

Хотя этот вопрос действительно старый. Я считаю, что в numpy гораздо более простой подход (один лайнер).

import numpy as np

list = [1,3,9,5,2,5,6,9,7]

np.diff(np.sign(np.diff(list))) #the one liner

#output
array([ 0, -2,  0,  2,  0,  0, -2])

Чтобы найти локальный макс или мин, мы, по сути, хотим найти, когда разница между значениями в списке (3-1, 9-3…) изменяется от положительного к отрицательному (макс) или отрицательному к положительному (мин). Поэтому сначала мы находим разницу. Затем мы находим знак, а затем находим изменения знака, снова принимая разность. (Вроде как первая и вторая производные в исчислении, только у нас есть дискретные данные и не имеют непрерывной функции.)

Результат в моем примере не содержит экстремумов (первое и последнее значения в списке). Кроме того, как и исчисление, если вторая производная отрицательна, у вас есть max, и если она положительная, у вас есть мин.

Таким образом, мы имеем следующий матч:

[1,  3,  9,  5,  2,  5,  6,  9,  7]
[0, -2,  0,  2,  0,  0, -2]
Max     Min         Max

Ответ №8

Ни одно из этих решений не работало для меня, так как я хотел найти пики в центре повторяющихся значений. например, в

ar = np.array([0,1,2,2,2,1,3,3,3,2,5,0])

ответ должен быть

array([ 3,  7, 10], dtype=int64)

Я сделал это, используя цикл. Я знаю, что он не супер чистый, но он выполняет свою работу.

def findLocalMaxima(ar):
# find local maxima of array, including centers of repeating elements
maxInd = np.zeros_like(ar)
peakVar = -np.inf
i = -1
while i < len(ar)-1:
#for i in range(len(ar)):
i += 1
if peakVar < ar[i]:
peakVar = ar[i]
for j in range(i,len(ar)):
if peakVar < ar[j]:
break
elif peakVar == ar[j]:
continue
elif peakVar > ar[j]:
peakInd = i + np.floor(abs(i-j)/2)
maxInd[peakInd.astype(int)] = 1
i = j
break
peakVar = ar[i]
maxInd = np.where(maxInd)[0]
return maxInd

Ответ №9

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 < 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 содержат индексы минимумов и максимумов соответственно. Для огромного набора данных он даст много максим/минимумов, поэтому в этом случае сначала сгладьте кривую, а затем примените этот алгоритм.

У меня есть фрейм данных из двух столбцов, а именно х, у. Я хочу найти локальные максимумы на графике x, y, как показано на рисунке 1 прилагаемого графика. Я пошел по этому пути: преобразовал каждый столбец фрейма данных в два отдельных матричных массива. Шаг 1: Мой код сначала идентифицирует позиции индекса локальных максимумов в Y. Шаг 2: будет определено значение x, соответствующее этим позициям индекса. Вот и все. В результате я смог найти только два локальных максимума. Но есть три локальных максимума. Мой метод не может определить это. Мой вопрос: есть ли способ определить локальный максимум непосредственно из 2D-массива?

Мой настоящий код:

x = my_dataframe.iloc[:,0].values # conversion of Data frame column into an array
y = my_dataframe.iloc[:,2].values # conversion of Data frame column into an array        

# Step 1: for local maximum in y list
local_y_index = argrelextrema(y, np.greater)
print("Index position of local maximum in y = ",local_y_index[0])

# Step 2: Below code is for identifying the value of x at local maximum
local_x = x[local_mpp_index[0]]
print("value of x corresponding to local maximum in y = ",local_x)

Выход:

Index position of local maximum in y =  [105 197]
value of x corresponding to local maximum in y =  [149.21 281.06]

Мой вопрос: как показано на рисунке 1, мой вышеупомянутый подход выявил только два локальных пика. Но есть три пика. Есть ли лучший подход для определения локального максимума непосредственно из двумерного массива x и y?

x = [1.0330e-01, 1.0380e-01, 1.0430e-01, 1.0680e-01, 1.1932e-01, 1.8192e-01,
 3.6365e-01, 5.4539e-01, 7.9191e-01, 1.0384e+00, 1.3626e+00, 1.6869e+00,
 1.7438e+00, 2.0286e+00, 2.4825e+00, 2.9363e+00, 3.4787e+00, 4.0212e+00,
 4.7129e+00, 5.2137e+00, 6.0460e+00, 6.9486e+00, 7.8511e+00, 8.6835e+00,
 1.0092e+01, 1.0418e+01, 1.2153e+01, 1.3888e+01, 1.5623e+01, 1.7358e+01,
 1.9093e+01, 2.0828e+01, 2.2563e+01, 2.4298e+01, 2.6033e+01, 2.7768e+01,
 2.9503e+01, 3.1237e+01, 3.2972e+01, 3.4707e+01, 3.6442e+01, 3.8177e+01,
 3.9912e+01, 4.1647e+01, 4.3382e+01, 4.5117e+01, 4.6852e+01, 4.8587e+01,
 5.0322e+01, 5.2056e+01, 5.3791e+01, 5.5526e+01, 5.7261e+01, 5.8996e+01,
 6.0731e+01, 6.2466e+01, 6.4201e+01, 6.5936e+01, 6.7671e+01, 6.9406e+01,
 7.1141e+01, 7.2875e+01, 7.4610e+01, 7.6345e+01, 7.8080e+01, 7.9815e+01,
 8.1550e+01, 8.3285e+01, 8.5020e+01, 8.6755e+01, 8.8490e+01, 9.0225e+01,
 9.1960e+01, 9.3694e+01, 9.5429e+01, 9.7164e+01, 9.8899e+01, 1.0063e+02,
 1.0237e+02, 1.0410e+02, 1.0584e+02, 1.0757e+02, 1.0931e+02, 1.1104e+02,
 1.1278e+02, 1.1451e+02, 1.1625e+02, 1.1798e+02, 1.1972e+02, 1.2145e+02,
 1.2319e+02, 1.2492e+02, 1.2666e+02, 1.2839e+02, 1.3013e+02, 1.3186e+02,
 1.3360e+02, 1.3533e+02, 1.3707e+02, 1.3880e+02, 1.4054e+02, 1.4227e+02,
 1.4401e+02, 1.4574e+02, 1.4748e+02, 1.4921e+02, 1.5095e+02, 1.5268e+02,
 1.5442e+02, 1.5615e+02, 1.5684e+02, 1.5753e+02, 1.5789e+02, 1.5861e+02,
 1.5934e+02, 1.5962e+02, 1.6056e+02, 1.6136e+02, 1.6256e+02, 1.6309e+02,
 1.6482e+02, 1.6656e+02, 1.6829e+02, 1.7003e+02, 1.7176e+02, 1.7350e+02,
 1.7523e+02, 1.7697e+02, 1.7870e+02, 1.8044e+02, 1.8217e+02, 1.8391e+02,
 1.8564e+02, 1.8738e+02, 1.8911e+02, 1.9085e+02, 1.9258e+02, 1.9432e+02,
 1.9605e+02, 1.9779e+02, 1.9952e+02, 2.0126e+02, 2.0299e+02, 2.0473e+02,
 2.0646e+02, 2.0820e+02, 2.0993e+02, 2.1167e+02, 2.1340e+02, 2.1514e+02,
 2.1687e+02, 2.1861e+02, 2.1927e+02, 2.1993e+02, 2.2034e+02, 2.2103e+02,
 2.2172e+02, 2.2208e+02, 2.2296e+02, 2.2381e+02, 2.2493e+02, 2.2555e+02,
 2.2700e+02, 2.2728e+02, 2.2871e+02, 2.2902e+02, 2.3057e+02, 2.3075e+02,
 2.3164e+02, 2.3249e+02, 2.3422e+02, 2.3596e+02, 2.3769e+02, 2.3943e+02,
 2.4116e+02, 2.4290e+02, 2.4463e+02, 2.4637e+02, 2.4810e+02, 2.4984e+02,
 2.5157e+02, 2.5331e+02, 2.5504e+02, 2.5678e+02, 2.5851e+02, 2.6025e+02,
 2.6198e+02, 2.6371e+02, 2.6545e+02, 2.6718e+02, 2.6892e+02, 2.7065e+02,
 2.7239e+02, 2.7412e+02, 2.7586e+02, 2.7759e+02, 2.7933e+02, 2.8106e+02,
 2.8280e+02, 2.8453e+02, 2.8627e+02, 2.8800e+02, 2.8974e+02, 2.9147e+02,
 2.9321e+02, 2.9494e+02, 2.9668e+02, 2.9841e+02, 3.0015e+02, 3.0188e+02,
 3.0362e+02, 3.0535e+02, 3.0709e+02, 3.0882e+02, 3.1056e+02, 3.1229e+02,
 3.1403e+02, 3.1576e+02, 3.1749e+02, 3.1923e+02, 3.2096e+02, 3.2270e+02,
 3.2443e+02, 3.2617e+02, 3.2790e+02, 3.2964e+02, 3.3137e+02, 3.3311e+02,
 3.3484e+02, 3.3658e+02, 3.4686e+02, 3.4686e+02, 3.4686e+02, 3.4686e+02,
 3.4686e+02, 3.4686e+02, 3.4686e+02, 3.4686e+02, 3.4687e+02]

y = [4.2014e-01, 4.2237e-01, 4.2460e-01, 4.3574e-01, 4.9146e-01, 7.7004e-01,
     1.5788e+00, 2.3874e+00, 3.4842e+00, 4.5808e+00, 6.0228e+00, 7.4647e+00,
     7.7180e+00, 8.9843e+00, 1.1002e+01, 1.3020e+01, 1.5431e+01, 1.7842e+01,
     2.0916e+01, 2.3141e+01, 2.6839e+01, 3.0848e+01, 3.4856e+01, 3.8552e+01,
     4.4807e+01, 4.6254e+01, 5.3953e+01, 6.1650e+01, 6.9344e+01, 7.7035e+01,
     8.4723e+01, 9.2409e+01, 1.0009e+02, 1.0777e+02, 1.1545e+02, 1.2312e+02,
     1.3079e+02, 1.3846e+02, 1.4613e+02, 1.5379e+02, 1.6145e+02, 1.6911e+02,
     1.7677e+02, 1.8442e+02, 1.9207e+02, 1.9971e+02, 2.0735e+02, 2.1499e+02,
     2.2263e+02, 2.3027e+02, 2.3790e+02, 2.4552e+02, 2.5315e+02, 2.6077e+02,
     2.6839e+02, 2.7600e+02, 2.8361e+02, 2.9122e+02, 2.9882e+02, 3.0642e+02,
     3.1401e+02, 3.2160e+02, 3.2918e+02, 3.3676e+02, 3.4433e+02, 3.5190e+02,
     3.5946e+02, 3.6701e+02, 3.7455e+02, 3.8209e+02, 3.8961e+02, 3.9712e+02,
     4.0462e+02, 4.1211e+02, 4.1958e+02, 4.2703e+02, 4.3447e+02, 4.4188e+02,
     4.4926e+02, 4.5661e+02, 4.6393e+02, 4.7122e+02, 4.7846e+02, 4.8565e+02,
     4.9278e+02, 4.9985e+02, 5.0685e+02, 5.1376e+02, 5.2057e+02, 5.2728e+02,
     5.3386e+02, 5.4029e+02, 5.4656e+02, 5.5265e+02, 5.5852e+02, 5.6415e+02,
     5.6950e+02, 5.7453e+02, 5.7920e+02, 5.8347e+02, 5.8727e+02, 5.9056e+02,
     5.9325e+02, 5.9527e+02, 5.9654e+02, 5.9697e+02, 5.9646e+02, 5.9490e+02,
     5.9217e+02, 5.9175e+02, 5.9419e+02, 5.9665e+02, 5.9790e+02, 6.0049e+02,
     6.0309e+02, 6.0410e+02, 6.0748e+02, 6.1034e+02, 6.1467e+02, 6.1658e+02,
     6.2282e+02, 6.2905e+02, 6.3528e+02, 6.4151e+02, 6.4772e+02, 6.5393e+02,
     6.6013e+02, 6.6632e+02, 6.7251e+02, 6.7868e+02, 6.8484e+02, 6.9099e+02,
     6.9712e+02, 7.0323e+02, 7.0931e+02, 7.1536e+02, 7.2137e+02, 7.2732e+02,
     7.3320e+02, 7.3899e+02, 7.4464e+02, 7.5013e+02, 7.5540e+02, 7.6039e+02,
     7.6502e+02, 7.6922e+02, 7.7287e+02, 7.7589e+02, 7.7817e+02, 7.7962e+02,
     7.8014e+02, 7.8039e+02, 7.8250e+02, 7.8464e+02, 7.8598e+02, 7.8823e+02,
     7.9050e+02, 7.9166e+02, 7.9458e+02, 7.9739e+02, 8.0109e+02, 8.0313e+02,
     8.0793e+02, 8.0888e+02, 8.1359e+02, 8.1462e+02, 8.1978e+02, 8.2036e+02,
     8.2330e+02, 8.2610e+02, 8.3183e+02, 8.3755e+02, 8.4326e+02, 8.4897e+02,
     8.5466e+02, 8.6035e+02, 8.6602e+02, 8.7168e+02, 8.7732e+02, 8.8295e+02,
     8.8855e+02, 8.9412e+02, 8.9965e+02, 9.0513e+02, 9.1055e+02, 9.1588e+02,
     9.2110e+02, 9.2618e+02, 9.3108e+02, 9.3576e+02, 9.4015e+02, 9.4420e+02,
     9.4784e+02, 9.5100e+02, 9.5362e+02, 9.5563e+02, 9.5698e+02, 9.5761e+02,
     9.5746e+02, 9.5650e+02, 9.5468e+02, 9.5195e+02, 9.4828e+02, 9.4363e+02,
     9.3796e+02, 9.3122e+02, 9.2337e+02, 9.1437e+02, 9.0418e+02, 8.9275e+02,
     8.8004e+02, 8.6600e+02, 8.5059e+02, 8.3376e+02, 8.1546e+02, 7.9566e+02,
     7.7430e+02, 7.5134e+02, 7.2674e+02, 7.0046e+02, 6.7244e+02, 6.4266e+02,
     6.1108e+02, 5.7765e+02, 5.4234e+02, 5.0512e+02, 4.6596e+02, 4.2483e+02,
     3.8170e+02, 3.3654e+02, 6.8800e-05, 5.1500e-05, 4.8000e-05, 4.7300e-05,
     4.7200e-05, 4.7200e-05, 4.7200e-05, 4.7200e-05, 1.5520e-04]

2018-08-16 11:39

3
ответа

Вот мой наивный подход:

Шаг 1: найдите список, содержащий склоны, который +1 если два подрядy-значения растут, -1 если уменьшается и 0 если одинаковы:

import numpy as np
slope = [np.sign(y[i]-y[i-1]) for i in range(1, len(y))]

Теперь, если вы печатаете slopeбудет либо 0,1,-1 который говорит о склонах между каждыми двумя подряд y точки.

Шаг 2: Найти minimas а также maximasЯ написал этот код, который оценивает, изменяется наклон или нет. Если это изменится с 1 в -1 индекс будет сохранен как maximaиначе как minima,

x_prev = slope[0]
optima_dic={'minima':[], 'maxima':[]}
for i in range(1, len(slope)):
    if slope[i]*x_prev==-1: #slope changed
        if x_prev==1: # slope changed from 1 to -1
            optima_dic['maxima'].append(i)
        else: # slope changed from -1 to 1
            optima_dic['minima'].append(i)
        x_prev=-x_prev

и если вы печатаете результаты:

print(optima_dic)

Выход:

{'minima': [109, 237], 'maxima': [105, 197]}

Быстро и грязно:)

2018-08-16 13:09

Вы также можете использовать np.gradient работай и посмотри, где градиент меняет знак:

z = np.gradient(y, x)
i = 0
while i < len(x)-2:
if (z[i]*z[i+2]<=0 and z[i]>0): #gradient changes sign > optima, and point previous to optima has a positive slope
        print(i+1, x[i+1], y[i+1])
        i = i+1
    i+=1

plt.ylim(-1, 1)
plt.plot(x, z)

Смотря на график, кажется, что точка около 210 не является максимумом (градиент не достигает нуля). Вы можете проверить это, заменив if заявление со следующим if (y[i+1]>y[i] and y[i+1]>y[i+2]):

2018-08-16 12:31

Любой экстремум таков, что производная в экстремуме равна нулю. Поскольку у нас нет аналитического выражения для данных, следующая лучшая вещь, которую мы можем сделать, — приблизить производную. По сути, это то же самое, что брать разность в 1 шаг и искать «маленькие» значения.

Следующее работает хорошо для меня,

def find_extrema(frame, tolerance=0.5):
    diff = frame.diff()

    extrema = diff[np.abs(diff) < tolerance]

    return extrema[~np.isnan(extrema.y)]


df = pd.DataFrame(dict(y=y), index=x)

candidates = find_extrema(df)

print(candidates)

И я нахожу,

                      y
0.10380    2.230000e-03
0.10430    2.230000e-03
0.10680    1.114000e-02
0.11932    5.572000e-02
0.18192    2.785800e-01
1.74380    2.533000e-01
149.21000  4.300000e-01
156.15000 -4.200000e-01
218.61000  2.500000e-01
282.80000 -1.500000e-01
346.86000 -1.730000e-05
346.86000 -3.500000e-06
346.86000 -7.000000e-07
346.86000 -1.000000e-07
346.86000  0.000000e+00
346.86000  0.000000e+00
346.86000  0.000000e+00
346.87000  1.080000e-04

Это еще потребует некоторой очистки (в основном по краям), но, надеюсь, общая идея должна быть вам понятна.

Следующий сюжет был сделан с,

tolerance = 0.75

diff = df.diff()

ax = diff[np.abs(diff) < tolerance].y.plot(
     title="Derivative approximation for tolerance = {0}".format(tolerance))

ax.set_xlabel("x")
ax.set_ylabel("y[x] - y[x - 1]")

plt.show()

(обратите внимание на больший допуск, поэтому мы можем наблюдать некоторые линии, а не только точки)

экстремумов

2018-08-16 12:24

Понравилась статья? Поделить с друзьями:
  • Как найти залежи золота в земле
  • Как найти диагностическую карту техосмотра по базе
  • Как найти жителей в фоллаут шелтер
  • Как правильно составить протокол обще
  • Как найти связанные телефоны