I'm trying to fit an exponential curve using curve_fit (scipy.optimize)
but the fitted curve looks nowhere like the real curve.
Right now I'm using the following code:
X=[0.0, 9.0, 18.0, 27.0, 36.0, 45.0, 54.0]
Y=[0.090316199, -0.078157925, -0.350137315, -0.695193468, -1.106773689, -1.60467115, -2.196169408]
#plot Y against X
fig = plt.figure(num=None, figsize=(9, 7),facecolor='w', edgecolor='k')
ax=fig.add_subplot(111)
ax.scatter(X,Y)
#fit using curve_fit
popt, pcov = curve_fit(func, X, Y,maxfev=10000)
#compute Y_estiamted using fitted parameters
Y_estimated=[popt[0]*np.exp(i+popt[1])+popt[2] for i in X]
#plot Y_estiamted against X
ax.scatter(X,Y_estimated, c='r')
def func(x,a,b,c):
return a*(np.exp(x+b))+c
The blue curve is the real curve and the red curve is the fitted curve.
As you can see the fitted red curve does not match the real blue curve at all. Any help would be appreciated!
I got a fairly good fit to an asymptotic exponential type of equation that has a single shape parameter and a small offset, "1.0 - pow(a, x) + b". Here is a graphical Python fitter using this equation with your data.
import numpy, scipy, matplotlib
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
# ignore warnings within curve_fit() routine
import warnings
warnings.filterwarnings("ignore")
X=[0.0, 9.0, 18.0, 27.0, 36.0, 45.0, 54.0]
Y=[0.090316199, -0.078157925, -0.350137315, -0.695193468, -1.106773689, -1.60467115, -2.196169408]
# alias data to match previous example
xData = numpy.array(X, dtype=float)
yData = numpy.array(Y, dtype=float)
def func(x, a, b): # Asymptotic Exponential A equation with offset from zunzun.com
return 1.0 - numpy.power(a, x) + b
# these are the same as the scipy defaults
initialParameters = numpy.array([1.0, 1.0])
# curve fit the test data
fittedParameters, pcov = curve_fit(func, xData, yData, initialParameters)
modelPredictions = func(xData, *fittedParameters)
absError = modelPredictions - yData
SE = numpy.square(absError) # squared errors
MSE = numpy.mean(SE) # mean squared errors
RMSE = numpy.sqrt(MSE) # Root Mean Squared Error, RMSE
Rsquared = 1.0 - (numpy.var(absError) / numpy.var(yData))
print('Parameters:', fittedParameters)
print('RMSE:', RMSE)
print('R-squared:', Rsquared)
print()
##########################################################
# graphics output section
def ModelAndScatterPlot(graphWidth, graphHeight):
f = plt.figure(figsize=(graphWidth/100.0, graphHeight/100.0), dpi=100)
axes = f.add_subplot(111)
# first the raw data as a scatter plot
axes.plot(xData, yData, 'D')
# create data for the fitted equation plot
xModel = numpy.linspace(min(xData), max(xData))
yModel = func(xModel, *fittedParameters)
# now the model as a line plot
axes.plot(xModel, yModel)
axes.set_xlabel('X Data') # X axis data label
axes.set_ylabel('Y Data') # Y axis data label
plt.show()
plt.close('all') # clean up after using pyplot
graphWidth = 800
graphHeight = 600
ModelAndScatterPlot(graphWidth, graphHeight)