Peak-Finding-Algorithmus für Python / SciPy

136

Ich kann selbst etwas schreiben, indem ich Nulldurchgänge der ersten Ableitung oder etwas finde, aber es scheint eine ausreichend gemeinsame Funktion zu sein, um in Standardbibliotheken enthalten zu sein. Kennt jemand einen?

Meine spezielle Anwendung ist ein 2D-Array, aber normalerweise wird es zum Auffinden von Peaks in FFTs usw. verwendet.

Insbesondere bei solchen Problemen gibt es mehrere starke Spitzen und dann viele kleinere "Spitzen", die nur durch Rauschen verursacht werden und ignoriert werden sollten. Dies sind nur Beispiele; nicht meine tatsächlichen Daten:

1-dimensionale Peaks:

FFT-Ausgang mit Spitzen

2-dimensionale Peaks:

Radontransformationsausgang mit eingekreistem Peak

Der Peak-Finding-Algorithmus würde den Ort dieser Peaks finden (nicht nur ihre Werte) und im Idealfall den wahren Inter-Sample-Peak finden, nicht nur den Index mit dem Maximalwert, wahrscheinlich unter Verwendung einer quadratischen Interpolation oder so.

Normalerweise interessieren Sie sich nur für ein paar starke Peaks, daher werden sie entweder ausgewählt, weil sie über einem bestimmten Schwellenwert liegen, oder weil sie die ersten n Peaks einer geordneten Liste sind, sortiert nach Amplitude.

Wie gesagt, ich kann so etwas selbst schreiben. Ich frage nur, ob es eine bereits vorhandene Funktion oder ein Paket gibt, von dem bekannt ist, dass es gut funktioniert.

Aktualisieren:

Ich habe ein MATLAB-Skript übersetzt und es funktioniert für den 1-D-Fall anständig, könnte aber besser sein.

Aktualisiertes Update:

sixtenbe hat eine bessere Version für den 1-D-Fall erstellt.

Endolith
quelle
@endolith Haben Sie die ursprüngliche MATLAB-Datei, die Sie dafür in Python übersetzt haben? Vielen Dank!
Spacey
1
@endolith Ich weiß, dass diese Frage ziemlich alt ist, aber sie ist ziemlich nützlich;) Ich habe heute Morgen ein paar Stunden damit verbracht find_peaks, also habe ich diese Antwort hinzugefügt , die für zukünftige Referenz nützlich sein könnte. (Ich bin sicher, dass Sie dies bereits seit 2009 gefunden haben, aber es ist für andere Leute + mich, wenn ich mir die Frage in ein paar Jahren noch einmal
stelle

Antworten:

74

Die Funktion ist scipy.signal.find_peaks, wie der Name schon sagt, hierfür nützlich. Aber es ist wichtig , gut seine Parameter zu verstehen width, threshold, distance und vor allemprominence eine gute Spitzen Extraktion zu erhalten.

Nach meinen Tests und der Dokumentation ist das Konzept der Bekanntheit "das nützliche Konzept", um die guten Spitzen beizubehalten und die lauten Spitzen zu verwerfen.

Was ist (topografische) Bedeutung ? Es ist "die Mindesthöhe, die erforderlich ist, um vom Gipfel in ein höheres Gelände zu gelangen" , wie hier zu sehen ist:

Geben Sie hier die Bildbeschreibung ein

Die Idee ist:

Je höher der Bekanntheitsgrad, desto "wichtiger" ist der Peak.

Prüfung:

Geben Sie hier die Bildbeschreibung ein

Ich habe absichtlich eine (verrauschte) frequenzvariable Sinuskurve verwendet, da diese viele Schwierigkeiten aufweist. Wir können sehen, dass der widthParameter hier nicht sehr nützlich ist, denn wenn Sie ein Minimum widthzu hoch einstellen, kann er keine sehr engen Spitzen im Hochfrequenzteil verfolgen. Wenn Sie widthzu niedrig einstellen , haben Sie im linken Teil des Signals viele unerwünschte Spitzen. Gleiches Problem mit distance. thresholdvergleicht nur mit den direkten Nachbarn, was hier nicht sinnvoll ist. prominenceist derjenige, der die beste Lösung gibt. Beachten Sie, dass Sie viele dieser Parameter kombinieren können!

Code:

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()
Basj
quelle
Das ist es, wonach ich suche. Aber kennen Sie zufällig eine Implementierung, die in 2D-Arrays eine herausragende Rolle spielt?
Jason
43

Ich betrachte ein ähnliches Problem und habe festgestellt, dass einige der besten Referenzen aus der Chemie stammen (aus Peaks, die in Massenspezifikationsdaten gefunden wurden). Lesen Sie dies, um eine gründliche Übersicht über die Algorithmen zur Ermittlung von Spitzenwerten zu erhalten . Dies ist eine der klarsten Bewertungen von Peak-Finding-Techniken, auf die ich gestoßen bin. (Wavelets eignen sich am besten, um Peaks dieser Art in verrauschten Daten zu finden.)

Es sieht so aus, als ob Ihre Spitzen klar definiert sind und nicht im Rauschen verborgen sind. In diesem Fall würde ich empfehlen, glatte Savtizky-Golay-Derivate zu verwenden, um die Peaks zu finden (Wenn Sie nur die obigen Daten differenzieren, kommt es zu einem Durcheinander von Fehlalarmen). Dies ist eine sehr effektive Technik und ziemlich einfach zu implementieren (Sie benötigen eine Matrixklasse mit grundlegenden Operationen). Wenn Sie einfach den Nulldurchgang der ersten SG-Ableitung finden, werden Sie glücklich sein.

Paul
quelle
2
Ich suchte nach einer Allzwecklösung, die nicht nur für diese speziellen Bilder geeignet ist. Ich habe ein MATLAB-Skript an Python angepasst und es funktioniert anständig.
Endolith
1
Direkt am. Matlab ist eine gute Quelle für Algorithmen. Welche Technik verwendet das Skript? (Übrigens ist SG eine sehr allgemeine Technik).
Paul
2
Ich habe es oben verlinkt. Grundsätzlich wird nur nach lokalen Maxima gesucht, die größer als ein bestimmter Schwellenwert über ihren Nachbarn sind. Es gibt sicherlich bessere Methoden.
Endolith
1
@ Paul Ich habe diese Seite mit einem Lesezeichen versehen. IYO und zusammenfassend, welche spezielle Technik hat Ihrer Meinung nach am besten für dieses Spitzengeschäft funktioniert?
Spacey
Warum sind Nullen der Ableitung besser als nur zu testen, ob eine Mitte von drei Punkten größer oder kleiner als die anderen beiden ist? Ich habe SG Transfor bereits angewendet, scheint ein Aufpreis zu sein.
kirill_igum
20

Es gibt eine Funktion in scipy mit dem Namen, scipy.signal.find_peaks_cwtdie für Ihre Bedürfnisse geeignet klingt. Ich habe jedoch keine Erfahrung damit und kann sie daher nicht empfehlen.

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

Hanan Shteingart
quelle
12
Ja, das gab es nicht, als ich das fragte, und ich bin mir immer noch nicht sicher, wie ich es verwenden soll
Endolith
1
Sie haben dies vor einiger Zeit hinzugefügt, aber das hat fantastisch funktioniert. Die Verwendung ist kinderleicht. Übergeben Sie einfach das Array und ein anderes Array (z. B. np.arange (1,10)), in dem alle gewünschten Peaks aufgelistet sind. schöner Vorteil, nach dünnen oder breiten Spitzen zu filtern, wenn man es braucht. Danke noch einmal!
Meilen
15

Für diejenigen, die sich nicht sicher sind, welche Peak-Finding-Algorithmen in Python verwendet werden sollen, finden Sie hier einen schnellen Überblick über die Alternativen: https://github.com/MonsieurV/py-findpeaks

Ich wollte, dass ich der MatLab- findpeaksFunktion äquivalent bin, und fand, dass die Funktion detect_peaks von Marcos Duarte ein guter Haken ist.

Ziemlich einfach zu bedienen:

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))

Welches wird Ihnen geben:

detect_peaks Ergebnisse

Yoan Tournade
quelle
1
Da dieser Beitrag geschrieben wurde, wurde die find_peaksFunktion hinzugefügt scipy.
Onewhaleid
6

Die zuverlässige Erkennung von Peaks in einem Spektrum wurde eingehend untersucht, beispielsweise alle Arbeiten zur sinusförmigen Modellierung von Musik- / Audiosignalen in den 80er Jahren. Suchen Sie in der Literatur nach "Sinusmodellierung".

Wenn Ihre Signale so sauber sind wie im Beispiel, sollte ein einfaches "Gib mir etwas mit einer Amplitude höher als N Nachbarn" einigermaßen gut funktionieren. Wenn Sie verrauschte Signale haben, besteht eine einfache, aber effektive Möglichkeit darin, Ihre Peaks rechtzeitig zu betrachten und zu verfolgen: Sie erkennen dann Spektrallinien anstelle von Spektralspitzen. IOW, Sie berechnen die FFT in einem Schiebefenster Ihres Signals, um eine Reihe von zeitlichen Spektren zu erhalten (auch Spektrogramm genannt). Sie betrachten dann die zeitliche Entwicklung des Spektralpeaks (dh in aufeinanderfolgenden Fenstern).

David Cournapeau
quelle
Spitzen in der Zeit betrachten? Spektrallinien erkennen? Ich bin mir nicht sicher, was das bedeutet. Würde es für Rechteckwellen funktionieren?
Endolith
Oh, Sie sprechen von STFT anstelle von FFT. Bei dieser Frage geht es nicht speziell um FFTs. Das ist nur ein Beispiel. Es geht darum, die Peaks in einem allgemeinen 1D- oder 2D-Array zu finden.
Endolith
4

Ich glaube nicht, dass SciPy das bietet, wonach Sie suchen. In dieser Situation würde ich den Code selbst schreiben.

Die Spline-Interpolation und die Glättung von scipy.interpolate sind sehr hilfreich und können sehr hilfreich sein, um Spitzen anzupassen und dann die Position ihres Maximums zu ermitteln.

Eric O Lebigot
quelle
16
Ich entschuldige mich, aber ich denke, dass dies ein Kommentar sein sollte, keine Antwort. Es wird nur vorgeschlagen, es selbst zu schreiben, mit einem vagen Vorschlag für Funktionen, die nützlich sein könnten (die in Pauls Antwort sind übrigens viel relevanter).
Ami Tavory
1

Es gibt statistische Standardfunktionen und -methoden zum Auffinden von Ausreißern von Daten, die Sie wahrscheinlich im ersten Fall benötigen. Die Verwendung von Derivaten würde Ihre zweite lösen. Ich bin mir jedoch nicht sicher, ob eine Methode sowohl kontinuierliche Funktionen als auch abgetastete Daten löst.

Null Zeiger
quelle
0

Das Wichtigste zuerst: Die Definition von "Peak" ist vage, wenn auch ohne weitere Angaben. Würden Sie beispielsweise für die folgende Serie 5-4-5 einen oder zwei Peaks nennen?

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

In diesem Fall benötigen Sie mindestens zwei Schwellenwerte: 1) einen hohen Schwellenwert nur oberhalb dessen ein Extremwert als Peak registriert werden kann; und 2) eine niedrige Schwelle, so dass Extremwerte, die durch kleine Werte darunter getrennt sind, zwei Spitzen werden.

Die Peakerkennung ist ein gut untersuchtes Thema in der Literatur zur Extremwerttheorie, das auch als "Deklarieren von Extremwerten" bezeichnet wird. Zu seinen typischen Anwendungen gehört das Identifizieren von Gefahrenereignissen auf der Grundlage kontinuierlicher Ablesungen von Umgebungsvariablen, z. B. das Analysieren der Windgeschwindigkeit, um Sturmereignisse zu erkennen.

Ian Liu
quelle