2

I need to fit some data with a two-term exponential following the equation a*exp(b*x)+c*exp(d*x). In matlab, it's as easy as changing the 1 to a 2 in polyfit to go from a one-term exponential to a two-term. I haven't found a simple solution to do it in python and was wondering if there even was one? I tried using curve_fit but it is giving me lots of trouble and after scouring the internet I still haven't found anything useful. Any help is appreciated!

Kevin
  • 74,910
  • 12
  • 133
  • 166
EmilyK
  • 33
  • 1
  • 4

2 Answers2

4

Yes you can use curve_fit from scipy. Here is an example for your specific fit function.

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

x = np.linspace(0,4,50) # Example data

def func(x, a, b, c, d):
    return a * np.exp(b * x) + c * np.exp(d * x)

y = func(x, 2.5, 1.3, 0.5, 0.5) # Example exponential data

# Here you give the initial parameters for a,b,c which Python then iterates over
# to find the best fit
popt, pcov = curve_fit(func,x,y,p0=(1.0,1.0,1.0,1.0))

print(popt) # This contains your three best fit parameters

p1 = popt[0] # This is your a
p2 = popt[1] # This is your b
p3 = popt[2] # This is your c
p4 = popt[3] # This is your d

residuals = y - func(x,p1,p2,p3,p4)
fres = sum( (residuals**2)/func(x,p1,p2,p3,p4) ) # The chi-sqaure of your fit

print(fres)

""" Now if you need to plot, perform the code below """
curvey = func(x,p1,p2,p3,p4) # This is your y axis fit-line

plt.plot(x, curvey, 'red', label='The best-fit line')
plt.scatter(x,y, c='b',label='The data points')
plt.legend(loc='best')
plt.xlabel('x')
plt.ylabel('y')
plt.show()

enter image description here

Srivatsan
  • 9,225
  • 13
  • 58
  • 83
1

You can do it with leastsq. Something like:

from numpy import log, exp
from scipy.optimize.minpack import leastsq

## regression function
def _exp(a, b, c, d):
    """
    Exponential function y = a * exp(b * x) + c * exp(d * x)
    """
    return lambda x: a * exp(b * x) + c * exp(d * x)

## interpolation
def interpolate(x, df, fun=_exp):
    """
    Interpolate Y from X based on df, a dataframe with columns 'x' and 'y'.
    """
    resid = lambda p, x, y: y - fun(*p)(x)
    ls = leastsq(resid, [1.0, 1.0, 1.0, 1.0], args=(df['x'], df['y']))
    a, b, c, d = ls[0]
    y = fun(a, b, c, d)(x)
    return y
mattexx
  • 6,456
  • 3
  • 36
  • 47