Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python curve_fit with multiple independent variables

Python's curve_fit calculates the best-fit parameters for a function with a single independent variable, but is there a way, using curve_fit or something else, to fit for a function with multiple independent variables? For example:

def func(x, y, a, b, c):
    return log(a) + b*log(x) + c*log(y)

where x and y are the independent variable and we would like to fit for a, b, and c.

like image 472
ylangylang Avatar asked Feb 06 '15 18:02

ylangylang


3 Answers

You can pass curve_fit a multi-dimensional array for the independent variables, but then your func must accept the same thing. For example, calling this array X and unpacking it to x, y for clarity:

import numpy as np
from scipy.optimize import curve_fit

def func(X, a, b, c):
    x,y = X
    return np.log(a) + b*np.log(x) + c*np.log(y)

# some artificially noisy data to fit
x = np.linspace(0.1,1.1,101)
y = np.linspace(1.,2., 101)
a, b, c = 10., 4., 6.
z = func((x,y), a, b, c) * 1 + np.random.random(101) / 100

# initial guesses for a,b,c:
p0 = 8., 2., 7.
print(curve_fit(func, (x,y), z, p0))

Gives the fit:

(array([ 9.99933937,  3.99710083,  6.00875164]), array([[  1.75295644e-03,   9.34724308e-05,  -2.90150983e-04],
   [  9.34724308e-05,   5.09079478e-06,  -1.53939905e-05],
   [ -2.90150983e-04,  -1.53939905e-05,   4.84935731e-05]]))
like image 169
xnx Avatar answered Nov 18 '22 17:11

xnx


Fitting to an unknown numer of parameters

In this example, we try to reproduce some measured data measData. In this example measData is generated by the function measuredData(x, a=.2, b=-2, c=-.8, d=.1). I practice, we might have measured measData in a way - so we have no idea, how it is described mathematically. Hence the fit.

We fit by a polynomial, which is described by the function polynomFit(inp, *args). As we want to try out different orders of polynomials, it is important to be flexible in the number of input parameters. The independent variables (x and y in your case) are encoded in the 'columns'/second dimension of inp.

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

def measuredData(inp, a=.2, b=-2, c=-.8, d=.1):
    x=inp[:,0]
    y=inp[:,1]
    return a+b*x+c*x**2+d*x**3 +y

def polynomFit(inp, *args):
    x=inp[:,0]
    y=inp[:,1]
    res=0
    for order in range(len(args)):
        print(14,order,args[order],x)
        res+=args[order] * x**order
    return res +y


inpData=np.linspace(0,10,20).reshape(-1,2)
inpDataStr=['({:.1f},{:.1f})'.format(a,b) for a,b in inpData]
measData=measuredData(inpData)
fig, ax = plt.subplots()
ax.plot(np.arange(inpData.shape[0]), measData, label='measuered', marker='o', linestyle='none' )

for order in range(5):
    print(27,inpData)
    print(28,measData)
    popt, pcov = curve_fit(polynomFit, xdata=inpData, ydata=measData, p0=[0]*(order+1) )
    fitData=polynomFit(inpData,*popt)
    ax.plot(np.arange(inpData.shape[0]), fitData, label='polyn. fit, order '+str(order), linestyle='--' )
    ax.legend( loc='upper left', bbox_to_anchor=(1.05, 1))
    print(order, popt)

ax.set_xticklabels(inpDataStr, rotation=90)

Result:

enter image description here

like image 3
Markus Dutschke Avatar answered Nov 18 '22 19:11

Markus Dutschke


Yes. We can pass multiple variables for curve_fit. I have written a piece of code:

import numpy as np
x = np.random.randn(2,100)
w = np.array([1.5,0.5]).reshape(1,2)
esp = np.random.randn(1,100)
y = np.dot(w,x)+esp
y = y.reshape(100,)

In the above code I have generated x a 2D data set in shape of (2,100) i.e, there are two variables with 100 data points. I have fit the dependent variable y with independent variables x with some noise.

def model_func(x,w1,w2,b):
  w = np.array([w1,w2]).reshape(1,2)
  b = np.array([b]).reshape(1,1)
  y_p = np.dot(w,x)+b
  return y_p.reshape(100,)

We have defined a model function that establishes relation between y & x.
Note: The shape of output of the model function or predicted y should be (length of x,)

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

The popt is an 1D numpy array containing predicted parameters. In our case there are 3 parameters.

like image 1
Kumar Mayank Avatar answered Nov 18 '22 19:11

Kumar Mayank