Reputation: 113
I am trying to use lmfit, but getting sporadic results for the parameters:
import numpy as np
import scipy.stats as sp
from scipy.optimize import curve_fit
from lmfit import minimize, Parameters, Parameter, report_fit
x = [0.01,
0.02,
0.03,
0.04,
0.05,
0.06,
0.07,
0.08,
0.09,
0.1,
0.2,
0.3,
0.4,
0.5,
0.6,
0.7,
0.8,
0.9,
0.99999999,]
#some paramters to try to estimate
sigma1 = 6
scale1 = np.exp(5)
#generate values to use to fit
y = sp.lognorm(sigma1,scale=scale1).ppf(x)
#function set-up to use in lmfit
def invlognorm(params,x,data):
sigma = params['sigma']
mu = params['mu']
model = sp.lognorm(sigma,scale=mu).ppf(x)
return model - data
params = Parameters()
params.add('sigma', value= 1,)
params.add('mu', value= 1, )
# do fit, here with leastsq model
result = minimize(invlognorm,params, method = 'least-squares',args=(x, y))
and finally checking the results
result.params.pretty_print()
Name Value Min Max Stderr Vary Expr Brute_Step
mu 2.161 -inf inf None True None None
sigma 6.754 -inf inf None True None None
but these are nowhere near the original values.
Any help on what's going on here and how I can fix this so it gives reasonable results?
Upvotes: 0
Views: 1692
Reputation: 7862
You will almost certainly need better starting values for the sigma
and mu
parameters.
The lognorm().ppf()
function diverges at x=1
, giving huge values which will completely dominate any measure of misfit such as chi-square.
In addition, small changes in parameter values will have essentially no effect on the total misfit, and all fitting algorithms will quickly give up. The huge value at x=1
will also make any fit insensitive to the other data. Perhaps you actually meant some other method of lognorm
such pdf
or cdf
?
If not, you may want to fit "in log space" -- fit the log of your data to the log of the model. That will reduce the importance of the x=1
datum.
Also, though it is not the cause of the problem, your fit did not actually use the leastsq
method as your comment says. To use the leastsq
(Levenberg-Marquardt method) use:
# do fit, here with leastsq model
result = minimize(invlognorm, params, args=(x, y))
To use scipy.optimize.least_squares
(which actually use trust region reflective use
# do fit, here with least_squares model
result = minimize(invlognorm,params, method='least_squares', args=(x, y))
(note spelling. Your example used least-squares
which is not recognized, and so causes the Nelder-Mead method to be used).
Upvotes: 2