Skip to content

curvefit_stats.estimators

Joint least-squares estimation with explicit shared-parameter mappings.

GlobalFitGroup fits independent datasets jointly; eiv_curve_fit accounts for independent measurement uncertainty in both axes through SciPy ODR. Numerical helpers are shared with inference without circular imports.

GlobalFitGroup

Fit named datasets with shared and dataset-specific model parameters.

Parameters:

Name Type Description Default
model callable

Common model model(x, *parameters). Keyword-only options are not fitted. Different model functions per dataset are not supported.

required
datasets mapping

Nonempty mapping of dataset names to dictionaries containing x, y, and optional sigma. Scalar/vector y and x with observations on the last axis are supported. sigma is a positive scalar/vector standard deviation or a positive-definite observation covariance. Inputs are copied.

required
shared_parameters set or mapping

Set of local model parameter names shared across all datasets, or a map from local names to shared global aliases. Explicit repeated aliases tie those model parameters to one global variable. Unlisted parameters receive independent dataset-specific variables.

frozenset()
parameter_names sequence of str

Explicit names in model argument order, required for ambiguous/variadic model signatures. Overrides names but must match an inferable count.

None

Returns:

Type Description
GlobalFitGroup

Configured fitting group; call fit to obtain parameter estimates, covariance, predictions, residuals, and diagnostics.

Raises:

Type Description
ValueError

Invalid dataset names/shapes, uncertainties, parameter names, or sharing mappings. Optimizer validation is deferred to fit.

Notes

The joint objective is sum_d r_d.T @ inv(C_d) @ r_d, using one optimized variable for each shared global degree of freedom. Global covariance is obtained from the joint whitened residual Jacobian.

Shared globals follow first occurrence in model argument order. Dataset names are sorted lexically; their local globals follow model argument order and are named 'dataset.parameter'. Shared aliases are bare identifiers. The public parameter_indices property exposes local-to-global integer maps.

Errors are independent between datasets. sigma=None means unit relative weight, or known unit variance when absolute_sigma=True. With False one unknown scale multiplies the entire block-diagonal observation covariance; separate unknown variance scales per dataset are not estimated. Cross-dataset error covariance is unsupported. The solver finds a local optimum, and rank diagnoses local numerical dependence rather than structural identifiability.

Examples:

>>> import numpy as np
>>> model = lambda x, slope, intercept: slope*x+intercept
>>> group = GlobalFitGroup(model, {
...     'a': {'x': np.arange(3.), 'y': [1., 3., 5.]},
...     'b': {'x': np.arange(4.), 'y': [3., 5., 7., 9.]},
... }, shared_parameters={'slope'})
>>> result = group.fit([1., 0., 0.], absolute_sigma=True)
>>> result.parameter_names
('slope', 'a.intercept', 'b.intercept')
>>> np.allclose(result.popt, [2., 1., 3.])
True
>>> result.success
True

parameter_names property

parameter_names: tuple[str, ...]

Return global parameter names in their optimization vector order.

model_parameter_names property

model_parameter_names: tuple[str, ...]

Return local names in model argument order.

dataset_names property

dataset_names: tuple[str, ...]

Return datasets in residual-concatenation order.

parameter_indices property

parameter_indices: Mapping[str, _Index]

Return independent local-to-global index copies for each dataset.

__init__

__init__(model: _Model, datasets: Mapping[str, Mapping[str, ArrayLike | None]], shared_parameters: Set[str] | Mapping[str, str] = frozenset(), *, parameter_names: Sequence[str] | None = None) -> None

Validate data and build an explicit deterministic parameter mapping.

fit

fit(p0: ArrayLike | Mapping[str, float] | None = None, bounds: tuple[Any, Any] | Mapping[str, tuple[float, float]] = (-np.inf, np.inf), *, absolute_sigma: bool = False, jac: _Jacobian = '3-point', rank_tolerance: float | None = None, **kwargs: Any) -> _GlobalFitResult

Optimize one global parameter vector and estimate its joint covariance.

Parameters:

Name Type Description Default
p0 array_like or mapping

Vector in parameter_names order or complete mapping from global names to values. Defaults to ones for unbounded variables and feasible midpoints/interior points for bounded variables.

None
bounds tuple or mapping

Scalar/vector (lower, upper) or global-name-to-(lower, upper) map. Omitted names are unbounded. Equal limits denote exactly fixed parameters; they are removed from the optimizer vector.

(-inf, inf)
absolute_sigma bool

True uses known observation variances. False scales covariance by weighted SSE/(N-p), counting each estimated shared variable once.

False
jac ('2-point', '3-point')

Finite differences obey optimization bounds. A callable returns the local model Jacobian, shape (n_dataset, n_model_parameters), from jac(x, *local_parameters). Shared/tied columns are assembled and whitened automatically. Complex-step differentiation is unsupported.

'2-point'
rank_tolerance float

Relative singular-value cutoff on column-normalized Jacobians. Default is max(N,p)*eps for analytic derivatives and at least 1e-7 for numerical derivatives. Supply an analytic jac to resolve very close directions; rank deficiency never produces a finite pseudoinverse.

None
**kwargs Any

Supported scipy.optimize.least_squares options. Only loss='linear' is allowed, preserving Gaussian least-squares covariance semantics. Array x_scale, diff_step, and jac_sparsity refer to non-fixed variables in global order. Solver args/kwargs overrides are not supported.

{}

Returns:

Name Type Description
result typed dataclass

popt, pcov, parameter_names, datasets, weighted_residuals, jacobian, active_mask, solver, and diagnostics. Each datasets[name] contains parameters, local popt, predictions, and raw/weighted residuals. result.success reflects solver convergence, not identifiability.

Raises:

Type Description
ValueError

Invalid guesses, bounds, solver options, uncertainties, or Jacobians.

FloatingPointError

Weighted residuals or numerical Jacobian calculations are non-finite.

Notes

For an interior full-rank global Jacobian J_r, covariance is inv(J_r.T @ J_r), multiplied by weighted SSE/(N-p) only for relative error scales. Equal bounds remove exactly fixed variables.

Optimization internally divides residuals/Jacobians by a common initial residual magnitude to avoid dependence on arbitrary common error units. Returned residuals, Jacobian, solver cost and optimality are restored to the original weighted units. SciPy gtol applies to the normalized objective; ftol and xtol retain their relative meanings. This improves common-scale invariance, not global-optimum guarantees.

Covariance comes from the actual global residual Jacobian. With active bounds it is conditional on active values: active rows/columns are NaN, and the free block uses N-p_free scaling. diagnostics.dof remains N-p for all optimized variables; covariance_dof explicitly reports N-p_free. Failed convergence or a rank-deficient optimized Jacobian gives all-NaN covariance. Full rank does not prove structural or global identifiability. When all parameters are fixed, success indicates model evaluation only: solver.status is None and nfev/njev are zero; SciPy options are not run. Results can still be inspected when success=False. Ordinary nonlinear Wald uncertainty is only a local approximation.

Examples:

>>> group = GlobalFitGroup(lambda x, a: a*x, {
...     'run': {'x': [1., 2., 3.], 'y': [2.1, 3.9, 6.0]},
... }, {'a'})
>>> result = group.fit({'a': 1.}, bounds={'a': (0., 5.)})
>>> abs(result.datasets['run'].parameters['a']-2) < 0.02
True

eiv_curve_fit

eiv_curve_fit(func: _Model, xdata: ArrayLike, ydata: ArrayLike, p0: ArrayLike | None = None, *, sx: ArrayLike | None = None, sy: ArrayLike | None = None, absolute_sigma: bool = False, full_output: Literal[False] = False, **kwargs: Any) -> tuple[_Array, _Array]
eiv_curve_fit(func: _Model, xdata: ArrayLike, ydata: ArrayLike, p0: ArrayLike | None = None, *, sx: ArrayLike | None = None, sy: ArrayLike | None = None, absolute_sigma: bool = False, full_output: Literal[True], **kwargs: Any) -> tuple[_Array, _Array, _ODRDiagnostics]
eiv_curve_fit(func: _Model, xdata: ArrayLike, ydata: ArrayLike, p0: ArrayLike | None = None, *, sx: ArrayLike | None = None, sy: ArrayLike | None = None, absolute_sigma: bool = False, full_output: bool, **kwargs: Any) -> tuple[_Array, _Array] | tuple[_Array, _Array, _ODRDiagnostics]
eiv_curve_fit(func: _Model, xdata: ArrayLike, ydata: ArrayLike, p0: ArrayLike | None = None, *, sx: ArrayLike | None = None, sy: ArrayLike | None = None, absolute_sigma: bool = False, full_output: bool = False, **kwargs: Any) -> tuple[_Array, _Array] | tuple[_Array, _Array, _ODRDiagnostics]

Fit scalar errors-in-variables models through SciPy's ODRPACK backend.

Parameters:

Name Type Description Default
func callable

Pointwise model written as func(x, *parameters). The adapter reverses arguments for ODR internally. Non-vectorized scalar callables and responses coupling observations are unsupported.

required
xdata array_like

Finite, nonempty one-dimensional observations of identical length. Only one independent variable and one scalar response are supported.

required
ydata array_like

Finite, nonempty one-dimensional observations of identical length. Only one independent variable and one scalar response are supported.

required
p0 array_like

Finite initial parameters. When omitted, explicit positional parameter names are inferred and initialized to ones, as in curve_fit. Ambiguous or variadic signatures require p0; keyword-only options are not fitted.

None
sx array_like

Positive scalar/vector independent-variable standard deviations. None treats x as exact using ODR's least-squares mode, not unit x error. Zero elements are rejected; fixing selected x observations is unsupported.

None
sy array_like

Positive scalar/vector dependent-variable standard deviations. None means unit y weighting, or known unit y variance with absolute_sigma=True.

None
absolute_sigma bool

True returns unscaled Output.cov_beta for known absolute error scales. False returns cov_beta*Output.res_var, matching ODR's sd_beta convention. One common unknown scale multiplies both axis covariance specifications.

False
full_output bool

False returns (popt, pcov). True additionally returns a typed diagnostics dataclass with termination, rank, residual variance, weighted objective, coordinate corrections, and scaled/unscaled uncertainty information.

False
**kwargs Any

ODR controls maxit (default 200), sstol, partol, ndigit, and taufac only. maxit may be zero for diagnostic evaluation. sigma, jac, bounds, method, maxfev, robust losses, and other curve_fit options are rejected.

{}

Returns:

Name Type Description
popt, pcov : ndarray

Parameter vector and covariance of shapes (p,) and (p, p).

diagnostics typed dataclass, optional

Returned with full_output=True. adjusted_x=xdata+delta and fitted_y is func(adjusted_x, popt). eps is fitted_y-ydata, the ODR sign convention. standard_errors correspond to returned pcov; backend_standard_errors always follow cov_betares_var. dof=N-p only for identified solutions.

Raises:

Type Description
ValueError

Invalid data, uncertainties, parameter guesses, controls, or N <= p.

RuntimeError

Missing/unsupported backend or nonconvergence with full_output=False.

FloatingPointError

Unrepresentable weights or non-finite fitted parameters/results.

Notes

Supports SciPy >=1.12,<1.19. scipy.odr is deprecated in 1.17 and removed in 1.19. Calls on deprecated versions emit a FutureWarning; the backend import deprecation is translated into that explicit compatibility warning. No replacement dependency is installed. This is not a full curve_fit substitute: bounds, correlated axis errors, multiple predictors, fixed parameters, and analytic ODR derivatives are outside this interface.

With full_output=True, nonconvergence warns and returns current estimates, all-NaN pcov, and success=False. Rank deficiency similarly warns and returns NaN covariance even when the optimizer converged. Full rank is a local numerical diagnostic, not proof of structural identifiability. A numerical relative rank cutoff of at least 1e-7 avoids finite uncertainties fabricated by finite-difference noise in dependent parameter columns.

ODR covariance is a local Gauss-Newton approximation. For independent errors the weighted objective is sum((delta/sx)2)+sum((eps/sy)2); the first term is zero in exact-x mode. For identified fits res_var=objective/(N-p). Zero residual variance makes scaled covariance degenerate and warns. At least one residual degree of freedom is required, including absolute-scale fits. Outputs are copies; inputs are not mutated.

Examples:

>>> import warnings
>>> with warnings.catch_warnings():
...     warnings.simplefilter('ignore', FutureWarning)
...     popt, pcov = eiv_curve_fit(lambda x, slope: slope*x,
...         [1., 2., 3., 4.], [2.1, 3.9, 6.1, 7.9], [2.],
...         sx=0.05, sy=0.1, absolute_sigma=True)
>>> abs(popt[0]-2) < 0.02 and pcov.shape == (1, 1)
True