Recommended Free Tools
To fit a probability distribution to a sample in Python, use scipy.stats.fit; to fit a function to paired x-y observations, use scipy.optimize.curve_fit. They solve different problems. This guide shows how to choose the right API, set parameter bounds, inspect the result, and assess whether the fitted model is a reasonable one. Examples and API details refer to the SciPy v1.18.0 documentation; check the reference for your installed version because signatures and defaults can vary.
Choose the SciPy fit API that matches your data
| Your task | API | What it fits |
|---|---|---|
| Estimate a named probability distribution from sample values | scipy.stats.fit or a continuous distribution instance’s fit method |
A distribution family and its parameters, typically using likelihood-based estimation |
| Estimate parameters in a specified function from paired measurements | scipy.optimize.curve_fit |
A callable model relating independent values to observed responses |
| Minimize a custom residual vector, including with robust loss | scipy.optimize.least_squares |
User-defined residuals, with controls such as bounds and loss function |
| Test whether a sample is compatible with a distribution family | scipy.stats.goodness_of_fit |
A goodness-of-fit statistic calibrated by Monte Carlo simulation |
These are separate operations, not interchangeable spellings of one fit function. If your data are a one-dimensional sample and you want a distribution such as a normal or negative-binomial family, start with distribution fitting. If each observation has an x value and a corresponding y value, define a model and use curve fitting.
As an Amazon Associate I earn from qualifying purchases.
Fit a distribution to sample values
The top-level scipy.stats.fit API accepts a distribution object, one-dimensional data, and bounds that define the parameter search space. Bounds should reflect plausible values for the problem rather than arbitrary extremes. SciPy notes that tighter bounds containing the maximum-likelihood estimate make convergence more likely.
Example: bounded negative-binomial fit
The SciPy v1.18.0 reference demonstrates fitting a negative-binomial distribution to generated observations with bounded shape parameters. The exact numerical result is stochastic and can vary with the default optimizer, so treat this as an example of the workflow, not a promised output:
#1 Best Overall
import numpy as np
from scipy import stats
rng = np.random.default_rng(123)
data = stats.nbinom.rvs(5, 0.4, size=1_000, random_state=rng)
result = stats.fit(
stats.nbinom,
data,
bounds={"n": (1, 20), "p": (0.05, 0.95)},
)
print(result.params)
print(result.success, result.message)
result.plot()
For the top-level API, bounds can be a mapping of parameter names to ranges or a sequence of ranges. A sequence must include bounds for every shape parameter; location and scale bounds may follow. Unless supplied, location and scale are fixed at 0 and 1. Equal lower and upper endpoints fix a parameter at that value. Input data containing non-finite values raise ValueError. See the SciPy stats.fit reference for the accepted details.
Read the fit result before trusting it
The returned FitResult includes the named parameter tuple in result.params, as well as optimizer status and message. Inspect those fields, the negative log likelihood, and a plot comparing the fitted probability mass function or density with the normalized sample histogram. A successful optimizer status says the optimization completed; it does not establish that the distribution family is appropriate for the data.
Distribution instance methods
Univariate continuous distribution instances also provide a fit method. SciPy documents these methods as maximum-likelihood estimation and supports regular or censored observations represented by CensoredData. This method is distinct from the top-level scipy.stats.fit, particularly when you need explicit bounded fitting or are working with discrete distributions. The probability distributions tutorial cautions that default starting parameters do not work for every distribution.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Fit a curve to paired x-y measurements
Use curve_fit when your observations are represented by independent values xdata and responses ydata, and you have a model of the form ydata = f(xdata, *params) + eps. The model’s first argument is the independent variable; its remaining arguments are the parameters to estimate.
Rank #3
Example: exponential decay
This example follows the model structure used in SciPy’s reference, with an exponential decay function and parameter bounds. The returned popt contains the estimated parameters; pcov is an approximate covariance matrix.
import numpy as np
from scipy.optimize import curve_fit
def decay(x, amplitude, rate, offset):
return amplitude * np.exp(-rate * x) + offset
# xdata and ydata are paired measurements.
popt, pcov = curve_fit(
decay,
xdata,
ydata,
bounds=([0, 0, -np.inf], [np.inf, np.inf, np.inf]),
)
print(popt)
print(pcov)
Use floating-point 64-bit inputs and model outputs. Apply bounds when parameter limits are known, and take care when parameters have very different scales. The covariance estimate is local to the fitted solution: a poor Jacobian rank or a large covariance condition number can signal unreliable estimates. The curve_fit reference explains uncertainty weighting: sigma can be standard deviations in scalar or one-dimensional form, or a covariance matrix in two-dimensional form. By default, absolute_sigma=False scales covariance to residual variance; with absolute_sigma=True, supplied uncertainty is treated as absolute.
Rank #4
- Used Book in Good Condition
Use least squares when you need residual-level control
scipy.optimize.least_squares is a better fit for problems where you want to define the residual vector directly or choose a robust loss function. Its documentation demonstrates ordinary least squares alongside soft-L1 and Cauchy losses on data with outliers. Robust losses reduce the influence of large residuals, but they do not validate the model or make parameter estimates automatically correct. See the least_squares reference and SciPy’s optimization tutorial.
Test distribution fit separately from estimating parameters
A fitted parameter set is not a goodness-of-fit test. To assess whether a sample is compatible with a distribution family, scipy.stats.goodness_of_fit uses Monte Carlo simulation and supports Anderson-Darling, Kolmogorov-Smirnov, Cramér-von Mises, and Filliben statistics.
Best Value
- Used Book in Good Condition
The procedure refits unknown parameters for each simulated sample. That makes it more appropriate than treating parameters estimated from the observed sample as if they were known, but repeated fitting can be slow for families that require numerical optimization. SciPy describes the fixed-parameter shortcut as conservative and low power. See the goodness_of_fit reference for the test’s assumptions and options.
Quick Recap
A practical check before reporting a fit
- Confirm whether your input is a sample of values or paired x-y measurements; choose a distribution API or a curve model accordingly.
- Use parameter bounds that match the problem’s plausible domain, and fix parameters with equal endpoints only when they are genuinely known.
- Check optimizer status and fitted parameters, then compare the model with the data visually or with a formal goodness-of-fit procedure.
- For curve fitting, inspect the covariance estimate and its condition; use robust least squares when outliers make ordinary residual minimization unsuitable.
- Use documentation for the SciPy version installed in your environment when relying on a particular signature or default.
Official SciPy references
- scipy.stats.fit
- Probability distributions tutorial
- curve_fit
- least_squares
- goodness_of_fit
- Statistical functions reference
- Optimization tutorial
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.




