Reputation: 113
I am currently trying to fit by data using the curvefit() function in python. The shape should be a upside down 'hump' like shape. However this is giving me a parabola looking shape. Here is the code and a picture. Any help would be much appreciated![1]: https://i.sstatic.net/fmRBn.png
def model(x, a, p,q):
return a*np.exp(p*x+q*x**2)
# Input data
x = np.array([11, 11, 11,15,15,15,20,20,20,25,25,25,29,29,29])
y = np.array([2.048, 1.56, 1.18, 2.6116,2.35,2.1036,2.97, 2.97, 2.97, 2.463,2.05,1.6679,1.825,1.0939,0.534])
[enter image description here][1]
# Fit
popt, pcov = curve_fit(model, x, y)
# prepare some data for a plot
xx = np.linspace(-20, 60)
yy = model(xx, *popt)
plt.plot(x, y, 'o', xx, yy)
plt.title('Exponential Fit')
plt.ylim(0,5)
plt.xlim(-5,30)
plt.grid()
plt.show()
print(popt)
Upvotes: 1
Views: 871
Reputation: 114811
curve_fit
(like many iterative fitting and optimization methods) performs best when it is given a reasonable starting point. The default initial guess for curve_fit
is all 1s, which is a very bad guess for your problem--warnings are generated, overflow occurs, and the returned pcov
is an array of all inf
values (did you check it?).
With a little trial-and-error, I was able to get what looks like a reasonable fit by using p0=[0.1, 0.1, -0.001]
:
In [123]: popt, pcov = curve_fit(model, x, y, p0=[0.1, 0.1, -0.001])
In [124]: popt
Out[124]: array([ 0.0847053 , 0.36886652, -0.00961928])
In [125]: pcov
Out[125]:
array([[ 2.96403174e-03, -3.64981635e-03, 8.97783126e-05],
[-3.64981635e-03, 4.61677436e-03, -1.15963105e-04],
[ 8.97783126e-05, -1.15963105e-04, 2.96960195e-06]])
Here's the plot of your data and the fitted curve:
Upvotes: 0
Reputation: 11
Looking at your data, I would suggest to drop the exponencial model and just keep the paraobolic function
def simple_model(x, a, p,q):
return p*x + q*x**2 + a
For complicated non-linear functions curve-fit can't do magic, keep it simple, and then you might add more stuff to the model.
Anyway, if you rather stick to your model, you can set the seed of the initial values of a, p and q that curve_fit will try to optimize:
popt, pcov = curve_fit(model, x, y, p0=[a_seed, p_seed, q_seed])
Playing with reasonable initial guesses of a_seed, p_seed, q_seed may be helpful. Good luck!
Upvotes: 1