SciPy
前回、PythonのPandasでデータフレームからデータを抽出し、concatを使って連結させる場合に注意することを紹介しました。
今回はSciPyを使ってSavitzky-Golay法によるデータの平滑化、一次微分、二次微分の方法を紹介します。
Savitzky-Golay法はデータのある区間を多項式で近似します。
近似式とすることでデータの平滑化ができ、また微分も可能にします。
また多項式で近似するデータの区間は少しずつ移動していくことから移動平均の一種(重み付き移動平均)として、ノイズが多いデータの解析に広く使われています。
今回はそのSavitzky-Golay法をPythonのSciPyでやってみようというお話です。
まずはノイズ付きの信号データをガウス関数を使って作ってみました。
import numpy as np
import matplotlib.pyplot as plt
import random
x_min = 0
x_max = 100
noise_level = 0.02
def gauss_noise(x_list, a=1, m=0, s=1):
y_list = [a * np.exp(-(x - m)**2 / (2*s**2)) + random.uniform(-noise_level, noise_level) for x in x_list]
return y_list
x_list = np.arange(x_min, x_max, 1)
parameter = [1, (x_min+x_max)/2, 2]
y_list = gauss_noise(x_list, parameter[0], parameter[1], parameter[2])
fig = plt.figure()
plt.clf()
plt.plot(x_list, y_list)
plt.show()
実行結果
このプログラムでは「x_min」と「x_max」の中間にピークをもつデータを作成します。
またその際、「noise_level」で指定した比率でランダムノイズが追加されます。
def gauss_noise(x_list, a=1, m=0, s=1):
y_list = [a * np.exp(-(x - m)**2 / (2*s**2)) + random.uniform(-noise_level, noise_level) for x in x_list]
return y_list
パラメータを指定しているのはこちらです。
parameter = [1, (x_min+x_max)/2, 2]
それでは始めていきましょう。
Savitzky-Golay法によるデータの平滑化
まずはSavitzky-Golay法によるデータの平滑化を試してみます。
「SciPyのsignal」をインポートし、「signal.savgol_filter(Y値のリスト, 多項式を計算する点の数, 多項式の次数, deriv=0)」とします。
まずは多項式の次数2、多項式を計算するデータ数5として試してみます。
import numpy as np
import matplotlib.pyplot as plt
import random
#----------この部分を追加----------
from scipy import signal
#----------この部分を追加----------
x_min = 0
x_max = 100
noise_level = 0.02
#----------この部分を追加----------
degree = 2
window = 5
#----------この部分を追加----------
def gauss_noise(x_list, a=1, m=0, s=1):
y_list = [a * np.exp(-(x - m)**2 / (2*s**2)) + random.uniform(-noise_level, noise_level) for x in x_list]
return y_list
x_list = np.arange(x_min, x_max, 1)
parameter = [1, (x_min+x_max)/2, 2]
y_list = gauss_noise(x_list, parameter[0], parameter[1], parameter[2])
#----------この部分を追加----------
yma_list = signal.savgol_filter(y_list, window, degree, deriv=0)
#----------この部分を追加----------
fig = plt.figure()
plt.clf()
plt.plot(x_list, y_list)
#----------この部分を追加----------
plt.plot(x_list, yma_list)
#----------この部分を追加----------
plt.show()
多項式を計算するデータ数を増やすと、データが平滑化されますが、やりすぎると元の形から大きく変わってしまいます。
import numpy as np
import matplotlib.pyplot as plt
import random
from scipy import signal
x_min = 0
x_max = 100
noise_level = 0.02
degree = 2
#----------この部分を変更----------
window = 25
#----------この部分を変更----------
def gauss_noise(x_list, a=1, m=0, s=1):
y_list = [a * np.exp(-(x - m)**2 / (2*s**2)) + random.uniform(-noise_level, noise_level) for x in x_list]
return y_list
x_list = np.arange(x_min, x_max, 1)
parameter = [1, (x_min+x_max)/2, 2]
y_list = gauss_noise(x_list, parameter[0], parameter[1], parameter[2])
yma_list = signal.savgol_filter(y_list, window, degree, deriv=0)
fig = plt.figure()
plt.clf()
plt.plot(x_list, y_list)
plt.plot(x_list, yma_list)
plt.show()
実行結果
多項式の次数を大きくすると元のデータにより合いやすくなり、平滑化されなくなります。
import numpy as np
import matplotlib.pyplot as plt
import random
from scipy import signal
x_min = 0
x_max = 100
noise_level = 0.02
#----------この部分を変更----------
degree = 4
#----------この部分を変更----------
window = 5
def gauss_noise(x_list, a=1, m=0, s=1):
y_list = [a * np.exp(-(x - m)**2 / (2*s**2)) + random.uniform(-noise_level, noise_level) for x in x_list]
return y_list
x_list = np.arange(x_min, x_max, 1)
parameter = [1, (x_min+x_max)/2, 2]
y_list = gauss_noise(x_list, parameter[0], parameter[1], parameter[2])
yma_list = signal.savgol_filter(y_list, window, degree, deriv=0)
fig = plt.figure()
plt.clf()
plt.plot(x_list, y_list)
plt.plot(x_list, yma_list)
plt.show()
Savitzky-Golay法によるデータの微分
次にSavitzky-Golay法によるデータの微分を試してみましょう。
データの微分をするには先ほどの「signal.savgol_filter(Y値のリスト, 多項式を計算する点の数, 多項式の次数, deriv=0)」の「deriv=0」の数値を微分したい回数に変えます。
つまり「deriv=1」なら1次微分、「deriv=2」なら2次微分というわけです。
import numpy as np
import matplotlib.pyplot as plt
import random
from scipy import signal
x_min = 0
x_max = 100
noise_level = 0.02
degree = 2
window = 5
def gauss_noise(x_list, a=1, m=0, s=1):
y_list = [a * np.exp(-(x - m)**2 / (2*s**2)) + random.uniform(-noise_level, noise_level) for x in x_list]
return y_list
x_list = np.arange(x_min, x_max, 1)
parameter = [1, (x_min+x_max)/2, 2]
y_list = gauss_noise(x_list, parameter[0], parameter[1], parameter[2])
#----------この部分を変更----------
yma_list = signal.savgol_filter(y_list, window, degree, deriv=1)
#----------この部分を変更----------
fig = plt.figure()
plt.clf()
plt.plot(x_list, y_list)
plt.plot(x_list, yma_list)
plt.show()
実行結果
import numpy as np
import matplotlib.pyplot as plt
import random
from scipy import signal
x_min = 0
x_max = 100
noise_level = 0.02
degree = 2
window = 5
def gauss_noise(x_list, a=1, m=0, s=1):
y_list = [a * np.exp(-(x - m)**2 / (2*s**2)) + random.uniform(-noise_level, noise_level) for x in x_list]
return y_list
x_list = np.arange(x_min, x_max, 1)
parameter = [1, (x_min+x_max)/2, 2]
y_list = gauss_noise(x_list, parameter[0], parameter[1], parameter[2])
#----------この部分を変更----------
yma_list = signal.savgol_filter(y_list, window, degree, deriv=2)
#----------この部分を変更----------
fig = plt.figure()
plt.clf()
plt.plot(x_list, y_list)
plt.plot(x_list, yma_list)
plt.show()
実行結果
次回はSciPyを使ってガウス分布(正規分布)のグラフを描く方法を紹介します。
ではでは今回はこんな感じで。
コメント