Dapatkah Anda menyarankan fungsi modul dari numpy / scipy yang dapat menemukan maxima / minima lokal dalam array numpy 1D? Jelas pendekatan paling sederhana adalah dengan melihat tetangga terdekat, tetapi saya ingin memiliki solusi yang diterima yang merupakan bagian dari distro numpy.
116
Jawaban:
Jika Anda mencari semua entri dalam larik 1d yang
a
lebih kecil dari tetangganya, Anda dapat mencobanyaAnda juga bisa menghaluskan larik Anda sebelum langkah ini menggunakan
numpy.convolve()
.Saya rasa tidak ada fungsi khusus untuk ini.
sumber
<
dengan>
akan memberi Anda maksima lokal alih-alih minima[False False]
Apa yang bisa menjadi masalah di sini?Dalam SciPy> = 0.11
Menghasilkan
Catatan, ini adalah indeks x yang merupakan maks / menit lokal. Untuk mendapatkan nilainya, coba:
scipy.signal
juga menyediakanargrelmax
danargrelmin
untuk menemukan masing-masing maxima dan minima.sumber
np.random.random(12)
menghasilkan 12 nilai acak, mereka digunakan untuk mendemonstrasikan fungsinyaargrelextrema
.test02=np.array([10,4,4,4,5,6,7,6])
, maka itu tidak berfungsi. Itu tidak mengakui nilai-nilai berurutan sebagai minimum lokal.Untuk kurva dengan noise yang tidak terlalu banyak, saya merekomendasikan potongan kode kecil berikut:
Ini
+1
penting, karenadiff
mengurangi nomor indeks asli.sumber
[1, 2, 2, 3, 3, 3, 2, 2, 1]
, maksima lokal jelas berada di antara 3 di tengah. Tetapi jika Anda menjalankan fungsi yang Anda berikan, Anda mendapatkan maksimas pada indeks 2,6 dan minimal pada indeks 1,3,5,7, yang bagi saya tidak masuk akal.+1
alih-alihnp.diff()
digunakannp.gradient()
.Pendekatan lain (lebih banyak kata, lebih sedikit kode) yang mungkin membantu:
Lokasi maksimum dan minimum lokal juga merupakan lokasi penyeberangan nol dari turunan pertama. Secara umum, jauh lebih mudah untuk menemukan penyeberangan nol daripada menemukan langsung maksima dan minimum lokal.
Sayangnya, turunan pertama cenderung "memperkuat" derau, jadi ketika derau yang signifikan hadir dalam data asli, turunan pertama paling baik digunakan hanya setelah data asli menerapkan beberapa tingkat penghalusan.
Karena penghalusan, dalam arti yang paling sederhana, filter lolos rendah, penghalusan sering kali paling baik (baik, paling mudah) dilakukan dengan menggunakan kernel konvolusi, dan "membentuk" kernel tersebut dapat memberikan jumlah yang mengejutkan dari kemampuan mempertahankan / meningkatkan fitur . Proses menemukan kernel yang optimal dapat diotomatiskan menggunakan berbagai cara, tetapi yang terbaik mungkin adalah kekerasan sederhana (sangat cepat untuk menemukan kernel kecil). Kernel yang baik akan (sebagaimana dimaksud) secara besar-besaran mendistorsi data asli, tetapi TIDAK akan mempengaruhi lokasi puncak / lembah yang diinginkan.
Untungnya, sering kali kernel yang sesuai dapat dibuat melalui SWAG sederhana ("tebakan secara cerdas"). Lebar kernel penghalus harus sedikit lebih lebar dari puncak terlebar yang diharapkan "menarik" dalam data asli, dan bentuknya akan menyerupai puncak itu (wavelet berskala tunggal). Untuk kernel yang menjaga rata-rata (filter penghalus yang bagus), jumlah elemen kernel harus sama persis dengan 1,00, dan kernel harus simetris dengan bagian tengahnya (artinya akan memiliki jumlah elemen ganjil.
Mengingat kernel penghalusan yang optimal (atau sejumlah kecil kernel yang dioptimalkan untuk konten data yang berbeda), tingkat penghalusan menjadi faktor penskalaan untuk ("perolehan") kernel konvolusi.
Menentukan derajat pemulusan yang "benar" (optimal) (penguatan kernel konvolusi) bahkan dapat diotomatiskan: Bandingkan deviasi standar data turunan pertama dengan deviasi standar data yang dihaluskan. Bagaimana rasio dari dua deviasi standar berubah dengan perubahan tingkat penghalusan cam digunakan untuk memprediksi nilai penghalusan yang efektif. Beberapa data manual yang dijalankan (yang benar-benar representatif) seharusnya menjadi semua yang dibutuhkan.
Semua solusi sebelumnya yang diposting di atas menghitung turunan pertama, tetapi solusi di atas tidak memperlakukannya sebagai ukuran statistik, juga tidak solusi di atas mencoba melakukan pelestarian fitur / peningkatan penghalusan (untuk membantu puncak halus "melompati" kebisingan).
Akhirnya, berita buruknya: Menemukan puncak yang "nyata" menjadi masalah besar ketika kebisingan juga memiliki fitur yang terlihat seperti puncak nyata (bandwidth yang tumpang tindih). Solusi yang lebih kompleks berikutnya umumnya menggunakan kernel konvolusi yang lebih panjang ("bukaan kernel yang lebih lebar") yang memperhitungkan hubungan antara puncak "nyata" yang berdekatan (seperti kecepatan minimum atau maksimum untuk kejadian puncak), atau menggunakan beberapa lintasan konvolusi menggunakan kernel yang memiliki lebar berbeda (tetapi hanya jika lebih cepat: merupakan kebenaran matematika fundamental bahwa konvolusi linier yang dilakukan secara berurutan selalu dapat digabung menjadi satu konvolusi tunggal). Tetapi seringkali jauh lebih mudah untuk terlebih dahulu menemukan urutan kernel yang berguna (dengan lebar yang bervariasi) dan menggabungkannya bersama-sama daripada mencari langsung kernel akhir dalam satu langkah.
Mudah-mudahan ini memberikan info yang cukup untuk membiarkan Google (dan mungkin teks statistik yang bagus) mengisi kekosongan. Saya sangat berharap saya punya waktu untuk memberikan contoh yang berhasil, atau tautan ke salah satunya. Jika ada yang menemukannya secara online, silakan posting di sini!
sumber
Mulai SciPy versi 1.1, Anda juga dapat menggunakan find_peaks . Di bawah ini adalah dua contoh yang diambil dari dokumentasi itu sendiri.
Dengan menggunakan
height
argumen, seseorang dapat memilih semua maksima di atas ambang tertentu (dalam contoh ini, semua maksima non-negatif; ini bisa sangat berguna jika seseorang harus berurusan dengan baseline yang berisik; jika Anda ingin mencari minimum, cukup kalikan masukan Anda oleh-1
):Argumen lain yang sangat membantu adalah
distance
, yang mendefinisikan jarak minimum antara dua puncak:sumber
Mengapa tidak menggunakan fungsi signal.find_peaks_cwt Scipy built-in untuk melakukan pekerjaan itu?
hasil:
Salam
sumber
Pembaruan: Saya tidak senang dengan gradien jadi saya merasa lebih dapat diandalkan untuk digunakan
numpy.diff
. Tolong beri tahu saya jika itu sesuai dengan keinginan Anda.Berkaitan dengan masalah kebisingan, masalah matematisnya adalah mencari letak maxima / minima jika kita ingin melihat noise kita dapat menggunakan sesuatu seperti convolve yang telah disebutkan sebelumnya.
sumber
Padahal pertanyaan ini sangat tua. Saya percaya ada pendekatan yang jauh lebih sederhana di numpy (satu liner).
Untuk menemukan maks atau min lokal, kami pada dasarnya ingin menemukan ketika perbedaan antara nilai-nilai dalam daftar (3-1, 9-3 ...) berubah dari positif ke negatif (maks) atau negatif ke positif (min). Oleh karena itu, pertama kita temukan perbedaannya. Lalu kita temukan tandanya, lalu kita temukan perubahan tanda itu dengan mengambil perbedaannya lagi. (Semacam turunan pertama dan kedua dalam kalkulus, hanya kami yang memiliki data diskrit dan tidak memiliki fungsi kontinu.)
Output dalam contoh saya tidak mengandung extrema (nilai pertama dan terakhir dalam daftar). Juga, seperti kalkulus, jika turunan keduanya negatif, Anda memiliki nilai maks, dan jika positif Anda memiliki nilai min.
Jadi kami memiliki pertarungan berikut:
sumber
Tak satu pun dari solusi ini berhasil untuk saya karena saya juga ingin menemukan puncak di tengah nilai yang berulang. misalnya, di
ar = np.array([0,1,2,2,2,1,3,3,3,2,5,0])
jawabannya seharusnya
Saya melakukan ini menggunakan loop. Saya tahu ini tidak super bersih, tetapi menyelesaikan pekerjaan.
sumber
minm
danmaxm
masing-masing berisi indeks minimal dan maksimal. Untuk kumpulan data yang sangat besar, itu akan memberikan banyak maksimas / minimas sehingga dalam hal ini menghaluskan kurva terlebih dahulu dan kemudian menerapkan algoritma ini.sumber
Solusi lain yang pada dasarnya menggunakan operator dilatasi:
dan untuk minima:
Juga, dari
scipy.ndimage
Anda dapat menggantirank_filter(x, -1, size=3)
dengangrey_dilation
danrank_filter(x, 0, size=3)
dengangrey_erosion
. Ini tidak memerlukan jenis lokal, jadi ini sedikit lebih cepat.sumber
Yang lainnya:
sumber