Abbas Mohammed
Abbas Mohammed

Reputation: 25

generic curve fitting by changing model function in python

I am using SciPy.optimize.curve_fit https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.curve_fit.html to get the coefficients of curve fitting function, the SciPy function takes the model function as its first argument so if I want to make a linear curve fit, I pass to it the following function:

def objective(x, a, b):
    return a * x + b

If I want polynomial curve fitting of second degree, I pass the following:

def objective(x, a, b, c):
    return a * x + b * x**2 + c

And so on, what I want to achieve is to make this model function generic for example, if the user wanted to curve fit to a polynomial of 5th degree by inputting 5 it should change to

def objective(x, a, b, c, d, e, f):
    return (a * x) + (b * x**2) + (c * x**3) + (d * x**4) + (e * x**5) + f

While the code is running is this possible? And if it is not possible using SciPy because it requires to change a function, is there any other way to achieve what I want ?

Upvotes: 1

Views: 792

Answers (2)

loamoza
loamoza

Reputation: 158

The task can be accomplished in a few ways. If you want to use scipy, you can simply create a dictionary to refer to specific function by using numerical input from user:

import scipy.optimize as optimization
polnum = 2 # suppose this is input from user


def objective1(x, a, b):
    return a * x + b


def objective2(x, a, b, c):
    return a * x + b * x**2 + c

# Include some more functions

# Do not include round brackets in the dictionary 
object_dict = {
    1: objective1,
    2: objective2
# Include the numbers with corresponding functions
}
opt = optimization.curve_fit(object_dict[polnum], x, y)  # Curve fitted

print(opt[0]) # Returns parameters

However, I would suggest you going with a bit better way where you do not have to define each function:

import numpy as np
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import make_pipeline
from sklearn.linear_model import LinearRegression

polnum = 2  # suppose this is input from user

# Creates a Polynomial of polnum degree
model = make_pipeline(PolynomialFeatures(polnum), LinearRegression)
# You can change the estimator Linear Regression to any other offered in sklearn.linear_model
# Make sure that x and y data are of the same shape
model.fit(x, y)
# Now you can use the model to check some other values
y_predict = model.predict(x_predict[:, np.newaxis])

Upvotes: 1

joni
joni

Reputation: 7157

If you really want to implement it on your own, you can either use a variable number of coefficients *coeffs:

def objective(x, *coeffs):
    result = coeffs[-1]
    for i, coeff in enumerate(coeffs[:-1]):
        result += coeff * x**(i+1)
    return result

or use np.polyval:

import numpy as np

def objective(x, *coeffs):
    return np.polyval(x, coeffs)

However, note that there's no need to use curve_fit. You can directly use np.polyfit to do a least-squares polynomial fit.

Upvotes: 1

Related Questions