可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am trying to fit some data that I have using scipy.optimize.curve_fit.
My fit function is:
def fitfun(x, a):
return np.exp(a*(x - b))
What i want is to define a
as the fitting parameter, and b
as a parameter that changes depending on the data I want to fit. This means that for one set of data I would want to fit the function: np.exp(a*(x - 10))
while for another set I would like to fit the function np.exp(a*(x - 20))
. In principle, I would like the parameter b to be passed in as any value.
The way I am currently calling curve_fit is:
coeffs, coeffs_cov = curve_fit(fitfun, xdata, ydata)
But what I would like would be something like this:
b=10
coeffs, coeffs_cov = curve_fit(fitfun(b), xdata, ydata)
b=20
coeffs2, coeffs_cov2 = curve_fit(fitfun(b), xdata, ydata)
So that I get the coefficient a for both cases (b=10 and b=20).
I am new to python so I cannot make it work, even though I have tried to read the documentation. Any help would be greatly appreciated.
回答1:
Let me also recommend lmfit (http://lmfit.github.io/lmfit-py/) and its Model class for this type of problem. Lmfit provides a higher-level abstraction for curve fitting and optimization problems.
With lmfit, each parameter in the model becomes an object that can be fixed, varied freely, or given upper and lower bounds without changing the fitting function. In addition, you can define multiple "independent variables" for any model.
That gives you two possible approaches. First, define parameters and fix b
:
from lmfit import Model
def fitfun(x, a, b):
return np.exp(a*(x - b))
# turn this model function into a Model:
mymodel = Model(fitfun)
# create parameters with initial values. Note that parameters are
# **named** according to the arguments of your model function:
params = mymodel.make_params(a=1, b=10)
# tell the 'b' parameter to not vary during the fit
params['b'].vary = False
# do fit
result = mymodel.fit(ydata, params, x=xdata)
print(result.fit_report())
The params
is not changed in the fit (updated params are in result.params
), so to fit another set of data, you could just do:
params['b'].value = 20 # Note that vary is still False
result2 = mymodel.fit(ydata2, params, x=xdata2)
An alternative approach would be to define b
as an independent variable:
mymodel = Model(fitfun, independent_vars=['x', 'b'])
params = mymodel.make_params(a=1)
result = model.fit(ydata, params, x=xdata, b=10)
Lmfit has many other nice features for curve-fitting including composing complex models and evaluation of confidence intervals.
回答2:
I don't know if this is the "proper" way of doing things, but I usually wrap my function in a class, so that I can access parameters from self
. Your example would then look like:
class fitClass:
def __init__(self):
pass
def fitfun(self, x, a):
return np.exp(a*(x - self.b))
inst = fitClass()
inst.b = 10
coeffs, coeffs_cov = curve_fit(inst.fitfun, xdata, ydata)
inst.b = 20
coeffs, coeffs_cov = curve_fit(inst.fitfun, xdata, ydata)
This approach avoids using global parameters, which are generally considered evil.
回答3:
You can define b
as a global variable inside the fit function.
from scipy.optimize import curve_fit
def fitfun(x, a):
global b
return np.exp(a*(x - b))
xdata = np.arange(10)
#first sample data set
ydata = np.exp(2 * (xdata - 10))
b = 10
coeffs, coeffs_cov = curve_fit(fitfun, xdata, ydata)
print(coeffs)
#second sample data set
ydata = np.exp(5 * (xdata - 20))
b = 20
coeffs, coeffs_cov = curve_fit(fitfun, xdata, ydata)
print(coeffs)
Output:
[2.]
[5.]
回答4:
UPDATE:
Apologies for posting the untested code. As pointed out by @mr-t , the code indeed throws an error. It seems , the kwargs argument of the curve_fit function is to set the keywords arguments of leastsq
and least_squares
functions and not the keyword arguments of fit function itself.
In this case, in addition to answer proposed by others, another possible solution is to redefine the fit function to return the error and directly call the leastsq
function which allows to pass the arguments.
def fitfun(a,x,y,b):
return np.exp(a*(x - b)) - y
b=10
leastsq(fitfun,x0=1,args=(xdata,ydata,b))