66

I have some points and I am trying to fit curve for this points. I know that there exist scipy.optimize.curve_fit function, but I do not understand documentation, i.e how to use this function.

My points: np.array([(1, 1), (2, 4), (3, 1), (9, 3)])

Can anybody explain how to do that?

CIsForCookies
  • 10,991
  • 7
  • 44
  • 96
Bob
  • 9,583
  • 22
  • 60
  • 69

2 Answers2

113

I suggest you to start with simple polynomial fit, scipy.optimize.curve_fit tries to fit a function f that you must know to a set of points.

This is a simple 3 degree polynomial fit using numpy.polyfit and poly1d, the first performs a least squares polynomial fit and the second calculates the new points:

import numpy as np
import matplotlib.pyplot as plt

points = np.array([(1, 1), (2, 4), (3, 1), (9, 3)])
# get x and y vectors
x = points[:,0]
y = points[:,1]

# calculate polynomial
z = np.polyfit(x, y, 3)
f = np.poly1d(z)

# calculate new x's and y's
x_new = np.linspace(x[0], x[-1], 50)
y_new = f(x_new)

plt.plot(x,y,'o', x_new, y_new)
plt.xlim([x[0]-1, x[-1] + 1 ])
plt.show()

enter image description here

Trilarion
  • 9,942
  • 9
  • 61
  • 98
jabaldonedo
  • 24,746
  • 8
  • 73
  • 76
  • This works only with given dataset. But when I change points, in the majority of cases there is only curve between two points. Why? – Dmitri Oct 03 '13 at 20:38
  • It works with any dataset as long as you provide the data correctly, that is two arrays of the same size, for example: `x = np.array([1, 2, 3, 4, 5, 6])` and `y = np.array([0.2, 1, 1.2, 3, 0.8, 1.1])` – jabaldonedo Oct 03 '13 at 20:49
  • It draws only curve between two lines with following dataset: x = np.array([0., 1., -1., .5]) y = np.array([0., 1., .9, .7]) – Dmitri Oct 03 '13 at 20:55
  • What is difference that it one case it draws correct curve while in other only line between points? – Dmitri Oct 03 '13 at 20:56
  • 6
    The problem is that your `x` array is not sorted, and therefore the polyfit is not working, you must reorder both arrays properly: `x = np.array([-1., 0., .5, 1.])` and `y = np.array([.9, 0., .7, 1.])` – jabaldonedo Oct 03 '13 at 21:02
  • @jabaldonedo Very nice example, is it possible to fit also data with error bars? – Alexander Cska Jun 13 '16 at 10:41
  • 1
    An alternative to sorting your x vals: `x_new = np.linspace(min(x), max(x), 50)` – andyw Sep 12 '17 at 09:32
  • could you explain `x_new` and `y_new`? What does calculating new xs and ys mean? – Snow Aug 16 '18 at 15:41
  • 1
    In this specific case, a polynomial fit is a bit of overkill. The data is overfitted, at least for 3 degree polyniomial. Just a horizontal line seems to be more realisitic. – westr Oct 01 '19 at 09:01
  • can you do a polynomial fit in N dimensions? – MetaStack Jun 04 '20 at 19:51
  • 1
    Note that the docs recommend using [numpy.polynomial](https://numpy.org/doc/stable/reference/generated/numpy.polynomial.polynomial.Polynomial.fit.html#numpy.polynomial.polynomial.Polynomial.fit) over [numpy.polyfit](https://numpy.org/doc/stable/reference/generated/numpy.polyfit.html) since numpy version 1.4 – Casey Oct 28 '21 at 14:26
59

You'll first need to separate your numpy array into two separate arrays containing x and y values.

x = [1, 2, 3, 9]
y = [1, 4, 1, 3]

curve_fit also requires a function that provides the type of fit you would like. For instance, a linear fit would use a function like

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

scipy.optimize.curve_fit(func, x, y) will return a numpy array containing two arrays: the first will contain values for a and b that best fit your data, and the second will be the covariance of the optimal fit parameters.

Here's an example for a linear fit with the data you provided.

import numpy as np
from scipy.optimize import curve_fit

x = np.array([1, 2, 3, 9])
y = np.array([1, 4, 1, 3])

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

params = curve_fit(fit_func, x, y)

[a, b] = params[0]

This code will return a = 0.135483870968 and b = 1.74193548387

Here's a plot with your points and the linear fit... which is clearly a bad one, but you can change the fitting function to obtain whatever type of fit you would like.

enter image description here

Greg
  • 5,951
  • 3
  • 16
  • 20