SciPy
前回、PythonのNumPyで全ての要素が0の配列を作成する方法を紹介しました。
今回はSciPyのcurve_fitを使って、カーブフィッティングをしてみたいと思います。
今回使う曲線は2次関数でこんな感じに作ってみました。
import matplotlib.pyplot as plt
import numpy as np
x_list = range(10)
def square(x_list, a=2):
y_list = [a*x**2 for x in x_list]
return y_list
y_list = square(x_list)
fig = plt.figure()
plt.clf()
plt.scatter(x_list, y_list)
plt.show()
実行結果
それでは始めていきましょう。
curve_fitでカーブフィッティング
curve_fitでカーブフィッティングをするにはまず「scipy.optimize」から「curve_fit」をインポートします。
from scipy.optimize import curve_fit
そして「curve_fit(フィッティングする関数, フィッティングしたいX値のリスト, フィッティングしたいY値のリスト)」とします。
つまり先ほどグラフを作成した際の「square関数」が必要となります。
def square(x_list, a=2):
y_list = [a*x**2 for x in x_list]
return y_list
そして返ってくるのは最適推定値(一番確からしい値)と共分散(どれくらい確からしいか)が返ってきます。
ということでこんな感じでカーブフィッティングで最適推定値と共分散を取得します。
popt, pcov = curve_fit(square, x_list, y_list)
そして実際のフィッティングカーブを取得するには、先ほどのsquare関数のX値のリストはそのままに変数のところに「*popt」を追加します。
アスタリスクはリストをアンパックするのに用いています。
ということでグラフに出力する場合はこんな感じになります。
from scipy.optimize import curve_fit
popt, pcov = curve_fit(square, x_list, y_list)
fig = plt.figure()
plt.clf()
plt.scatter(x_list, y_list)
plt.plot(x_list, square(x_list, *popt))
plt.show()
実行結果
私がやったミス
ここで私がやって悩んだミスを紹介します。
関数をこんな感じで作り、カーブフィッティングを試してみようとしました。
def square(x_list):
y_list = [x**2 for x in x_list]
return y_list
全体的にはこんな感じのプログラムとして、実行したところエラーが出てしまいました。
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit
x_list = range(10)
def square(x_list):
y_list = [x**2 for x in x_list]
return y_list
y_list = square(x_list)
popt, pcov = curve_fit(square, x_list, y_list)
fig = plt.figure()
plt.clf()
plt.scatter(x_list, y_list)
plt.plot(x_list, square(x_list, *popt))
plt.show()
実行結果
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[3], line 13
9 return y_list
11 y_list = square(x_list)
---> 13 popt, pcov = curve_fit(square, x_list, y_list)
15 fig = plt.figure()
16 plt.clf()
File /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/scipy/optimize/_minpack_py.py:859, in curve_fit(f, xdata, ydata, p0, sigma, absolute_sigma, check_finite, bounds, method, jac, full_output, nan_policy, **kwargs)
857 args = sig.args
858 if len(args) < 2:
--> 859 raise ValueError("Unable to determine number of fit parameters.")
860 n = len(args) - 1
861 else:
ValueError: Unable to determine number of fit parameters.
どこにミスがあったのか、お気づきになられましたでしょうか?
ミスは「y_list = [x**2 for x in x_list]」にあります。
実は推測すべき変数が存在しないのです。
この式はXの値とYの値だけで完結してしまうため、フィッティングするためのパラメータがありません。
そのためエラーとなってしまいました。
次のミスで作成した関数はこんな感じでした。
def square(x, a=1):
y = a*x**2
return y
この関数を使い、全体としてはこんなプログラムを作成し、実行するとやはりエラーとなってしまいました。
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit
x_list = range(10)
def square(x, a=1):
y = a*x**2
return y
y_list = [square(x) for x in x_list]
popt, pcov = curve_fit(square, x_list, y_list)
fig = plt.figure()
plt.clf()
plt.scatter(x_list, y_list)
plt.plot(x_list, square(x_list, *popt))
plt.show()
実行結果
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[9], line 13
9 return y
11 y_list = [square(x) for x in x_list]
---> 13 popt, pcov = curve_fit(square, x_list, y_list)
15 fig = plt.figure()
16 plt.clf()
(中略)
File /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/scipy/optimize/_minpack_py.py:523, in _wrap_func.<locals>.func_wrapped(params)
522 def func_wrapped(params):
--> 523 return func(xdata, *params) - ydata
Cell In[9], line 8, in square(x, a)
7 def square(x, a=1):
----> 8 y = a*x**2
9 return y
TypeError: unsupported operand type(s) for ** or pow(): 'range' and 'int'
こちらの場合、関数が一つのX値を入れて一つのY値が返される形になっています。
curve_fitではX値のリスト、Y値のリストを入れることから、関数をX値のリストを入れて、Y値のリストが返ってくる形にしなければいけません。
この2点が私がcurve_fitを使おうと思って、特につまづいたところです。
次回はこのcurve_fitを使って、ピークフィッティングをする方法を紹介します。
ではでは今回はこんな感じです。
コメント