I want to fit the function
f(x) = b+a/x
x = np.asarray(range(20,401,20))
y = np.random.rand(20)
params = np.array([1,1])
res = least_squares(funinv, params, args=(x, y))
return np.atleast_1d(fun(x, *args, **kwargs))
TypeError: funinv() takes 1 positional argument but 3 were given
To make a little of clarity. There are two related problems:
To fit a model to observed data is to find such parameters of a model which minimize some sort of error between model data and observed data.
least_squares method just minimizes a following function with respect to
x can be a vector).
F(x) = 0.5 * sum(rho(f_i(x)**2), i = 0, ..., m - 1)
rho is a loss function and default is
rho(x) = x so don't mind it for now)
least_squares(func, x0) expects that call to
func(x) will return a vector
[a1, a2, a3, ...] for which a sum of squares will be computed:
S = 0.5 * (a1^2 + a2^2 + a3^2 + ...).
least_squares will tweak
x0 to minimize
Thus, in order to use it to fit model to data, one must construct a function of error between a model and actual data - residuals and then minimize that residuals function. In your case you can write it as follows:
import numpy as np from scipy.optimize import least_squares x = np.asarray(range(20,401,20)) y = np.random.rand(20) params = np.array([1,1]) def funcinv(x, a, b): return b + a/x def residuals(params, x, data): # evaluates function given vector of params [a, b] # and return residuals: (observed_data - model_data) a, b = params func_eval = funcinv(x, a, b) return (data - func_eval) res = least_squares(residuals, params, args=(x, y))
This gives a result:
... message: '`gtol` termination condition is satisfied.' nfev: 4 njev: 4 optimality: 5.6774618339971994e-10 status: 1 success: True x: array([ 6.89518618, 0.37118815])
However, as a residuals function pretty much the same all the time (
res = observed_data - model_data), there is a shortcut in
curve_fit(func, xdata, ydata, x0).
curve_fit builds residuals function automatically and you can simply write:
import numpy as np from scipy.optimize import curve_fit x = np.asarray(range(20,401,20)) y = np.random.rand(20) params = np.array([1,1]) def funcinv(x, a, b): return b + a/x res = curve_fit(funcinv, x, y, params) print(res) # ... array([ 6.89518618, 0.37118815]), ...