In scipy.optimize.curve_fit, set p0 to plausible starting values in the model’s parameter order, use bounds only for justified parameter limits, and raise maxfev only when the solver is making progress but runs out of function calls. A larger call budget cannot repair a poor model, unsuitable initial values, or unidentifiable parameters.
What curve_fit does
curve_fit fits a nonlinear model to data by least squares. The model has the form ydata = f(xdata, *params) + eps: the callable receives the independent variable first, followed by each fitted parameter as a separate positional argument. It returns popt, the fitted parameter values, and pcov, an estimated covariance matrix. SciPy recommends using float64 inputs and model outputs; other dtypes can produce incorrect optimization results. See the SciPy curve_fit reference.
As an Amazon Associate I earn from qualifying purchases.
Set an initial guess with p0
p0 is one starting estimate for each fitted parameter, in exactly the order they appear in the model signature. When omitted, SciPy uses 1 for every parameter if it can infer their number from the callable; if it cannot infer the number, it raises ValueError. An all-ones start may be unsuitable when parameters differ in scale, sign, or meaning.
Estimate starting values from the data, the model’s physical meaning, or a simpler preliminary fit. The values need not be the final answer, but should be plausible enough to give the local optimizer a useful starting point.
#1 Best Overall
Constrain parameters with bounds
bounds is a pair of lower and upper limits. Each side may be a scalar applied to all parameters or an array with one limit per parameter. Infinite limits leave a side unconstrained. You can also pass a scipy.optimize.Bounds object; it supports equal lower and upper limits for fixing variables. See the SciPy Bounds reference.
Use limits only when the model or domain justifies them. Check that every initial value lies within the intended feasible region and that the limits are in the correct parameter order. Narrow or incorrect bounds can prevent a valid solution.
Rank #2
The default method is lm when no bounds are given and trf when bounds are supplied. lm does not support bounds; trf and dogbox support box constraints. Supplying bounds therefore changes the default solver as well as the allowed parameter values.
Understand maxfev and the evaluation-limit error
maxfev is not a dedicated top-level argument in the current curve_fit signature. curve_fit accepts extra keyword arguments and passes them to its underlying solver. For the lm method, the underlying leastsq option maxfev sets the maximum number of calls to the function.
The SciPy leastsq reference documents defaults of 200*(N+1) function calls without a supplied Jacobian and 100*(N+1) with one, where N is the number of fitted variables. These are leastsq defaults for the lm path; do not assume they apply to bounded trf or dogbox fits.
If you see Optimal parameters not found: The maximum number of function evaluations is exceeded., the solver reached its call limit before meeting its stopping conditions. Increasing the budget may help if it was making progress. It does not establish that a resulting fit is correct, nor does it fix an unsuitable model or starting point.
A practical fit setup
This example shows the argument pattern, not universal parameter values. Choose p0 and bounds to match your own data and model.
import numpy as np
from scipy.optimize import curve_fit
def model(x, amplitude, rate, offset):
return amplitude * np.exp(-rate * x) + offset
p0 = [2.0, 1.0, 0.2]
bounds = ([0.0, 0.0, -np.inf], [10.0, 5.0, np.inf])
popt, pcov = curve_fit(
model, xdata, ydata,
p0=p0,
bounds=bounds,
maxfev=10000,
)
Here, the bounds select the bounded-fit path, whose default method is trf. The maxfev example illustrates forwarding an extra keyword; for a solver other than lm, check which options that solver supports rather than assuming leastsq defaults or behavior.
Best Value
Diagnose a fit that will not converge
- Check the callable and data. Put the independent variable first and fitted parameters after it. Confirm that
xdata,ydata, and model output have compatible shapes, usefloat64, and contain finite values. SciPy’scheck_finitebehavior is documented in the curve_fit reference; disabling checks can allow nonsensical results. - Choose p0 deliberately. Supply one plausible value per parameter and verify the order against the callable signature instead of relying on the all-ones default.
- Review bounds. Use limits supported by domain knowledge, and confirm the initial values and feasible ranges are consistent. Remember that bounds change the default method from
lmtotrf. - Consider parameter scale. SciPy warns that parameters should have similar scales. For
trfordogbox,x_scalecan help when magnitudes differ substantially. Scaling and the evaluation budget address different issues. - Raise the budget selectively. If the solver is progressing and simply hits its call limit, provide a larger budget supported by the chosen method. Otherwise, revisit the model, initial values, bounds, and scaling first.
- Assess whether the fit is trustworthy. Examine residuals, whether estimates are plausible, and the covariance matrix. A large condition number for
pcovcan signal unreliable estimates; redundant parameters can make it extremely ill-conditioned and leave estimates ambiguous.
Know when curve_fit is not the right tool
curve_fit is a local least-squares method. If you need more direct least-squares control, SciPy points to least_squares; for global optimization or different objective functions, its documentation also points to SciPy’s global optimization tools and LMFIT. The SciPy optimization index lists related tools.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




