curvefit_stats.inference ¶
Local and resampling inference for nonlinear least-squares models.
Only NumPy and SciPy are required. Model calls use func(x, *parameters).
Observations and model outputs are scalar or one-dimensional; coordinates may
be multidimensional with observations on the last axis. All computations use
float64. None of these methods establishes structural identifiability or exact
coverage for arbitrary nonlinear models.
generate_error_bands ¶
generate_error_bands(func: _Model, x: ArrayLike, popt: ArrayLike, pcov: ArrayLike, y: ArrayLike | None = None, alpha: float = 0.05, interval_type: Literal['confidence', 'prediction'] = 'confidence', *, x_fit: ArrayLike | None = None, dof: int | None = None, jac: _Jacobian | None = None, prediction_variance: float | ArrayLike | None = None, reference: Literal['student-t', 'normal'] = 'student-t') -> tuple[_Array, _Array]
Return pointwise Delta Method confidence or prediction bands.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
callable
|
Model evaluated as |
required |
x
|
array_like
|
Evaluation coordinates; observations occupy the last axis. |
required |
popt
|
array_like
|
Fitted parameter vector of length p. |
required |
pcov
|
array_like
|
Finite positive-semidefinite parameter covariance, shape (p, p). |
required |
y
|
array_like
|
Original fitting observations. Used to infer degrees of freedom and, for prediction intervals, unknown common independent noise variance. |
None
|
alpha
|
float
|
Two-sided significance level. |
0.05
|
interval_type
|
('confidence', 'prediction')
|
Confidence for fitted means or prediction for future scalar observations. |
'confidence'
|
x_fit
|
array_like
|
Fitting coordinates aligned with y; defaults to x when y is supplied. |
None
|
dof
|
int
|
Positive fitting residual degrees of freedom for Student-t intervals. Required if y is absent. Never inferred from an evaluation-only grid. |
None
|
jac
|
callable
|
Model parameter Jacobian of shape (n_evaluation, p). Without jac, numerical differentiation scales parameters by max(abs(popt), parameter standard deviation), using one for zero scales. Central differences are refined until successive columns agree within 1e-6 relative norm, with at most 40 refinements. Supply jac for nonsmooth models or derivatives that do not stabilize. |
None
|
prediction_variance
|
float or array_like
|
Nonnegative future-observation variances in evaluation order. Required for known, heteroscedastic, or correlated noise; includes only marginal noise and assumes future noise is independent of parameter estimation. |
None
|
reference
|
('student-t', 'normal')
|
Use 'normal' explicitly for known absolute Gaussian error scales. That option does not require dof and never estimates noise from residuals. |
'student-t'
|
Returns:
| Type | Description |
|---|---|
lower_band, upper_band : ndarray
|
One-dimensional arrays, including for a single evaluation point. |
Raises:
| Type | Description |
|---|---|
ValueError
|
Invalid data/covariance, interval options, prediction variance, or dof. |
FloatingPointError
|
Non-finite numerical calculations or unrepresentable band endpoints. |
Notes
At each point, mean variance is j @ pcov @ j.T. Endpoints are f(x, popt) +/- q * sqrt(mean_variance + future_variance), where the future term is zero for confidence intervals. q is the specified normal or Student-t upper-tail quantile at alpha/2.
These are pointwise, not simultaneous, intervals. Residual-based prediction assumes independent homoscedastic Gaussian errors with unknown variance. The API cannot infer a noise model from pcov; choosing it is the caller's responsibility. Linearization may be unreliable near bounds or in strongly nonlinear or non-identifiable models. Unrepresentable band endpoints raise FloatingPointError instead of returning infinite or collapsed bands. Singular covariance permits zero mean uncertainty in its nullspace. A nonzero projection onto its positive-variance support that underflows to zero instead raises FloatingPointError.
Examples:
>>> import numpy as np
>>> lo, hi = generate_error_bands(lambda x, a: a*x, [1., 2.],
... [2.], [[0.01]], dof=8)
>>> bool(np.all(lo < hi))
True
audit_fit ¶
audit_fit(func: _Model, x: ArrayLike, y: ArrayLike, popt: ArrayLike, sigma: ArrayLike | None = None, absolute_sigma: bool = False) -> dict[str, float]
Calculate Gaussian goodness-of-fit and likelihood-consistent AIC/BIC.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
callable
|
Model |
required |
x
|
array_like
|
Fitting coordinates and aligned scalar observations. |
required |
y
|
array_like
|
Fitting coordinates and aligned scalar observations. |
required |
popt
|
array_like
|
Estimated parameters. |
required |
sigma
|
array_like
|
Positive standard deviations (scalar/vector) or full positive-definite observation covariance, with the same interpretation as curve_fit. |
None
|
absolute_sigma
|
bool
|
True treats sigma as known; absent sigma then means known unit variance. False estimates one common scale multiplying the supplied covariance. |
False
|
Returns:
| Type | Description |
|---|---|
dict
|
Counts, dof, rss, rmse, residual_variance, chi_square, reduced_chi_square, aic, and bic. Counts are returned as floats. |
Raises:
| Type | Description |
|---|---|
ValueError
|
Invalid observations, parameters, sigma, absolute_sigma, or a numerically rank-deficient parameter Jacobian incompatible with regular criteria. |
FloatingPointError
|
Residual sums or likelihood quantities are outside float64 range. |
Notes
For observation covariance C, Q = r.T @ inv(C) @ r. Known-scale deviance is Nlog(2pi) + logdet(C) + Q, with K=p. Unknown-scale deviance is N(log(2pi)+1+log(Q/N)) + logdet(C), with K=p+1. AIC = deviance+2K; BIC = deviance+Klog(N).
AIC/BIC assume maximum-likelihood input estimates and count every supplied parameter. Fixed/tied parameters require a reduced model/vector; singular and boundary models need separate likelihood/parameter-count calibration. Arbitrary estimates merely evaluate a likelihood, not valid model criteria. A column-normalized, whitened numerical Jacobian must have full rank at relative cutoff max(1e-7, max(N,p)*eps); otherwise the audit rejects the input rather than reporting regular criteria with an invalid parameter count. Rank checks do not verify maximum likelihood or boundary regularity.
AIC/BIC retain the Gaussian normalization constant for consistent likelihood comparisons. Unknown scale counts as an additional fitted parameter. The unweighted residual variance is RSS/(N-p), even for weighted fits; it is not an estimate of a heteroscedastic covariance. Without known or supplied weights, chi-square is undefined (NaN). Nonpositive dof makes residual variance and reduced chi-square NaN. Zero weighted RSS with unknown scale has an unbounded likelihood and returns NaN AIC/BIC with a warning. Nonzero squared residuals outside float64 range raise FloatingPointError rather than falsely reporting an exact fit or infinite likelihood metrics.
Examples:
>>> result = audit_fit(lambda x, a: a*x, [1., 2., 3.],
... [2.1, 3.9, 6.0], [2.])
>>> round(result['rss'], 2)
0.02
fit_summary ¶
fit_summary(func: _Model, x: ArrayLike, y: ArrayLike, popt: ArrayLike, pcov: ArrayLike, param_names: list[str] | None = None, *, alpha: float = 0.05, precision: int = 5) -> str
Produce an aligned ASCII table of approximate nonlinear Wald inference.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
callable
|
Model |
required |
x
|
array_like
|
Original aligned fitting data, used to determine N-p. |
required |
y
|
array_like
|
Original aligned fitting data, used to determine N-p. |
required |
popt
|
array_like
|
Parameter estimates and their covariance. |
required |
pcov
|
array_like
|
Parameter estimates and their covariance. |
required |
param_names
|
list of str
|
Explicit parameter names overriding signature inspection. |
None
|
alpha
|
float
|
Two-sided significance level. |
0.05
|
precision
|
int
|
Positive number of significant digits in numeric columns. |
5
|
Returns:
| Type | Description |
|---|---|
str
|
Table with estimates, standard errors, t-statistics, two-tailed p-values, confidence endpoints, sample size, dof, and confidence level. |
Raises:
| Type | Description |
|---|---|
ValueError
|
Invalid data, covariance shape/finite PSD values, names, alpha, or precision. |
FloatingPointError
|
A roundoff covariance repair produces unrepresentable numerical results. |
Notes
SE_i = sqrt(pcov[i,i]); t_i = popt[i]/SE_i. Two-sided p-values are 2*StudentT.sf(abs(t_i), N-p), and intervals use the Student-t upper-tail quantile at alpha/2. This function always uses Student-t, including when a caller supplies known-scale or ODR covariance; it does not automatically calibrate those alternative estimator conventions.
These are approximate Wald tests against zero, not exact nonlinear tests. Singular covariance or a rank-deficient/unverifiable parameter Jacobian produces NaN standard errors, tests, and intervals instead of spurious marginal significance. Numerical rank uses column normalization and a relative singular-value cutoff of at least 1e-7. Reduce fixed/tied parameterizations before requesting unrestricted Student-t inference. Invalid finite covariance raises ValueError. Non-finite covariance or nonpositive dof warns and displays NaN for undefined inference. Zero standard errors do not imply infinite significance: tests are shown as NaN. Active bounds, small samples, and non-identifiability invalidate ordinary Wald interpretations; supply an appropriate unrestricted covariance. Overflowing statistics or unrepresentable confidence endpoints warn and display NaN.
Examples:
>>> text = fit_summary(lambda x, slope: slope*x, [1., 2., 3.],
... [2.1, 3.9, 6.0], [2.], [[0.01]])
>>> 'slope' in text and 'Pr(>|t|)' in text
True
profile_likelihood_errors ¶
profile_likelihood_errors(func: _Model, x: ArrayLike, y: ArrayLike, popt: ArrayLike, sigma: ArrayLike | None = None, sigma_level: float = 1.0, bounds: tuple[Any, Any] = (-np.inf, np.inf), *, pcov: ArrayLike | None = None, max_nfev: int = 10000, max_bracket_steps: int = 50, tolerance: float = 1e-06, absolute_sigma: bool = False) -> list[dict[str, float]]
Profile parameters with bounded nuisance fits and likelihood thresholds.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
callable
|
Model |
required |
x
|
array_like
|
Aligned fitting coordinates and observations. |
required |
y
|
array_like
|
Aligned fitting coordinates and observations. |
required |
popt
|
array_like
|
Locally optimal parameters; an appreciably suboptimal input is rejected. |
required |
sigma
|
array_like
|
Standard deviations or positive-definite observation covariance. |
None
|
sigma_level
|
float
|
Normal-equivalent central coverage; 1 corresponds to about 68.27%. |
1.0
|
bounds
|
tuple
|
Scalar or vector lower and upper parameter bounds. |
(-inf, inf)
|
pcov
|
array_like
|
Covariance used only to select initial search step sizes. |
None
|
max_nfev
|
int
|
Limits for each optimizer run and each directional bracket search. |
10000
|
max_bracket_steps
|
int
|
Limits for each optimizer run and each directional bracket search. |
10000
|
tolerance
|
float
|
Positive relative root tolerance. An improvement exceeding tolerancesigma_level*2 on the likelihood-ratio scale rejects the baseline or invalidates the affected profile direction. |
1e-06
|
absolute_sigma
|
bool
|
True uses known Gaussian covariance (unit covariance when sigma is absent). False profiles one unknown scale, including for relative sigma. |
False
|
Returns:
| Type | Description |
|---|---|
list of dict
|
Each parameter has signed |
Raises:
| Type | Description |
|---|---|
ValueError
|
Invalid data, options, bounds, covariance, suboptimal starting estimates, or zero best SSE with unknown scale. |
RuntimeError
|
Baseline nuisance optimization fails. Directional failures instead warn and leave the affected endpoint NaN. |
FloatingPointError
|
Baseline likelihood calculations are outside float64 range. |
Notes
Signed endpoints solve 2(logL_best-logL_profile) = sigma_level*2 after reoptimizing nuisance parameters. The calibration assumes a regular one-parameter chi-square likelihood-ratio reference.
Known-scale likelihood ratios are weighted SSE differences. Unknown-scale ratios are Nlog(SSE_profile/SSE_best); a zero best SSE is undefined. Threshold is sigma_level2, equivalent to a chi-square(1) quantile at the specified normal central coverage. Nuisance fits are local, not global. Boundary and nonregular models need specialized coverage calibration. Root tolerances apply to signed parameter displacements, not absolute parameter values. Exactly fixed parameters are never numerically perturbed. Non-finite trial evaluations warn and leave that endpoint unresolved. Root searches allow at most 1000 iterations. A returned finite endpoint must resolve its likelihood threshold within 10tolerance relative error; an oversized covariance seed cannot turn zero displacement into a crossing. Optimality checks use the same likelihood-ratio scale and threshold, not a fraction of total SSE. Large parameter-independent residuals therefore cannot relax a known-scale optimum check. Near-equal unknown-scale SSEs use log1p to avoid subtracting nearly equal logarithms.
Examples:
>>> intervals = profile_likelihood_errors(lambda x, a: a*x,
... [1., 2., 3.], [2.1, 3.9, 6.0], [1.992857142857],
... sigma=[0.1, 0.1, 0.1], absolute_sigma=True)
>>> intervals[0]['down'] < 0 < intervals[0]['up']
True
bootstrap_curve_fit ¶
bootstrap_curve_fit(func: _Model, x: ArrayLike, y: ArrayLike, p0: ArrayLike | None = None, n_resamples: int = 1000, random_state: int | None = None, **kwargs: Any) -> tuple[_Array, _Array, _Array]
Refit a fixed number of centered, exchangeable residual resamples.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
callable
|
SciPy-style model. |
required |
x
|
array_like
|
Original aligned data. |
required |
y
|
array_like
|
Original aligned data. |
required |
p0
|
array_like
|
Initial guess for the base fit; SciPy signature inference otherwise. |
None
|
n_resamples
|
int
|
Number of attempted replicates, not a requested number of successes. |
1000
|
random_state
|
int
|
Seed for a local numpy.random.Generator. |
None
|
**kwargs
|
Any
|
Compatible curve_fit options, including bounds and analytic jac. sigma, full_output=True, nan_policy, and check_finite=False are rejected. |
{}
|
Returns:
| Type | Description |
|---|---|
mean, covariance, samples : ndarray
|
Shapes (p,), (p, p), and (n_successful, p). Covariance uses B-1. |
Raises:
| Type | Description |
|---|---|
ValueError
|
Invalid data, replicate count, seed, or unsupported bootstrap options. |
RuntimeError
|
Base covariance is unusable or fewer than two replicates succeed; a base optimizer failure also propagates. |
FloatingPointError
|
Empirical mean or covariance is outside float64 range. |
TypeError
|
An unsupported keyword reaches scipy.optimize.curve_fit. |
Notes
For B successful parameter samples theta_b, the empirical covariance is sum(outer(theta_b-mean, theta_b-mean))/(B-1). Returned samples are rows, and no residual degrees-of-freedom inflation is applied.
Fits internally subtract a common response origin and normalize response units, including supplied analytic Jacobians. This prevents absolute trust-region stopping tolerances from certifying an unchanged initial guess in tiny response units. Known-unit base/refit covariance is transformed back before reliability checks; returned bootstrap samples retain parameter units.
Assumes independent, identically distributed observation errors with zero mean. Fitted residuals are generally correlated and have leverage-dependent variances; their empirical distribution is an approximation to the error law. Residuals are centered before resampling; no leverage correction is applied. Population covariance consistency requires regular fitting and a suitable asymptotic design (for example, vanishing maximum leverage), not just finite successful refits. Finite-sample covariance is not generally unbiased. Population parameter covariance must exist; ordinary least squares requires finite error variance. Weighted/correlated noise is not supported by this bootstrap. An invalid/non-finite/singular base covariance or rank-deficient parameter Jacobian raises RuntimeError before resampling. Each refit is checked as well, including trust-region pseudoinverse covariance without OptimizeWarning. Numerical Jacobian rank uses a column-normalized relative cutoff of at least 1e-7; analytic jac uses max(N,p)*eps. Supply analytic jac for models whose derivatives cannot be evaluated in an open neighborhood of a bound. A full- rank exact fit may return zero empirical spread; this does not establish zero population parameter uncertainty. Failed fits are excluded with a count warning; fewer than two successes raises RuntimeError. Less than 90% success triggers an additional warning. This does not provide universal outlier robustness or fix model misspecification. Non-finite synthetic observations count as failures. Unrepresentable empirical mean/covariance raises FloatingPointError; rescale parameters in that case.
Examples:
>>> mean, covariance, samples = bootstrap_curve_fit(lambda x, a: a*x,
... [1., 2., 3., 4.], [2.1, 3.9, 6.1, 7.9], [2.],
... n_resamples=10, random_state=3)
>>> samples.shape, covariance.shape
((10, 1), (1, 1))
collinearity_diagnostics ¶
collinearity_diagnostics(pcov: ArrayLike, *, correlation_threshold: float = 0.99) -> dict[str, Any]
Diagnose covariance-derived local parameter dependence.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pcov
|
array_like
|
Square parameter covariance matrix. |
required |
correlation_threshold
|
float
|
Absolute off-diagonal correlation flag threshold, strictly between 0 and 1. |
0.99
|
Returns:
| Type | Description |
|---|---|
dict
|
correlation_matrix, vif, max_abs_correlation, condition_number, high_correlation_pairs, potential_identifiability_issue, and rank. Rank is None when non-finite covariance prevents its determination. Pair indices are zero-based. Condition and rank refer to correlation among parameters with positive variance; invalid zero-variance directions are excluded and flagged. Singular valid correlation has infinite VIF and condition number rather than a finite pseudoinverse substitute. |
Raises:
| Type | Description |
|---|---|
ValueError
|
Invalid covariance shape, finite PSD values, or correlation threshold. |
FloatingPointError
|
A roundoff covariance repair produces unrepresentable numerical results. |
Notes
For positive variances, R[i,j] = V[i,j]/sqrt(V[i,i]*V[j,j]), vif = diag(inv(R)), and condition_number = max(eig(R))/min(eig(R)). These use correlation units, not the raw covariance condition number.
VIF-like values are inverse correlation diagonals from a stable solver. They are not generally classical design-matrix VIFs for nonlinear models. Strong correlation indicates local dependence, not structural non-identifiability.
Examples:
>>> result = collinearity_diagnostics([[1., 0.5], [0.5, 1.]])
>>> result['high_correlation_pairs']
[]
robust_bounded_pcov ¶
robust_bounded_pcov(func: _Model, x: ArrayLike, y: ArrayLike, popt: ArrayLike, bounds: tuple[Any, Any], *, sigma: ArrayLike | None = None, absolute_sigma: bool = False, jac: _Jacobian | None = None, bound_tolerance: float = 1e-08) -> _Array
Estimate conditional local covariance of parameters away from bounds.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
callable
|
Model |
required |
x
|
array_like
|
Aligned fitting data. |
required |
y
|
array_like
|
Aligned fitting data. |
required |
popt
|
array_like
|
Parameters within bounds. |
required |
bounds
|
tuple
|
Scalar or vector lower/upper bounds; equality denotes an exactly fixed parameter but still produces NaN covariance rows/columns here. |
required |
sigma
|
array_like
|
Standard deviations or positive-definite observation covariance. |
None
|
absolute_sigma
|
bool
|
If False, scale free covariance by weighted RSS/(N-p_free). |
False
|
jac
|
callable
|
Model Jacobian of shape (N, p); finite differences otherwise. |
None
|
bound_tolerance
|
float
|
Nonnegative tolerance multiplied by max(1, |parameter|, |finite bound|) separately for each bound. Numerical derivatives of free parameters require the model to be defined in a small open neighborhood. |
1e-08
|
Returns:
| Type | Description |
|---|---|
ndarray
|
Full (p, p) matrix. Active rows/columns are NaN. Free covariance is conditional on active parameters, not unrestricted marginal uncertainty. Rank-deficient free Jacobians or undefined scaling return NaN blocks. |
Raises:
| Type | Description |
|---|---|
ValueError
|
Invalid data, parameters, bounds, sigma, Jacobian, or activity tolerance. |
FloatingPointError
|
Numerical differentiation or whitening produces non-finite results. |
Notes
Holding active parameters fixed, the free block is approximately inv(J_free.T @ inv(C) @ J_free). Unknown scale multiplies it by Q/(N-p_free). Active rows/columns are NaN, not zero uncertainty.
This does not repair structural non-identifiability, nor infer one-sided uncertainty for active parameters. All-active inputs return all NaN. Conditional means holding active values fixed in the model; it does not calibrate the sampling distribution conditional on selecting that active set. Effective dof is N-p_free under the stated local conditional approximation. Rank is assessed after Jacobian column normalization, then covariance is transformed back to the original parameter units. A covariance outside float64 range warns and returns NaN, rather than finite zero uncertainty.
Examples:
>>> covariance = robust_bounded_pcov(lambda x, a, b: a*x+b,
... [0., 1., 2.], [1., 3., 5.], [2., 1.],
... ([0., 1.], [3., 1.]), absolute_sigma=True)
>>> bool(np.isnan(covariance[1]).all())
True
propagate_uncertainty ¶
propagate_uncertainty(derived_func: Callable[..., Any], popt: ArrayLike, pcov: ArrayLike, *, n_samples: int = 10000, alpha: float = 0.05, random_state: int | None = None, min_valid_fraction: float = 0.9) -> dict[str, Any]
Propagate Gaussian parameter uncertainty by sample-wise Monte Carlo.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
derived_func
|
callable
|
Scalar or fixed-shape vector output from |
required |
popt
|
array_like
|
Parameter mean and finite positive-semidefinite covariance. |
required |
pcov
|
array_like
|
Parameter mean and finite positive-semidefinite covariance. |
required |
n_samples
|
int
|
Number of attempted samples, at least two. |
10000
|
alpha
|
float
|
Two-sided empirical interval significance level. |
0.05
|
random_state
|
int
|
Seed for a local Generator, without modifying global RNG state. |
None
|
min_valid_fraction
|
float
|
Minimum fraction of finite outputs, in (0, 1]; default 0.9. At least two valid outputs are always required. Lower fractions raise ValueError. |
0.9
|
Returns:
| Type | Description |
|---|---|
dict
|
mean, median, std (ddof=1), lower, upper, n_samples, n_valid, n_invalid. Statistics are Python floats for scalar output and arrays for vectors. A vector sample is rejected in full if any component is non-finite. |
Raises:
| Type | Description |
|---|---|
ValueError
|
Invalid covariance, parameter/sample options, changing output shape, or too few valid derived samples. |
FloatingPointError
|
Parameter uncertainty is below float64 resolution or summaries are unrepresentable. Exceptions raised by derived_func propagate unchanged. |
Notes
Draw theta from Normal(popt, pcov), then evaluate g(theta) sample-wise. Standard deviation uses the valid sample count minus one; endpoints are empirical alpha/2 and 1-alpha/2 quantiles, not simultaneous vector regions.
Covariance PSD and rank checks use correlation units so parameter units cannot hide negative variance or create false singularity. Negative diagonal variances are rejected. Correlation eigenvalues in [-100epsp, 0) are repaired with a warning; zero variance requires an exactly zero row and column. Singular covariance warns. Non-finite outputs are counted and warned about; retained quantiles describe the valid subset and may be biased by rejection. A Gaussian approximation may violate physical bounds or miss asymmetric likelihoods. Finite ratio outputs do not guarantee that population moments exist. Unrepresentable numerical summaries or parameter uncertainty below floating point resolution at popt raise FloatingPointError; recenter/rescale instead. Seed reproducibility is guaranteed within a fixed NumPy/LAPACK environment, not bit-for-bit across backend versions or repeated eigenvalue conventions.
Examples:
>>> result = propagate_uncertainty(lambda a, b: a+b, [1., 2.],
... [[0.01, 0.], [0., 0.01]], n_samples=100, random_state=7)
>>> result['n_valid']
100