Open14
測定データをフィットしたい
曲線フィット
import pandas as pd
import numpy as np
from scipy.optimize import curve_fit
f = フィット関数
xdata = X軸
ydata = Y軸
p0 = 初期パラメーター
popt, pcov = curve_fit(f, xdata, ydata, p0)
perr = np.sqrt(np.diag(pcov))
曲線フィットのオプション
-
f
,xdata
,ydata
p0=None
sigma=None
absolute_sigma=False
check_finite=None
bounds=(-inf, inf)
method=None
jac=None
*
full_output=False
nan_policy=None
**kwargs
p0: 初期パラメーター
- フィットに使う関数の数だけ、初期パラメーターを用意する
-
p0 = None
の場合、各要素が1
の初期値が適用される -
p0
に指定した値は、numpy.atleast_1dで1次元配列(ndarray
)に変換される
bounds: パラメーターの上限と下限
- デフォルトは上限/下限なし(
(-inf, inf)
) - 2要素のタプル or scipy.optimize.Boundsオブジェクト
-
p0 == None
の場合は、適当な値を設定する
if p0 is None:
p0 = _initialize_feasible(lb, ub)
method: フィットの方法
- デフォルトは
lm
- 上限/下限がある場合は
trf
bounded_problem = np.any((lb > -np.inf) | (ub < np.inf))
if method is None:
if bounded_problem:
method = 'trf'
else:
method = 'lm'
- 詳細はscipy.optimize.least_squaresを参照
-
trf
: Trust Region Reflective algorithm- particularly suitable for large sparse problems with bounds. Generally robust method.
-
dogbox
: dogleg algorithm with rectangular trust regions- typical use case is small problems with bounds
- Not recommended for problems with rank-deficient Jacobian.
-
lm
: Levenberg-Marquardt algorithm as implemented in MINPACK.- Doesn’t handle bounds and sparse Jacobians.
- Usually the most efficient method for small unconstrained problems.
lm
if method == 'lm':
# if ydata.size == 1, this might be used for broadcast.
if ydata.size != 1 and n > ydata.size:
raise TypeError(f"The number of func parameters={n} must not"
f" exceed the number of data points={ydata.size}")
res = leastsq(func, p0, Dfun=jac, full_output=1, **kwargs)
popt, pcov, infodict, errmsg, ier = res
ysize = len(infodict['fvec'])
cost = np.sum(infodict['fvec'] ** 2)
if ier not in [1, 2, 3, 4]:
raise RuntimeError("Optimal parameters not found: " + errmsg)
-
scipy.optimize.leastsqでフィット
- Minimize the sum of squares of a set of equations.
trf
else:
# Rename maxfev (leastsq) to max_nfev (least_squares), if specified.
if 'max_nfev' not in kwargs:
kwargs['max_nfev'] = kwargs.pop('maxfev', None)
res = least_squares(func, p0, jac=jac, bounds=bounds, method=method,
**kwargs)
if not res.success:
raise RuntimeError("Optimal parameters not found: " + res.message)
infodict = dict(nfev=res.nfev, fvec=res.fun)
ier = res.status
errmsg = res.message
ysize = len(res.fun)
cost = 2 * res.cost # res.cost is half sum of squares!
popt = res.x
# Do Moore-Penrose inverse discarding zero singular values.
_, s, VT = svd(res.jac, full_matrices=False)
threshold = np.finfo(float).eps * max(res.jac.shape) * s[0]
s = s[s > threshold]
VT = VT[:s.size]
pcov = np.dot(VT.T / s**2, VT)
-
scipy.optimize.least_squaresでフィット
- Solve a nonlinear least-squares problem with bounds on the variables.
-
scipy.optimise.leastsq
とは別物?- こちらのほうが新しいインターフェース?
check_finite
: 入力値のチェック
-
check_finite=True
にすると、入力した配列にinf
やnan
がないかを確認する-
inf
やnan
がある場合はValueError
になる
-
-
nan_policy
を設定していない場合ははcheck_finite=True
になる
nan_polity: NaNの扱い方
-
raise
: エラー -
omit
: NaN値を除外して計算する -
None
: なにもしない -
nan_police=None
以外にすると、check_finite=False
になる
sigma: ydataの誤差
- データの誤差を考慮してフィットする(ということ?)
if sigma is not None:
sigma = np.asarray(sigma)
-
None
orscalar
orM-length sequence
orMxM array
- 残差(residuals):
r = ydata - f(xdata, *popt)
(実データと推定値の差) - 1次元の場合:固定値 or ydataの標準偏差
# 1-D scalar
transform = 1.0 / sigma
func = _lightweight_memoizer(_wrap_func(f, xdata, ydata, transform))
- 2次元の場合:ydataの誤差の共分散行列
# 2-D scalar
# scipy.linalg.cholesky requires lower=True to return L L^T = A
transform = cholesky(sigma, lower=True)
func = _lightweight_memoizer(_wrap_func(f, xdata, ydata, transform))
absolute_sigma
-
pcov
の計算で使われる - デフォルトは
absolute_sigma=False
warn_cov = False
if pcov is None or np.isnan(pcov).any():
# indeterminate covariance
pcov = zeros((len(popt), len(popt)), dtype=float)
pcov.fill(inf)
warn_cov = True
elif not absolute_sigma:
if ysize > p0.size:
s_sq = cost / (ysize - p0.size)
pcov = pcov * s_sq
else:
pcov.fill(inf)
warn_cov = True
full_output
-
full_output=True
にすると、返り値が増える
if full_output:
return popt, pcov, infodict, errmsg, ier
else:
return popt, pcov
-
lm
の場合
if method == 'lm':
popt, pcov, infodict, errmsg, ier = res
-
lm
じゃない場合
else:
infodict = dict(nfev=res.nfev, fvec=res.fun)
ier = res.status
errmsg = res.message
popt = res.x
pcov = np.dot(VT.T / s**2, VT)
最小二乗法
- 残差(residual):
r = y_{\text{data}} - y_{\text{fit}} - 残差平方和 :
\sum_{\text{lower}}^{\text{upper}} r^{2} - 最小二乗法:
\min \left( \sum r^{2} \right)