1

Index error while trying to fit a order>1 polynomial to the data :

import numpy as np
from scipy.optimize import curve_fit

x =  b #1D array for X Axis
y =  c #1D array for Y Axis

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

iniguess = [0,0.038,13.99]
param, pcov = curve_fit(func, x, y, p0=iniguess)

print (param[0],param[1],param[2])
 
import matplotlib.pyplot as plt
plt.plot(x,y,'bo ')
xfit = b
yfit = func(xfit, param[0], param[1], param[3])
plt.plot(xfit,yfit,'r-')
plt.legend(['data','fit'],loc='best')

This gives me an error code when I try to calculate my predicted Y values. The error is "index 3 is out of bounds for axis 0 with size 3"

Community
  • 1
  • 1
Abhinav
  • 13
  • 3
  • 5
    Should not be `param[2]` and not `param[3]` for the last parameter in your function `func` at the line starting by `yfit = func...`? – Ben.T Nov 27 '18 at 03:02
  • yep..sort of: read the error message. Anyhow, is `x = b` or is `b` the fitting parameter. Sure, python can work like this, but from the code readability point of view variable naming could be improved as well. – mikuszefski Nov 27 '18 at 07:45
  • Yes. It should've been Param[2]. Missed that. – Abhinav Nov 28 '18 at 04:45

1 Answers1

1

As @Ben.T pointed out, the problem is that param[3] in your code should be param[2]. When you have a list of arguments like param that you're passing to a function one after the other in order (ie func(..., param[0], param[1], param[2], ...)), you can instead just pass them all at once with *param. The leading asterix *foo is a shortcut in the python syntax that lets you pass many arguments at once instead of one at a time. Using these kinds of shortcuts makes your code easier to read and less error prone, since you'll no longer have to bother with the individual indices of param.

Here's a complete working version of your code. Note the use of *param in the line that creates yfit:

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

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

iniguess = [2,0.038,13.99]

# make some fake example data
N = 1000
x =  np.linspace(0, 10, N)
y = func(x, *iniguess)

# add some noise to make this a non-trivial curve fitting
y +=  np.random.normal(size=N)

param, pcov = curve_fit(func, x, y, p0=iniguess)
print(param)

plt.plot(x,y,'bo ')

yfit = func(x, *param)
plt.plot(x,yfit,'r-')

plt.legend(['data','fit'],loc='best')

Output:

[ 1.99894963  0.04834206 14.0062958 ]

enter image description here

tel
  • 13,005
  • 2
  • 44
  • 62