Python / SciPyのピーク検出アルゴリズム


136

一次導関数などのゼロクロッシングを見つけることで自分で何かを書くことができますが、標準ライブラリに含めるには十分に一般的な関数のようです。誰か知ってる?

私の特定のアプリケーションは2Dアレイですが、通常はFFTのピークを見つけるためなどに使用されます。

具体的には、これらの種類の問題では、複数の強いピークがあり、無視すべきノイズだけが原因で発生する多数の小さな「ピーク」があります。これらは単なる例です。私の実際のデータではありません:

1次元ピーク:

ピークのあるFFT出力

2次元ピーク:

丸で囲まれたピークを持つラドン変換出力

ピーク検出アルゴリズムは、これらのピークの位置(それらの値だけでなく)を見つけ、理想的には、おそらく2次補間などを使用して、最大値のインデックスだけでなく、真のサンプル間ピークを見つけます。

通常、気になるのは数個の強いピークだけなので、特定のしきい値を超えているため、または振幅でランク付けされた順序付きリストの最初のn個のピークであるために選択されます。

私が言ったように、私はこのようなものを自分で書く方法を知っています。うまく機能することが知られている既存の関数またはパッケージがあるかどうかを尋ねています。

更新:

はMATLABスクリプト翻訳しましたが、それは1次元の場合にうまく機能しますが、もっと良いかもしれません。

更新された更新:

sixtenbe は1-Dケースのより良いバージョン作成しました


@endolithこのためにPythonに翻訳した元のMATLABファイルはありますか?ありがとう!
Spacey



1
@endolithこの質問はかなり古いですが、かなり役に立ちます;)私は今朝に数時間費やしたfind_peaksので、将来の参考に役立つかもしれないこの回答を追加しました。(2009年以降、あなたはこれをすでに見つけていると思いますが、数年後にもう一度質問するときは、他の人+私自身のためです!)
Basj

回答:


74

scipy.signal.find_peaksその名前が示すように、関数はこれに役立ちます。しかし、それはよくそのパラメータを理解することが重要だwidththresholddistance そして何よりもprominence良好なピーク抽出を取得します。

私のテストとドキュメントによると、卓越性の概念は、良好なピークを維持し、ノイズの多いピークを破棄するための「有用な概念」です。

(地形)目立ちとは何ですか?それは、「任意の高い地形に頂上から取得するために下降するために必要な最小の高さ」、それはここで見られるように、:

ここに画像の説明を入力してください

アイデアは:

目立つほど、ピークはより「重要」になります。

テスト:

ここに画像の説明を入力してください

(ノイズの多い)周波数が変化する正弦波を意図的に使用しました。width最小値をwidth高く設定しすぎると、高周波部分の非常に近いピークを追跡できなくなるため、このパラメーターはあまり役に立たないことがわかります。width低く設定しすぎると、信号の左側に不要なピークが多数発生します。と同じ問題distancethresholdここでは役に立ちませんが、直接隣人と比較するだけです。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()

これは私が求めているものです。しかし、2D配列で目立つものを見つけた実装はありますか?
Jason

43

私は同様の問題を調べていますが、最良の参照のいくつかは化学からのものであることがわかりました(質量分析データのピークの発見から)。ピーク検出アルゴリズムの完全なレビューについては、こちらをお読みください。これは、私が遭遇したピーク検出テクニックの最も明確なレビューの1つです。(ウェーブレットは、ノイズの多いデータでこの種のピークを見つけるのに最適です。)

ピークが明確に定義されており、ノイズに隠れていないようです。そのため、スムーズなsavtizky-golay導関数を使用してピークを見つけることをお勧めします(上記のデータを区別するだけで、誤検知が発生します)。これは非常に効果的な手法であり、実装は非常に簡単です(基本的な操作を伴う行列クラスが必要です)。最初のSG導関数のゼロクロスを見つけただけで幸せになると思います。


2
私は、これらの特定の画像でのみ機能するソリューションではなく、汎用のソリューションを探していました。私は、MATLABスクリプトをPythonに適合させ、ちゃんと動作しました。
内部石

1
右に。Matlabはアルゴリズムの良い情報源です。スクリプトはどのような手法を使用していますか?(ところで、SGは非常に汎用的な手法です)。
ポール

2
上でリンクしました。基本的には、隣人より上の特定のしきい値よりも大きい極大値を検索します。確かにより良い方法があります。
内部石

1
@Paul私はそのページをブックマークしました。IYO、そして要約すると、このピッキングピッキングビジネスに最も効果的だったテクニックは何だと思いますか?
Spacey、

3つのポイントの真ん中が他の2つのポイントよりも大きいか小さいかをテストするよりも、導関数のゼロが優れている理由 私はすでに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

私自身がMatLab findpeaks関数と同等のものを求めているので、Marcos Duarteの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))

これはあなたに与えるでしょう:

detect_peaksの結果


1
この投稿が作成されたため、find_peaks関数がに追加されましたscipy
onewhaleid

6

信頼できる方法でスペクトルのピークを検出することは、かなり研究されてきました。たとえば、80年代の音楽/オーディオ信号の正弦波モデリングに関するすべての作業です。文献で「正弦波モデリング」を探します。

信号が例のようにきれいである場合、単純な「N近傍よりも大きい振幅を持つ何かを私に与えてください」はかなりうまくいくはずです。ノイズの多い信号がある場合、単純ですが効果的な方法は、時間内にピークを確認して追跡することです。その後、スペクトルピークの代わりにスペクトル線を検出します。IOW、信号のスライディングウィンドウでFFTを計算し、一連のスペクトル(スペクトログラムとも呼ばれます)を取得します。次に、時間の経過に伴う(つまり、連続するウィンドウでの)スペクトルピークの変化を確認します。


時間のピークを見ますか?スペクトル線を検出しますか?どういう意味かわかりません。方形波で機能しますか?
内部石

ああ、あなたはFFTの代わりにSTFTを使うことについて話している。この質問は、特にFFTに関するものではありません。これは単なる例です。これは、一般的な1Dまたは2Dアレイのピークを見つけることです。
内部石

4

あなたが探しているものがSciPyによって提供されているとは思いません。この状況では、自分でコードを記述します。

スプライン補間とscipy.interpolateからのスムージングは​​非常に優れており、ピークをフィッティングして最大値の場所を見つけるのに非常に役立ちます。


16
申し訳ありませんが、これはコメントではなく、回答であると思います。それは自分でそれを書くことを提案するだけであり、役に立つかもしれない機能について漠然とした提案をしています(ポールの答えにあるものは偶然にはるかに関連性があります)。
Ami Tavory

1

データの外れ値を見つけるための標準的な統計関数と方法があり、これはおそらく最初のケースで必要なものです。デリバティブを使用すると、2番目を解決します。ただし、連続関数とサンプリングされたデータの両方を解決する方法はわかりません。


0

まず最初に、「ピーク」の定義は、それ以上の仕様がなければ曖昧です。たとえば、次のシリーズの場合、5-4-5を1ピークまたは2ピークと呼びますか?

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

この場合、少なくとも2つのしきい値が必要です。1)極値がピークとして記録できる、それを超える高しきい値。2)しきい値が低いため、その下の小さな値で区切られた極値が2つのピークになります。

ピーク検出は、極値理論の文献でよく研究されているトピックであり、「極値の非クラスター化」としても知られています。その典型的なアプリケーションには、嵐のイベントを検出するために風速を分析するなど、環境変数の継続的な読み取りに基づいて危険イベントを識別することが含まれます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.