Algoritma pencari puncak untuk Python / SciPy


136

Saya dapat menulis sesuatu sendiri dengan menemukan nol-penyilangan dari turunan pertama atau sesuatu, tetapi sepertinya fungsi yang cukup umum untuk dimasukkan dalam perpustakaan standar. Adakah yang tahu?

Aplikasi khusus saya adalah array 2D, tetapi biasanya akan digunakan untuk menemukan puncak di FFT, dll.

Secara khusus, dalam masalah seperti ini, ada beberapa puncak yang kuat, dan kemudian banyak "puncak" yang lebih kecil yang hanya disebabkan oleh kebisingan yang harus diabaikan. Ini hanya contoh; bukan data aktual saya:

Puncak 1 dimensi:

Output FFT dengan puncak

Puncak 2 dimensi:

Radon mengubah output dengan puncak yang dilingkari

Algoritma penemuan-puncak akan menemukan lokasi puncak-puncak ini (bukan hanya nilainya), dan idealnya akan menemukan puncak antar-sampel yang sebenarnya, bukan hanya indeks dengan nilai maksimum, mungkin menggunakan interpolasi kuadrat atau sesuatu.

Biasanya Anda hanya peduli tentang puncak yang kuat beberapa, sehingga mereka akan baik dipilih karena mereka di atas ambang tertentu, atau karena mereka yang pertama n puncak daftar ordered, berdasarkan peringkat amplitudo.

Seperti yang saya katakan, saya tahu bagaimana menulis sesuatu seperti ini sendiri. Saya hanya bertanya apakah ada fungsi atau paket yang sudah ada sebelumnya yang berfungsi dengan baik.

Memperbarui:

Saya menerjemahkan skrip MATLAB dan berfungsi dengan baik untuk kasus 1-D, tetapi bisa lebih baik.

Pembaruan yang diperbarui:

sixtenbe menciptakan versi yang lebih baik untuk case 1-D.


@endolith Apakah Anda memiliki file MATLAB asli yang Anda terjemahkan ke python untuk ini? Terima kasih!
Spacey



1
@endolith Saya tahu pertanyaan ini cukup lama, tetapi cukup berguna;) Saya menghabiskan beberapa jam pagi ini find_peaks, jadi saya menambahkan jawaban ini yang mungkin berguna untuk referensi di masa mendatang. (Saya yakin Anda sudah menemukan ini sejak 2009 tetapi untuk orang lain + saya sendiri ketika saya akan mengajukan pertanyaan lagi kepada diri saya dalam beberapa tahun!)
Basj

Jawaban:


74

Fungsi scipy.signal.find_peaks, seperti namanya, berguna untuk ini. Tapi itu penting untuk memahami dengan baik parameter width, threshold, distance dan di atas semuaprominence untuk mendapatkan ekstraksi puncak yang baik.

Menurut tes dan dokumentasi saya, konsep menonjol adalah "konsep yang berguna" untuk menjaga puncak yang baik, dan membuang puncak yang bising.

Apa yang menonjol (topografi) ? Ini adalah "ketinggian minimum yang diperlukan untuk turun dari puncak ke medan yang lebih tinggi" , seperti yang dapat dilihat di sini:

masukkan deskripsi gambar di sini

Idenya adalah:

Semakin tinggi keunggulannya, semakin "penting" puncaknya.

Uji:

masukkan deskripsi gambar di sini

Saya menggunakan sinusoid (noise) yang bervariasi-frekuensi dengan sengaja karena menunjukkan banyak kesulitan. Kita dapat melihat bahwa widthparameter tidak terlalu berguna di sini karena jika Anda menetapkan minimum widthterlalu tinggi, maka itu tidak akan dapat melacak puncak yang sangat dekat di bagian frekuensi tinggi. Jika Anda menetapkan widthterlalu rendah, Anda akan memiliki banyak puncak yang tidak diinginkan di bagian kiri sinyal. Masalah yang sama dengan distance. thresholdhanya membandingkan dengan tetangga langsung, yang tidak berguna di sini. prominenceadalah orang yang memberikan solusi terbaik. Perhatikan bahwa Anda dapat menggabungkan banyak parameter ini!

Kode:

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

Inilah yang saya cari. Tapi apakah Anda mengetahui implementasi yang menemukan keunggulan dalam array 2D?
Jason

43

Saya melihat masalah yang sama, dan saya telah menemukan beberapa referensi terbaik berasal dari kimia (dari puncak yang ditemukan dalam data massa-spesifikasi). Untuk ulasan menyeluruh yang baik tentang algoritma pencarian puncak, baca ini . Ini adalah salah satu ulasan paling jelas terbaik dari teknik penemuan puncak yang pernah saya jumpai. (Wavelet adalah yang terbaik untuk menemukan puncak semacam ini dalam data berisik.).

Sepertinya puncak Anda didefinisikan dengan jelas dan tidak disembunyikan dalam kebisingan. Karena itu saya sarankan menggunakan derivatif savtizky-golay yang halus untuk menemukan puncak (Jika Anda hanya membedakan data di atas Anda akan memiliki kekacauan positif palsu.). Ini adalah teknik yang sangat efektif dan sangat mudah diimplementasikan (Anda perlu kelas matriks dengan operasi dasar). Jika Anda hanya menemukan zero crossing dari derivatif SG pertama, saya pikir Anda akan senang.


2
Saya mencari solusi tujuan umum, bukan solusi yang hanya bekerja pada gambar-gambar tertentu. Saya mengadaptasi skrip MATLAB ke Python dan berfungsi dengan baik.
endolith

1
Tepat. Matlab adalah sumber yang baik untuk algoritma. Teknik apa yang digunakan skrip? (BTW, SG adalah teknik tujuan yang sangat umum).
Paul

2
Saya menautkannya di atas. Ini pada dasarnya hanya mencari maxima lokal yang lebih besar dari batas tertentu di atas tetangga mereka. Tentu ada metode yang lebih baik.
endolith

1
@ Paul, saya menandai halaman itu. IYO dan secara ringkas, teknik spesifik apa yang menurut Anda paling baik untuk bisnis pemetik puncak ini?
Spacey

mengapa nol turunan lebih baik daripada hanya menguji jika tengah dari tiga poin lebih besar atau lebih kecil dari dua lainnya. Saya sudah menerapkan sg transfor, sepertinya biaya tambahan.
kirill_igum

20

Ada fungsi dalam nama scipy scipy.signal.find_peaks_cwtyang kedengarannya cocok untuk kebutuhan Anda, namun saya tidak memiliki pengalaman dengannya jadi saya tidak bisa merekomendasikan ..

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


12
Ya, itu tidak ada ketika saya menanyakan hal ini, dan saya masih tidak yakin bagaimana menggunakannya
endolith

1
Anda menambahkan ini beberapa waktu yang lalu, tetapi ini bekerja dengan luar biasa. Menggunakannya sederhana seperti pai. Masukkan saja array, dan array lain (mis. Np.arange (1,10)) yang mencantumkan semua lebar puncak yang Anda inginkan; manfaat bagus untuk menyaring puncak kurus atau lebar jika diperlukan. Terima kasih lagi!
Miles

15

Bagi mereka yang tidak yakin tentang algoritma pencarian-puncak mana yang akan digunakan dalam Python, di sini ikhtisar cepat alternatif: https://github.com/MonsieurV/py-findpeaks

Menginginkan diri saya setara dengan findpeaksfungsi MatLab , saya telah menemukan bahwa fungsi detect_peaks dari Marcos Duarte adalah tangkapan yang bagus.

Cukup mudah digunakan:

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

Yang akan memberi Anda:

detect_peaks hasil


1
Sejak posting ini ditulis, find_peaksfungsi ditambahkan ke scipy.
onewhaleid

6

Mendeteksi puncak dalam spektrum dengan cara yang dapat diandalkan telah dipelajari sedikit, misalnya semua pekerjaan pada pemodelan sinusoidal untuk sinyal musik / audio di tahun 80-an. Cari "Pemodelan Sinusoidal" dalam literatur.

Jika sinyal Anda sebersih contoh, sederhana "beri saya sesuatu dengan amplitudo lebih tinggi dari tetangga N" harus bekerja dengan baik. Jika Anda memiliki sinyal bising, cara sederhana namun efektif adalah dengan melihat puncak waktu Anda, untuk melacaknya: Anda kemudian mendeteksi garis spektral dan bukan puncak spektral. TKI, Anda menghitung FFT pada jendela geser sinyal Anda, untuk mendapatkan satu set spektrum waktu (juga disebut spektrogram). Anda kemudian melihat evolusi puncak spektral dalam waktu (yaitu di jendela berturut-turut).


Lihatlah puncak waktu? Deteksi garis spektral? Saya tidak yakin apa artinya ini. Apakah ini akan bekerja untuk gelombang persegi?
endolith

Oh, Anda sedang berbicara tentang menggunakan STFT, bukan FFT. Pertanyaan ini bukan tentang FFT secara khusus; itu hanya sebuah contoh. Ini tentang menemukan puncak dalam array 1D atau 2D umum.
endolith

4

Saya tidak berpikir bahwa apa yang Anda cari disediakan oleh SciPy. Saya akan menulis kode sendiri, dalam situasi ini.

Interpolasi spline dan smoothing dari scipy.interpolasi cukup bagus dan mungkin cukup membantu dalam pemasangan puncak dan kemudian menemukan lokasi maksimum mereka.


16
Saya minta maaf, tapi saya pikir ini seharusnya komentar, bukan jawaban. Itu hanya menyarankan untuk menulisnya sendiri, dengan saran samar untuk fungsi-fungsi yang mungkin berguna (yang ada dalam jawaban Paul jauh lebih relevan, kebetulan).
Ami Tavory

1

Ada fungsi statistik standar dan metode untuk menemukan pencilan data, yang mungkin merupakan yang Anda butuhkan dalam kasus pertama. Menggunakan turunan akan memecahkan masalah Anda yang kedua. Saya tidak yakin untuk metode yang memecahkan fungsi kontinu dan data sampel.


0

Hal pertama yang pertama, definisi "puncak" tidak jelas jika tanpa spesifikasi lebih lanjut. Misalnya, untuk seri berikut, akankah Anda menelepon 5-4-5 satu atau dua puncak?

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

Dalam hal ini, Anda memerlukan setidaknya dua ambang batas: 1) ambang batas tinggi hanya di atas yang dapat mendaftarkan nilai ekstrim sebagai puncak; dan 2) ambang rendah sehingga nilai ekstrem yang dipisahkan oleh nilai kecil di bawahnya akan menjadi dua puncak.

Deteksi puncak adalah topik yang dipelajari dengan baik dalam literatur Teori Nilai Ekstrim, juga dikenal sebagai "declustering of extreme values". Aplikasi umumnya termasuk mengidentifikasi peristiwa bahaya berdasarkan pembacaan berkelanjutan variabel lingkungan misalnya menganalisis kecepatan angin untuk mendeteksi peristiwa badai.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.