Алгоритм пошуку піків для Python / SciPy


136

Я можу щось написати самостійно, знайшовши нульові перетинання першої похідної чи щось таке, але здається, що функція достатньо загальна для включення в стандартні бібліотеки. Хтось знає одного?

Моє конкретне додаток - це 2D масив, але зазвичай він би використовувався для пошуку піків у FFT та ін.

Зокрема, у подібних проблемах є кілька сильних піків, а потім безліч менших "піків", які просто викликані шумом, який слід ігнорувати. Це лише приклади; не мої фактичні дані:

1-мірні піки:

Вихід FFT з піками

2-мірні піки:

Вихід трансформації радону з круговим піком

Алгоритм знаходження піків знайшов би розташування цих піків (не лише їх значення), і в ідеалі знайшов би справжній пік між вибірками, а не лише індекс з максимальним значенням, ймовірно, використовуючи квадратичну інтерполяцію чи щось таке.

Зазвичай вам цікаво лише кілька сильних вершин, тому їх або обирають, оскільки вони перевищують певний поріг, або тому, що вони є першими n вершинами упорядкованого списку, ранжированими за амплітудою.

Як я вже говорив, я знаю, як написати щось подібне самостійно. Я просто запитую, чи існує функція або пакет, який, як відомо, працює добре.

Оновлення:

Я переклав сценарій MATLAB, і він працює пристойно для 1-D справи, але може бути кращим.

Оновлено оновлення:

Sixtenbe створив кращу версію для 1-D справи.


@endolith У вас є оригінальний файл MATLAB, який ви переклали для цього на python? Дякую!
Спейси


2
Що з цього приводу: docs.scipy.org/doc/scipy/reference/generated/…
dashesy

1
@endolith Я знаю, що це питання досить давнє, але воно досить корисне;) Я провів кілька годин сьогодні вранці find_peaks, тому я додав цю відповідь, яка може бути корисною для подальшого використання. (Я впевнений, що ви це вже знайшли з 2009 року, але це стосується інших людей + себе, коли я знову через кілька років
задам

Відповіді:


74

Функція scipy.signal.find_peaks, як випливає з назви, корисна для цього. Але важливо , щоб добре зрозуміти його параметри width, threshold, distance і , перш за всеprominence , щоб отримати хорошу здобич піку.

Згідно з моїми тестами та документацією, концепція видатності - це «корисна концепція» для збереження добрих вершин та відкидання галасливих вершин.

Що таке (топографічна) видатність ? Це "мінімальна висота, необхідна для спуску, щоб дістатися з вершини на будь-яку більш високу місцевість" , як це видно тут:

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

Ідея така:

Чим більша видатність, тим "важливішим" є пік.

Тест:

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

Я спеціально використовував (шумний) синусоїду, що змінюється частотою, тому що це показує багато труднощів. Ми можемо бачити, що widthпараметр тут не дуже корисний, тому що якщо встановити мінімально widthзанадто високий рівень, він не зможе відслідковувати дуже близькі піки у високочастотній частині. Якщо ви встановите widthзанадто низький рівень, у вас буде багато небажаних піків у лівій частині сигналу. Така ж проблема і з distance. thresholdпорівнює лише з прямими сусідами, що тут не корисно. prominenceє тим, що дає найкраще рішення. Зауважте, що ви можете комбінувати багато з цих параметрів!

Код:

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

x = np.sin(2*np.pi*(2**np.linspace(2,10,1000))*np.arange(1000)/48000) + np.random.normal(0, 1, 1000) * 0.15
peaks, _ = find_peaks(x, distance=20)
peaks2, _ = find_peaks(x, prominence=1)      # BEST!
peaks3, _ = find_peaks(x, width=20)
peaks4, _ = find_peaks(x, threshold=0.4)     # Required vertical distance to its direct neighbouring samples, pretty useless
plt.subplot(2, 2, 1)
plt.plot(peaks, x[peaks], "xr"); plt.plot(x); plt.legend(['distance'])
plt.subplot(2, 2, 2)
plt.plot(peaks2, x[peaks2], "ob"); plt.plot(x); plt.legend(['prominence'])
plt.subplot(2, 2, 3)
plt.plot(peaks3, x[peaks3], "vg"); plt.plot(x); plt.legend(['width'])
plt.subplot(2, 2, 4)
plt.plot(peaks4, x[peaks4], "xk"); plt.plot(x); plt.legend(['threshold'])
plt.show()

Це те, що я після. Але чи знаєте ви будь-яку реалізацію, яка знаходить чільне місце у двовимірному масиві?
Джейсон

43

Я дивлюся на подібну проблему, і я виявив, що деякі найкращі посилання походять з хімії (від піків, що знаходяться в масових даних). Для гарного ретельного огляду найвищого алгоритму пошуку знаходження прочитайте це . Це один з найкращих чітких оглядів методів пошуку піків, які я натрапив. (Хвилянки найкращі для пошуку піків такого роду в галасливих даних.).

Схоже, ваші вершини чітко визначені і не заховані в шумі. У цьому випадку я рекомендую використовувати гладкі похідні savtizky-golay, щоб знайти вершини (Якщо ви просто розмежуєте дані вище, у вас буде помилка помилкових позитивних результатів.). Це дуже ефективна методика і досить проста у виконанні (вам потрібен матричний клас з основними операціями). Якщо ви просто знайдете нульовий перетин першої похідної SG, я думаю, ви будете щасливі.


2
Я шукав рішення загального призначення, а не таке, яке працює лише на цих образах. Я адаптував сценарій MATLAB до Python, і він працює пристойно.
ендоліт

1
Прямо на. Matlab є хорошим джерелом для алгоритмів. Яку техніку використовує сценарій? (BTW, SG - це дуже загальна мета).
Павло

2
Я пов’язав це вище. В основному це просто пошук локальних максимумів, які перевищують певний поріг вище за їх сусідів. Звичайно, є кращі методи.
ендоліт

1
@Paul Я зробив закладки на цій сторінці. IYO, підводячи підсумок, яка конкретна техніка ви вважали найкращою для цієї пікової діяльності?
Спейсі

чому нулі похідної краще, ніж просто тестування, якщо середня з трьох точок більша чи менша від двох інших. я вже застосував sg transfor, здається, додаткові витрати.
kirill_igum

20

Існує функція в scipy, scipy.signal.find_peaks_cwtяка називається підходить для ваших потреб, проте я не маю досвіду з цим, тому не можу рекомендувати ..

http://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.find_peaks_cwt.html


12
Так, цього не було, коли я запитав це, і я все ще не впевнений, як ним користуватися
endolith

1
Ви додали це деякий час тому, але це спрацювало приголомшливо. Використовувати його просто як пиріг. Просто передайте масив та інший масив (наприклад, np.arange (1,10)), який перераховує всі ширини піків, які ви хотіли б; приємна користь для фільтрування для худих або широких вершин, якщо потрібно. Знову дякую!
Майлз

15

Для тих, хто не впевнений, які алгоритми знаходження піків використовувати в Python, ось короткий огляд альтернатив: https://github.com/MonsieurV/py-findpeaks

Бажаючи собі еквівалент findpeaksфункції MatLab , я виявив, що функція detect_peaks від Маркоса Дуарте - це хороший результат.

Досить простий у використанні:

import numpy as np
from vector import vector, plot_peaks
from libs import detect_peaks
print('Detect peaks with minimum height and distance filters.')
indexes = detect_peaks.detect_peaks(vector, mph=7, mpd=2)
print('Peaks are: %s' % (indexes))

Що дасть вам:

Виявити результати


1
Оскільки ця публікація була написана, find_peaksфункція була додана до scipy.
onewhaleid

6

Виявлення піків у спектрі надійним способом було вивчено досить багато, наприклад, вся робота над синусоїдальним моделюванням музичних / аудіосигналів у 80-х роках. Шукайте "Синусоїдальне моделювання" в літературі.

Якщо ваші сигнали настільки чисті, як приклад, простий "дай мені щось з амплітудою, що перевищує N сусідів", повинен працювати досить добре. Якщо у вас є шумні сигнали, простий, але ефективний спосіб полягає в тому, щоб вчасно переглянути свої вершини, відстежити їх: ви виявите спектральні лінії замість спектральних піків. IOW, ви обчислюєте FFT на розсувному вікні вашого сигналу, щоб отримати набір спектру в часі (також називається спектрограма). Потім ви дивитеся на еволюцію спектрального піку у часі (тобто у послідовних вікнах).


Подивіться на вершини в часі? Виявити спектральні лінії? Я не впевнений, що це означає. Це буде працювати для квадратних хвиль?
ендоліт

О, ви говорите про використання STFT замість FFT. Це питання не стосується конкретно FFT; це лише приклад. Йдеться про пошук піків у будь-якому загальному 1D або 2D масиві.
ендоліт

4

Я не думаю, що те, що ви шукаєте, надає SciPy. Я б написав код сам, в цій ситуації.

Інтерполяція сплайну та вирівнювання з scipy.interpolate є досить приємною і може бути дуже корисною для встановлення піків та пошуку місця їх максимуму.


16
Вибачте, але я вважаю, що це повинен бути коментар, а не відповідь. Це просто пропонує написати його самостійно, з невиразною пропозицією щодо функцій, які можуть бути корисними (до речі, відповіді Павла набагато актуальніші).
Амі Таворі

1

Існують стандартні статистичні функції та методи пошуку людей, що не відповідають людям, які, мабуть, потрібні у першому випадку. Використання похідних вирішило би ваше друге. Я не впевнений у методі, який вирішує як безперервні функції, так і вибіркові дані.


0

По-перше, спочатку визначення "пік" є невиразним, якщо без додаткових специфікацій. Наприклад, для наступних серій ви б назвали 5-4-5 один пік чи два?

1-2-1-2-1-1-5-4-5-1-1-5-1

У цьому випадку вам знадобляться щонайменше два пороги: 1) високий поріг, лише вище якого може надзвичайне значення реєструватися як пік; і 2) низький поріг, завдяки чому екстремальні значення, розділені на малі значення нижче, стануть двома піками.

Виявлення піків - це добре вивчена тема в літературі Теорія екстремальних значень, яка також відома як "деградація екстремальних значень". Його типові програми включають виявлення небезпечних подій на основі постійного зчитування змінних довкілля, наприклад, аналіз швидкості вітру для виявлення штормових подій.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.