【SciPy】find_peaksを使って極大値、極小値、ゼロ交差点を取得する方法[Python]

  • URLをコピーしました!
目次

SciPy

前回、PythonのPandasでデータフレームをcsv、tsvファイルとして保存する方法と読み込む方法を紹介しました。

今回はSciPyのfind_peaksを使って、極大値(上向のピーク)、極小値(下向きのピーク)、その両方とゼロ交差点を取得する方法を紹介します。

ちなみにfind_peaksはこちらの記事で解説していますので、よかったらどうぞ。

今回はこのfind_peaksの使い方という感じです。

それでは始めていきましょう。

おさらい:極大値(上のピーク)の取得方法

まずはおさらいとして通常の使い方、極大値(上向のピーク)の取得方法です。

「from scipy.signal import find_peaks」でライブラリをインポートし、「peaks, _ = find_peaks(グラフのY値)」でピークのインデックスが取得できます。

今回はとりあえずsin波で試してみようと、こんなプログラムを作ってみました。

from scipy.signal import find_peaks
import numpy as np
import matplotlib.pyplot as plt

x = range(1800)
y = [np.sin(np.radians(x_val)) for x_val in x]

fig = plt.plot()
plt.clf()

plt.plot(x, y)

plt.show()

実行結果

このsin波に対して極大値を取得し、プロットしてみます。

from scipy.signal import find_peaks
import numpy as np
import matplotlib.pyplot as plt

x = range(1800)
y = [np.sin(np.radians(x_val)) for x_val in x]

peaks, _ = find_peaks(y)
print(peaks)

peak_x_list = [x[i] for i in peaks]
peak_y_list = [y[i] for i in peaks]

fig = plt.plot()
plt.clf()

plt.plot(x, y)
plt.scatter(peak_x_list, peak_y_list, color="red")

plt.show()

実行結果
[  90  450  810 1170 1530]

print関数で出力した値はピークのインデックスです。

それを元にX軸方向の値、Y軸方向の値を取得して、グラフ化しました。

極小値(下向きのピーク)の取得方法

次に極小値(下向きのピーク)を取得してみます。

先ほどのfind_peaks()で極大値を取得できるため、グラフ全体に「-1」を掛けて上下反転させてやることで極小値を極大値に変えて、ピーク検出します。

from scipy.signal import find_peaks
import numpy as np
import matplotlib.pyplot as plt

x = range(1800)
y = [np.sin(np.radians(x_val)) for x_val in x]

peaks, _ = find_peaks(-1*np.array(y))
peak_x_list = [x[i] for i in peaks]
peak_y_list = [y[i] for i in peaks]

fig = plt.plot()
plt.clf()

plt.plot(x, y)
plt.scatter(peak_x_list, peak_y_list, color="red")

plt.show()

実行結果
[ 270  630  990 1350 1710]

極大値、極小値を取得する方法

上記2つの方法を組み合わせて取得することで極大値と極小値を取得することができます。

ただし極大値と極小値のピークをそれぞれ別に取得することになるため、一つのリストにまとめ、さらにグラフの左からの順に並べるといった作業が必要になります。

ここではピークを取得したのち、2つのピークリストを「list(peaks)」リストに変換したのち(np.arrayになっているため)結合し、さらに「sorted()」で昇順に並び替えしています。

from scipy.signal import find_peaks
import numpy as np
import matplotlib.pyplot as plt

x = range(1800)
y = [np.sin(np.radians(x_val)) for x_val in x]

peaks_top, _ = find_peaks(y)
peaks_bottom, _ = find_peaks(-1*np.array(y))

peaks = sorted(list(peaks_top) + list(peaks_bottom))
print(peaks)

peak_x_list = [x[i] for i in peaks]
peak_y_list = [y[i] for i in peaks]

fig = plt.plot()
plt.clf()

plt.plot(x, y)
plt.scatter(peak_x_list, peak_y_list, color="red")

plt.show()

実行結果
[90, 270, 450, 630, 810, 990, 1170, 1350, 1530, 1710]

また今回のsin波のように0を挟んで極大値と極小値が交互に現れる場合、単純に絶対値を取ってしまっても、全ての極大値、極小値を一度に取ることができます。

from scipy.signal import find_peaks
import numpy as np
import matplotlib.pyplot as plt

x = range(1800)
y = [np.sin(np.radians(x_val)) for x_val in x]

peaks, _ = find_peaks(abs(np.array(y)))
print(peaks)

peak_x_list = [x[i] for i in peaks]
peak_y_list = [y[i] for i in peaks]

fig = plt.plot()
plt.clf()

plt.plot(x, y)
plt.scatter(peak_x_list, peak_y_list, color="red")

plt.show()

実行結果
[  90  270  450  630  810  990 1170 1350 1530 1710]

制限があるものの手軽に極大値、極小値を取ることができるので覚えておいて損はないでしょう。

ゼロ交差点の取得

ゼロ交差点を取得する方法は前にこちらの記事で解説をしています。

ただ今回のfind_peaksを使ってもゼロ交差点を取得できるので紹介します。

まずグラフの絶対値を取得します。

これにより0より下のグラフが上に移動することから、ゼロ点が極小値になります。

そしてグラフに「-1」を掛けることにより、極小値であったゼロ点が極大値に変わります。

その極大値を「find_peaks()」で検出するというわけです。

from scipy.signal import find_peaks
import numpy as np
import matplotlib.pyplot as plt

x = range(1800)
y = [np.sin(np.radians(x_val)) for x_val in x]

peaks, _ = find_peaks(-1*abs(np.array(y)))
print(peaks)

peak_x_list = [x[i] for i in peaks]
peak_y_list = [y[i] for i in peaks]

fig = plt.plot()
plt.clf()

plt.plot(x, y)
plt.scatter(peak_x_list, peak_y_list, color="red")
plt.plot(x, -1*abs(np.array(y)), ls="--")

plt.show()

実行結果
[ 180  360  540  720  900 1080 1260 1440 1620]

橙色の点線が絶対値を取得し「-1」を掛けたグラフですが、見事にゼロ点が極大値になっていることが分かります。

このようにちょっとした発想の転換から簡単に目的を達成できるとなかなか爽快感があります。

次回はmatplotlibでX軸やY軸の数値を反転させる方法を紹介します。

ではでは今回はこんな感じで。

よかったらシェアしてね!
  • URLをコピーしました!

コメント

コメントする

目次