Search code examples
pythonmatplotlibscipyscipy-optimize-minimize

Scipy fits very weirdly and creates multiple fitted curves which shouldn't be the case and I know curve fitting doesn't return multiple curves


Here is my code

yp = df.final_sulfur/df.start_sulfur
xp = df.mag/df.hm_weight
sns.set(font_scale=1.5, font='DejaVu Sans')
fig, ax = plt.subplots(1,1, figsize=(9, 9))
yp = df.final_sulfur/df.start_sulfur
xp = df.mag/df.hm_weight
p = ax.plot(xp, yp, marker='o', markersize=1, alpha=0.2, linestyle='none')
p = ax.set_xlabel('mag/hm_weight')
p = ax.set_ylabel('final/start sulfur')
p = ax.set_title('final S vs mag')
p = ax.set_xlim(0.08, 12)
p = ax.set_ylim(3.0e-3, 1.5)
p = ax.set_xscale('log')
p = ax.set_yscale('log')
leg = plt.legend()

Trying to fit the curve below is the equation which I think an exponential decay should dobut what I am getting is completely bad result

import scipy as sp
from scipy.optimize import curve_fit
def func(xp, a, b, c):
    return a*np.exp(-b*xp) + c  
popt2, pcov2 = curve_fit(func, xp, yp, p0=None)
a2, b2, c2 = popt2
print ('a2=', a2, 'b2=', b2, 'c2=', c2)
print ('func=', func(xp, a2, b2, c2))
ax.plot(xp, func(xp, *popt2), 'b-', label='Fit',linestyle='--',color='red')

Note : I need to use log scale for plotting which is when it makes sense

enter image description here

How my sample data looks like (its difficult to put all the data here unfortunately) xp (sample) converted to list for sake of SO

[1.8535530937584435,
 0.3220338983050847,
 1.184544992374174,
 0.7583873696081196,
 0.3209681662720337,
 1.158380317785751,
 1.6285714285714286,
 0.44209925841414716,
 0.7396205664008799,
 0.27983539094650206,
 0.575319622012229,
 0.3287671232876712,
 1.382921589688507,
 0.8247978436657682,
 1.315934065934066,
 0.23450134770889489,
 0.5697069296083265,
 1.0015731515469324,
 1.2841602547094721,
 0.645600653772814,
 0.4599483204134367,
 0.8340260459961208,
 0.8992900341835393,
 0.961340206185567,
 0.5845225027442371,
 0.9623773173391493,
 1.3451708366962605,
 0.8418230563002681,
 0.7456025203465477,
 1.9345156889495225]
 yp [0.05202312138728324,
 0.47058823529411764,
 0.04833333333333333,
 0.11392405063291139,
 0.36363636363636365,
 0.020588235294117647,
 0.008823529411764706,
 0.25641025641025644,
 0.12,
 0.47826086956521735,
 0.1826923076923077,
 0.3333333333333333,
 0.01282051282051282,
 0.029411764705882353,
 0.03225806451612903,
 0.26666666666666666,
 0.05,
 0.011428571428571429,
 0.12080536912751677,
 0.11764705882352941,
 0.2926829268292683,
 0.049999999999999996,
 0.06578947368421052,
 0.08024691358024691,
 0.15517241379310343,
 0.024390243902439025,
 0.017543859649122806,
 0.05479452054794521,
 0.03571428571428571,
 0.007142857142857143]

Solution

  • This is how I got it willing to get better curve more of exponential decay

    yp = df.final_sulfur/df.start_sulfur
    xp = df.mag/df.hm_weight
    test_data=xp.to_frame(name = 'xp').join(yp.to_frame(name='yp'))
    sns.set(font_scale=1.5, font='DejaVu Sans')
    fig, ax = plt.subplots(1,1, figsize=(9,15))
    yp = df.final_sulfur/df.start_sulfur
    xp = df.mag/df.hm_weight
    p = ax.plot(xp, yp, marker='o', markersize=1, alpha=0.2, linestyle='none')
    #p = sns.regplot(x=xp, y=yp, data=test_data,logx=True)
    model = lambda x, A, x0, sigma, offset:  offset+A*np.exp(-((x-x0)/sigma)**1)
    popt, pcov = curve_fit(model, xp.values, yp.values, p0=[0,0.5,1,1])
    x = np.linspace(xp.values.min(),xp.values.max())
    p =ax.plot(x,model(x,*popt), label="fit",color='red',linestyle='--')
    model2 = lambda x, sigma:  model(x,0.5,0,sigma**1,0)
    x2 = np.linspace(xp.values.min(),xp.values.max())
    popt2, pcov2 = curve_fit(model2, xp.values, 
                                  yp.values, p0=[1])
    p= ax.plot(x2,model2(x2,*popt2), label="fit2",color='green')
    model3 = lambda x, A, x0, sigma, offset:  offset+A*np.exp(-((x+x0)/sigma)**1)
    popt, pcov = curve_fit(model3, xp.values, yp.values, p0=[0,0.5,1,1])
    x3 = np.linspace(xp.values.min(),xp.values.max())
    p = ax.plot(x3,model(x3,*popt), label="fit3",color='blue')
    

    enter image description here