Python / SciPy için pik bulma algoritması


136

İlk türev veya bir şeyin sıfır geçişlerini bularak kendim bir şeyler yazabilirim, ancak standart kütüphanelere dahil edilecek yeterli ortak bir işlev gibi görünüyor. Birini bilen var mı?

Benim özel uygulama bir 2D dizisidir, ancak genellikle FFT'lerde zirve bulmak için kullanılır.

Özellikle, bu tür problemlerde, birden fazla güçlü tepe noktası vardır ve daha sonra sadece göz ardı edilmesi gereken gürültüden kaynaklanan daha küçük “tepe noktaları” vardır. Bunlar sadece örnektir; gerçek verilerim değil:

1 boyutlu zirveler:

Tepe noktalarına sahip FFT çıkışı

2 boyutlu pikler:

Dairesel tepe ile radon dönüşüm çıkışı

Zirve bulma algoritması, bu piklerin (sadece değerlerinin değil) yerini bulur ve ideal olarak, sadece kuadratik enterpolasyon veya bir şey kullanarak, sadece maksimum değere sahip indeksi değil, gerçek numuneler arası zirveyi bulur .

Tipik olarak sadece birkaç güçlü zirveye önem veriyorsunuz, bu yüzden ya belirli bir eşiğin üstünde oldukları için ya da sıralı bir listenin genliğe göre sıralanan ilk n zirveleri oldukları için seçileceklerdi .

Dediğim gibi, böyle bir şeyi nasıl yazacağımı biliyorum. Sadece iyi çalıştığı bilinen önceden var olan bir işlev veya paket olup olmadığını soruyorum.

Güncelleme:

Ben bir MATLAB komut dosyası tercüme ve 1-D durumu için adam gibi çalışır, ancak daha iyi olabilir.

Güncelleme:

sixtenbe 1-B durumu için daha iyi bir versiyon yarattı .


@endolith Bunun için python'a çevirdiğiniz orijinal MATLAB dosyanız var mı? Teşekkürler!
Spacey



1
@endolith Bu sorunun oldukça eski olduğunu biliyorum, ama oldukça yararlı;) Bu sabah birkaç saat geçirdim find_peaks, bu yüzden gelecekteki referans için yararlı olabilecek bu cevabı ekledim . (Bunu 2009'dan beri zaten bulduğunuzdan eminim ama birkaç yıl içinde kendime tekrar soru sorduğumda diğer insanlar + kendim için!)
Basj

Yanıtlar:


74

İşlev scipy.signal.find_peaks, adından da anlaşılacağı gibi, bunun için yararlıdır. Ama iyi parametrelerini anlamak önemlidir width, threshold, distance ve her şeyden önceprominence iyi bir zirve çıkarımı alır.

Testlerime ve belgelere göre, önem kavramı, iyi zirveleri tutmak ve gürültülü zirveleri atmak için "yararlı konsept" tir.

Nedir (topografik) önem ? Öyle "gerekli minimum yükseklik herhangi bir yüksek araziye zirveden almak için inmek için" burada görülebileceği gibi,:

resim açıklamasını buraya girin

Fikir:

Önem ne kadar yüksek olursa, zirve o kadar "önemli" olur.

Ölçek:

resim açıklamasını buraya girin

Amaç olarak (gürültülü) frekans değiştiren sinüsoid kullandım çünkü birçok zorluk gösteriyor. Burada widthparametrenin çok kullanışlı olmadığını görebiliriz, çünkü minimum widthçok yüksek ayarlarsanız , yüksek frekans kısmında çok yakın zirveleri izleyemez. widthÇok düşük ayarlarsanız , sinyalin sol tarafında birçok istenmeyen tepe noktasına sahip olursunuz. İle aynı sorun distance. thresholdsadece burada yararlı olmayan doğrudan komşularıyla karşılaştırır. prominenceen iyi çözümü veren olandır. Bu parametrelerin birçoğunu birleştirebileceğinizi unutmayın!

Kod:

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

Bu benim peşimdeyim. Ama 2D dizide ön plana çıkan herhangi bir uygulamayı biliyor musunuz?
Jason

43

Benzer bir soruna bakıyorum ve en iyi referanslardan bazılarının kimyadan geldiğini gördüm (kütle spesifikasyon verilerinde bulunan zirvelerden). Zirve bulma algoritmalarının kapsamlı bir incelemesi için bunu okuyun . Bu, karşılaştığım tepe bulma tekniklerinin en iyi incelemelerinden biridir. (Dalgacıklar gürültülü verilerde bu tür zirveleri bulmak için en iyisidir.).

Görünüşe göre zirveleriniz açıkça tanımlanmış ve gürültüde gizli değil. Bu durumda, zirveleri bulmak için pürüzsüz savtizky-golay türevleri kullanmanızı tavsiye ederim (Yukarıdaki verileri sadece farklılaştırırsanız, yanlış pozitif bir karışıklığa sahip olacaksınız.). Bu çok etkili bir tekniktir ve uygulanması oldukça kolaydır (temel işlemlerle bir matris sınıfına ihtiyacınız vardır). İlk SG türevinin sıfır geçişini bulursanız mutlu olacağını düşünüyorum.


2
Sadece bu görüntüler üzerinde çalışan bir çözüm değil, genel amaçlı bir çözüm arıyordum. Bir MATLAB betiğini Python'a uyarladım ve düzgün çalışıyor.
endolith

1
Kesinlikle doğru. Matlab algoritmalar için iyi bir kaynaktır. Senaryo hangi tekniği kullanıyor? (BTW, SG çok genel amaçlı bir tekniktir).
Paul

2
Yukarıda bağladım. Temel olarak sadece komşularının üzerinde belirli bir eşikten daha büyük olan yerel maksimumları arar. Kesinlikle daha iyi yöntemler var.
endolith

1
@ Paul Bu sayfaya yer işareti koydum. IYO ve özet olarak, bu pik toplama işi için en iyi hangi tekniğin işe yaradığını düşündünüz?
Spacey

neden türev sıfırları, üç noktadan bir ortasının diğer ikisinden daha büyük veya daha küçük olup olmadığını test etmekten daha iyidir. Ben zaten sg transfor uyguladı, ekstra bir maliyet gibi görünüyor.
kirill_igum

20

Scipy'de scipy.signal.find_peaks_cwtseslerin ihtiyaçlarınız için uygun olduğu adlandırılan bir işlev var, ancak bununla ilgili deneyimim yok, bu yüzden tavsiye edemem ..

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


12
Evet, bunu sorduğumda yoktu ve hala nasıl kullanılacağından emin değilim
endolith

1
Bunu bir süre önce ekledin, ama bu harika çalıştı. Pasta gibi basit kullanmak. Diziyi ve istediğiniz tüm pik genişliklerini listeleyen başka bir diziyi (yani. Np.arange (1,10)) iletmeniz yeterlidir; gerekirse sıska veya geniş tepeler için filtre için güzel bir fayda. Tekrar teşekkürler!
Miles

15

Python'da hangi zirve bulma algoritmalarının kullanılacağından emin olmayanlar için, alternatiflere hızlı bir genel bakış: https://github.com/MonsieurV/py-findpeaks

Kendimi MatLab findpeaksişlevine eşdeğer isteyen , Marcos Duarte'den tespit_peaks işlevinin iyi bir yakalama olduğunu buldum .

Kullanımı oldukça kolay:

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

Hangi size verecektir:

sonuçları tespit et


1
Bu yazı yazıldığından beri, find_peaksişlev eklendi scipy.
onewhaleid

6

Bir spektrumda zirveleri güvenilir bir şekilde tespit etmek biraz çalışılmıştır, örneğin 80'lerde müzik / ses sinyalleri için sinüzoidal modelleme üzerindeki tüm çalışmalar. Literatürde "Sinüzoidal Modelleme" yi arayın.

Sinyalleriniz örnek kadar temizse, basit bir "bana N komşularından daha yüksek genliğe sahip bir şey verin" makul şekilde iyi çalışmalıdır. Gürültülü sinyalleriniz varsa, basit ama etkili bir şekilde zirvelerinize zamanında bakmak, onları izlemek: daha sonra spektral zirveler yerine spektral çizgileri tespit edersiniz. IOW, zaman içinde bir dizi spektrum elde etmek için (spektrogram olarak da bilinir) FFT sinyalinizin kayan bir penceresinde hesaplarsınız. Daha sonra spektral zirvenin zaman içindeki evrimine bakarsınız (yani ardışık pencerelerde).


Zaman içinde zirvelere mi bakıyorsunuz? Spektral çizgileri algılansın mı? Bunun ne anlama geldiğinden emin değilim. Kare dalgalar için işe yarar mı?
endolith

Oh, FFT yerine STFT kullanmaktan bahsediyorsun. Bu soru özellikle FFT'lerle ilgili değildir; bu sadece bir örnek. Herhangi bir genel 1D veya 2D dizideki zirveleri bulmakla ilgilidir.
endolith

4

Aradığınız şeyin SciPy tarafından sağlandığını düşünmüyorum. Bu durumda kodu kendim yazardım.

Spline enterpolasyonu ve scipy.interpolate'den yumuşatma oldukça güzeldir ve zirveleri yerleştirmek ve daha sonra maksimum konumlarını bulmakta oldukça yardımcı olabilir.


16
Özür dilerim, ama bunun bir cevap değil, bir yorum olması gerektiğini düşünüyorum. Yararlı olabilecek işlevler için belirsiz bir öneri ile sadece kendi başına yazmayı önerir (Paul'un cevabındaki olanlar tesadüfen çok daha alakalı).
Ami Tavory

1

Verilere aykırı değer bulmak için standart istatistiksel işlevler ve yöntemler vardır, bu muhtemelen ilk durumda ihtiyacınız olan şeydir. Türev kullanmak ikincinizi çözecektir. Ancak sürekli fonksiyonları ve örneklenmiş verileri çözen bir yöntem için emin değilim.


0

İlk olarak, daha fazla spesifikasyon olmadan "tepe" tanımı belirsizdir. Örneğin, aşağıdaki seri için 5-4-5'e bir veya iki tane mi çağırırsınız?

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

Bu durumda, en az iki eşik değerine ihtiyacınız olacaktır: 1) sadece yukarıda yüksek bir eşik değer pik olarak kaydedilebilir; ve 2) düşük bir eşik, böylece altında küçük değerlerle ayrılan aşırı değerler iki tepe olacak.

Tepe tespiti, "Aşırı değerlerin azaltılması" olarak da bilinen Aşırı Değer Teorisi literatüründe iyi çalışılmış bir konudur. Tipik uygulamaları, çevresel değişkenlerin sürekli okumalarına dayanan tehlike olaylarının tanımlanmasını, örneğin fırtına olaylarını tespit etmek için rüzgar hızının analizini içerir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.