Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fitting exponential function through two data points with scipy curve_fit

I want to fit an exponential function y=x ** pw with a constant pw to fit through two datapoints. The scipy curve_fit function should optimise adj1 and adj2. I have tried with the code below but couldn't get it to work. The curve does not go through the datapoints. How can I fix it?

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

def func(x, adj1,adj2):
    return np.round(((x+adj1) ** pw) * adj2, 2)

x = [0.5,0.85] # two given datapoints to which the exponential function with power pw should fit
y = [0.02,4]

pw=15
popt, pcov = curve_fit(func, x, y)

xf=np.linspace(0,1,50)

plt.figure()
plt.plot(x, y, 'ko', label="Original Data")
plt.plot(xf, func(xf, *popt), 'r-', label="Fitted Curve")
plt.show()
like image 440
Nickpick Avatar asked Oct 17 '15 12:10

Nickpick


People also ask

How do you fit an exponential function to data in Python?

y = e(ax)*e(b) where a ,b are coefficients of that exponential equation. We would also use numpy. polyfit() method for fitting the curve. This function takes on three parameters x, y and the polynomial degree(n) returns coefficients of nth degree polynomial.

How does SciPy optimize Curve_fit work?

The SciPy open source library provides the curve_fit() function for curve fitting via nonlinear least squares. The function takes the same input and output data as arguments, as well as the name of the mapping function to use. The mapping function must take examples of input data and some number of arguments.

How do you find the exponential function from data points?

If you have two points, (x1, y1) and (x2, y2), you can define the exponential function that passes through these points by substituting them in the equation y = abx and solving for a and b. In general, you have to solve this pair of equations: y1 = abx1 and y2 = abx2, .


2 Answers

If you want to find the two parameters in your objective function from only two data points, this isn't necessarily a problem for least-squares fitting: just solve the simultaneous equations y1 = b(x1+a)^p and y2 = b(x2+a)^p for the parameters a and b:

import numpy as np
import matplotlib.pyplot as plt

def func(x, adj1,adj2):
    return ((x+adj1) ** pw) * adj2

x = [0.5,0.85] # two given datapoints to which the exponential function with power pw should fit
y = [0.02,4]

pw = 15
A = np.exp(np.log(y[0]/y[1])/pw)
a = (x[0] - x[1]*A)/(A-1)
b = y[0]/(x[0]+a)**pw

xf=np.linspace(0,1,50)
plt.figure()
plt.plot(x, y, 'ko', label="Original Data")
plt.plot(xf, func(xf, a, b), 'r-', label="Fitted Curve")
plt.show()

The resulting function will pass through both points exactly, of course.

enter image description here

like image 55
xnx Avatar answered Sep 24 '22 02:09

xnx


It's just because the round method is killing curve_fit's ability to search the space. Small perturbations of p0 will always give an equal result, so it stops searching immediatly and will always return whatever you give it as a starting point (by default p0 = [1.,1.]). The solution is to simply remove np.round from your function.

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

def func(x, adj1,adj2):
    return ((x+adj1) ** pw) * adj2

x = [0.5,0.85] # two given datapoints to which the exponential function with power pw should fit
y = [0.02,4]

pw=15
popt, pcov = curve_fit(func, x, y)

xf=np.linspace(0,1,50)

plt.figure()
plt.plot(x, y, 'ko', label="Original Data")
plt.plot(xf, func(xf, *popt), 'r-', label="Fitted Curve")
plt.show()

enter image description here

like image 33
joshua Avatar answered Sep 24 '22 02:09

joshua