user3635644
user3635644

Reputation:

Scipy strange results using curve fitting

When I try to fit my data, results are a bit strange and I don't understand why ? Obtained fitting is flat, and the first input e=0. seems to raised a division error somewhere. The only working case is when I modify e[0]=1.0e-9

The result is the following: enter image description here

From example here it seems that my example is not so far from what I read, but I stay stuck, so could you help me please on what's going wrong in my case ?

import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt

src_s = np.array((45.59,50.66664,59.74871,65.71018,72.76012,79.06256,84.13755,90.39944,
                  96.33653,101.65667,106.27968,110.76301,114.41808,117.21922,120.51836))
src_e = np.array((0.0,0.00126,0.00503,0.00804,0.01228,0.01685,0.02127,0.02846,0.03666,
                  0.04581,0.05620,0.06882,0.08005,0.09031,0.10327))
# plot source data
plt.plot(src_e, src_s, 'o')
# fitting function
def sigma(e, k ,n): return k*(e**n)
# find parameters curve fitting
param, var = curve_fit(sigma, src_e, src_s)
new_e = np.linspace(src_e.min(), src_e.max(), 50)
plt.plot(new_e, sigma(new_e, *param))

# modify first input
src_e[0]=1.0e-9
# relaunch parameters curve fitting
param, var = curve_fit(sigma, src_e, src_s)
new_e = np.linspace(src_e.min(), src_e.max(), 50)
plt.plot(new_e, sigma(new_e, *param))

plt.show()

Thanks in advance for your help.

Upvotes: 6

Views: 955

Answers (2)

HYRY
HYRY

Reputation: 97291

The first point can't be on the curve, so you need to change the curve formula:

import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt

src_s = np.array((45.59,50.66664,59.74871,65.71018,72.76012,79.06256,84.13755,90.39944,
                  96.33653,101.65667,106.27968,110.76301,114.41808,117.21922,120.51836))
src_e = np.array((0.0,0.00126,0.00503,0.00804,0.01228,0.01685,0.02127,0.02846,0.03666,
                  0.04581,0.05620,0.06882,0.08005,0.09031,0.10327))
# plot source data
plt.plot(src_e, src_s, 'o')

def sigma(e, k ,n, offset): return k*((e+offset)**n)
# find parameters curve fitting
param, var = curve_fit(sigma, src_e, src_s)
new_e = np.linspace(src_e.min(), src_e.max(), 50)
plt.plot(new_e, sigma(new_e, *param))

here is the output:

enter image description here

Upvotes: 0

CT Zhu
CT Zhu

Reputation: 54340

The root of problem is an bad initial guess of parameters (actually no starting parameter is provided for curve_fit).

The target function can easily be linearized. Let's do that, then do a linear regression to get a good set of initial guess parameters for curve_fit (pass to it by p0=). The resulting fit is better (having less residue) and does not need to replace the first value of to be 1e-9:

In [38]:

src_e[0]=1.0e-9
# relaunch parameters curve fitting
param, var = curve_fit(sigma, src_e, src_s)
new_e = np.linspace(src_e.min(), src_e.max(), 50)
src_e[0]=0
plt.plot(new_e, sigma(new_e, *param))
plt.plot(src_e, src_s, 'ro')
plt.savefig('1.png')
print 'Residue is:', ((sigma(src_e, *param)-src_s)**2).sum()
Residue is: 2168.65307587

enter image description here

In [39]:

import scipy.stats as ss
src_e[0]=0
V=ss.linregress(np.log(src_e)[1:], np.log(src_s)[1:]) #avoid log(0)
param, var = curve_fit(sigma, src_e, src_s, p0=(np.exp(V[1]), V[0]))
new_e = np.linspace(src_e.min(), src_e.max(), 50)
plt.plot(new_e, sigma(new_e, *param))
plt.plot(src_e, src_s, 'ro')
plt.savefig('1.png')
print 'Residue is:', ((sigma(src_e, *param)-src_s)**2).sum()
Residue is: 2128.85364181

enter image description here

Upvotes: 2

Related Questions