🚀 LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
🎓 COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.
REFERENCEscipy

scipy Documentation

LOADING ENGINE...

optimize.curve_fit()

AI & DATA SCIENCE // optimize-curve-fit

scipy.optimize.curve_fit() finds the parameters of a given function that make it best fit a set of observed data points, using non-linear least squares.

Syntax

scipy.optimize.curve_fit(f, xdata, ydata, p0=None)

Deep Dive Course

curve_fit() takes a model function f, which accepts the independent variable plus the parameters to be fit, arrays of observed x and y data, and an optional initial parameter guess p0, then finds the parameter values that minimize the sum of squared differences between the model's predictions and the actual observed data. It returns a tuple of the best-fit parameters and their estimated covariance matrix, from which you can compute standard errors/uncertainty on each fitted parameter.

1Understanding optimize.curve_fit()

curve_fit() takes a model function f, which accepts the independent variable plus the parameters to be fit, arrays of observed x and y data, and an optional initial parameter guess p0, then finds the parameter values that minimize the sum of squared differences between the model's predictions and the actual observed data. It returns a tuple of the best-fit parameters and their estimated covariance matrix, from which you can compute standard errors/uncertainty on each fitted parameter.

💡

Provide a reasonable initial guess via p0 for anything beyond a simple linear model — curve_fit() defaults to starting all parameters at 1, which can cause the fit to fail or converge to a poor result for models where that's a bad starting point, like an exponential decay model.

editor.html
from scipy import optimize
import numpy as np

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

x_data = np.array([1, 2, 3, 4])
y_data = np.array([2.1, 3.9, 6.2, 7.8])
params, _ = optimize.curve_fit(model, x_data, y_data)
print(np.round(params, 2))
localhost:3000

2Practical Example

Here is a real-world application of optimize.curve_fit() showing how it is used in production SciPy code.

editor.html
from scipy import optimize
import numpy as np

def model(x, a, b, c):
    return a * np.exp(-b * x) + c

x_data = np.array([0, 1, 2, 3, 4])
y_data = np.array([10, 6, 4, 3, 2.5])
params, _ = optimize.curve_fit(model, x_data, y_data, p0=[8, 0.5, 1])
print(np.round(params, 1))
localhost:3000

3Best Practices

Follow these guidelines when working with optimize.curve_fit():

1. Provide p0 with a sensible initial guess for the model's parameters, especially for non-linear models, rather than relying on the default starting values

2. Extract parameter uncertainty from the returned covariance matrix, the square root of its diagonal, rather than treating the fitted parameters as exact

3. Visually plot the fitted curve against the actual data points as a sanity check, rather than trusting a numerically successful fit blindly

⚠️

Tip: Provide a reasonable initial guess via p0 for anything beyond a simple linear model — curve_fit() defaults to starting all parameters at 1, which can cause the fit to fail or converge to a poor result for models where that's a bad starting point, like an exponential decay model.

editor.html
from scipy import optimize
import numpy as np

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

x_data = np.array([1, 2, 3, 4])
y_data = np.array([2.1, 3.9, 6.2, 7.8])
params, _ = optimize.curve_fit(model, x_data, y_data)
print(np.round(params, 2))
localhost:3000

Examples

Example 01Basic Usage
from scipy import optimize
import numpy as np

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

x_data = np.array([1, 2, 3, 4])
y_data = np.array([2.1, 3.9, 6.2, 7.8])
params, _ = optimize.curve_fit(model, x_data, y_data)
print(np.round(params, 2))
Example 02Advanced Example
from scipy import optimize
import numpy as np

def model(x, a, b, c):
    return a * np.exp(-b * x) + c

x_data = np.array([0, 1, 2, 3, 4])
y_data = np.array([10, 6, 4, 3, 2.5])
params, _ = optimize.curve_fit(model, x_data, y_data, p0=[8, 0.5, 1])
print(np.round(params, 1))

Best Practices

  • Provide p0 with a sensible initial guess for the model's parameters, especially for non-linear models, rather than relying on the default starting values
  • Extract parameter uncertainty from the returned covariance matrix, the square root of its diagonal, rather than treating the fitted parameters as exact
  • Visually plot the fitted curve against the actual data points as a sanity check, rather than trusting a numerically successful fit blindly

Interview Question

Why does curve_fit() need an initial parameter guess (p0), especially for non-linear models, while a simple linear fit often works fine with the default?

Hint: Think about the shape of the error surface being minimized for a linear model versus a more complex non-linear one.

For a linear model, the sum-of-squared-errors surface being minimized has a single, smooth, bowl-like shape with exactly one minimum, so the underlying least-squares algorithm reliably finds it regardless of where it starts. Non-linear models, like an exponential decay, can have a much more complex error surface with multiple local minima, flat regions, or areas where the algorithm's local search gets stuck or diverges entirely if it starts too far from reasonable parameter values. Providing a sensible p0 that's already in the right general neighborhood for each parameter dramatically increases the chance the algorithm converges to a good, meaningful fit rather than failing or settling on a poor one.

Exercises

MediumPractice using optimize.curve_fit() in a real scenario.
View Solution
from scipy import optimize
import numpy as np

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

x_data = np.array([1, 2, 3, 4])
y_data = np.array([2.1, 3.9, 6.2, 7.8])
params, _ = optimize.curve_fit(model, x_data, y_data)
print(np.round(params, 2))

Frequently Asked Questions

Why does curve_fit() need an initial parameter guess (p0), especially for non-linear models, while a simple linear fit often works fine with the default?

For a linear model, the sum-of-squared-errors surface being minimized has a single, smooth, bowl-like shape with exactly one minimum, so the underlying least-squares algorithm reliably finds it regardless of where it starts. Non-linear models, like an exponential decay, can have a much more complex error surface with multiple local minima, flat regions, or areas where the algorithm's local search gets stuck or diverges entirely if it starts too far from reasonable parameter values. Providing a sensible p0 that's already in the right general neighborhood for each parameter dramatically increases the chance the algorithm converges to a good, meaningful fit rather than failing or settling on a poor one.

Related Functions

optimize-minimizestats-normnp-array