【SciPy】curve_fitを用いてカーブフィッティングする方法[Python]

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

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を使って、ピークフィッティングをする方法を紹介します。

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

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

コメント

コメントする

目次