Soumav Nath
Soumav Nath

Reputation: 11

How to do Non-Linar Curve fitting and find fitting parameter using Python with user defined function?

I have the following data-set:

x = 0, 5, 10, 15, 20, 25, 30

y = 0, 0.13157895, 0.31578947, 0.40789474, 0.46052632, 0.5, 0.53947368

Now, I want to plot this data and fit this data set with my defined function f(x) = (A*K*x/(1+K*x)) and find the parameters A and K ?

I wrote the following python script but it seems like it can't do the fitting I require:

import matplotlib.pyplot as plt

import numpy as np

from scipy.optimize import curve_fit

x = np.array([0, 5, 10, 15, 20, 25, 30])

y = np.array([0, 0.13157895, 0.31578947, 0.40789474, 0.46052632, 0.5, 0.53947368])

def func(x, A, K):

    return (A*K*x / (1+K*x))

plt.plot(x, y, 'b-', label='data')


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

plt.plot(x, func(x, *popt), 'r-', label='fit')

plt.xlabel('x')

plt.ylabel('y')

plt.legend()

plt.show()

Still, it's not giving a best curve fit. Can anyone help me with the changes in the python script or a new script where I can properly fit the data with my desired fitting function ?

Upvotes: 0

Views: 177

Answers (2)

user1877600
user1877600

Reputation: 647

Try Minuit, which is a package implemented at Cern.

from iminuit import Minuit
import numpy as np
import matplotlib.pyplot as plt

def func(x, A, K):
    return (A*K*x / (1+K*x))

def least_squares(a, b):
    yvar = 0.01
    return sum((y - func(x, a, b)) ** 2 / yvar)

x = np.array([0, 5, 10, 15, 20, 25, 30])
y = np.array([0, 0.13157895, 0.31578947, 0.40789474, 0.46052632, 0.5, 0.53947368])

m = Minuit(least_squares, a=5, b=5)
m.migrad() # finds minimum of least_squares function
m.hesse()  # computes errors 
plt.plot(x, y, "o")
plt.plot(x, func(x, *m.values.values()))

# print parameter values and uncertainty estimates
for p in m.parameters:
    print("{} = {} +/- {}".format(p, m.values[p], m.errors[p]))

And the outcome:

a = 0.955697134431429 +/- 0.4957121286951612

b = 0.045175437602766676 +/- 0.04465599806912648

enter image description here

Upvotes: 0

Péter Leéh
Péter Leéh

Reputation: 2119

The classic problem: You didn't give any inital guess for A neither K. In this case the default value will be 1 for all parameters, which is not suitable for your dataset, and the fitting will converge to somewhere else. You can figure out the guesses different ways: by looking at the data, by the real meaning of parameters, etc.. You can guess values with the p0 parameter of scipy.optimize.curve_fit. It accepts list of values in the order they are in the func you want to optimize. I used 0.1 for both, and I got this curve:

popt, pcov = curve_fit(func, x, y, p0=[0.1, 0.1])

1

Upvotes: 3

Related Questions