Fitting exponential decay curve

# Fitting expoential decay function


Expoential Decay Function:


$y = A e^{Bx}$


Take the log of both sides:


$log(y) = log(A) + Bx$


Model log(y) as a linear function to figure out the slope B and the intercept log(A).<br>

Numpy.polyfit(x, y) Least squares polynomial fit.<br>

import numpy as np


x = np.array([10, 19, 30, 35, 51])

y = np.array([79, 50, 20, 7, 1])




result = np.polyfit(x, np.log(y), deg=1)

print(result)


B = result[0]

log_A = result[1]

A = np.exp(log_A)


X = np.arange(0, 60, 1)

y1 = A * np.exp(B*X)


print('The curve is : y = {} * e^({}x)'.format(A, B))


[-0.10943844  5.81833736]

The curve is : y = 336.4122549507605 * e^(-0.10943843796666908x) 

The problem is with a large y, the least square |y - y'|^2 creates a lot of bias towards small y values. A larger y value dominiates the loss function as opposed to a smaller y. One way to remediate is to add weights, so as to increase the weight of a smaller y and decrease the weight of a bigger y.<br>

**Numpy.polyfit(x, y, w)** Weighted Least squares polynomial fit.<br>

w:<br>

Weights to apply to the y-coordinates of the sample points. For gaussian uncertainties, use 1/sigma (not 1/sigma**2).


weight = np.sqrt(y)


result = np.polyfit(x, np.log(y), deg=1, w=np.sqrt(y))

print(result)


B = result[0]

log_A = result[1]

A = np.exp(log_A)


X = np.arange(0, 60, 1)

y2 = A * np.exp(B*X)


print('The curve is : y = {} * e^({}x)'.format(A, B))


[-0.08022606  5.2598691 ]

The curve is : y = 192.45629707026794 * e^(-0.08022606279569525x) 

# Fitting expoential decay with a bias


$y = A e^{Bx} + C$


The obove method will not work as the term C breaks the nice property of log. Other fitting method is needed. Scipy has a nice curve_fit that uses non-linear least squares to fit a function, f, to data.


import scipy.optimize


def fn(x, A, B, C):

    return A * np.exp(-B*x) + C


params, cv = scipy.optimize.curve_fit(fn, x, y)


X = np.arange(0, 60, 1)

y3 = fn(X, *params)


print(params)

[ 1.57265984e+02  5.22201371e-02 -1.27363118e+01] 


Compare the fitted curves

import matplotlib.pyplot as plt


plt.figure(figsize=(8, 8))

plt.scatter(x, y, c='green')

plt.plot(X, y1, c='red', label='polyfit')

plt.plot(X, y2, c='blue', label='polyfit with weight')

plt.plot(X, y3, c='orange', label='optimize.curve_fit')

plt.legend(loc='upper right')

plt.show()