nlsq.parameter_estimation module

Automatic initial parameter estimation for curve fitting.

This module provides intelligent parameter estimation when users don’t provide initial guesses (p0). It uses heuristics based on data characteristics and function signatures to generate reasonable starting points.

Key Features

  • Automatic p0 estimation: No need to manually guess initial parameters

  • Pattern detection: Recognizes common function types (linear, exponential, gaussian, sigmoid)

  • Smart heuristics: Uses data statistics (range, mean, peaks) to estimate parameters

  • Library function support: Custom functions can provide their own .estimate_p0() method

  • Fallback strategies: Always provides reasonable defaults if pattern detection fails

Examples

Basic usage with automatic p0 estimation:

>>> from nlsq import curve_fit
>>> import jax.numpy as jnp
>>> import numpy as np
>>>
>>> # Define model (no p0 needed!)
>>> def exponential_decay(x, amplitude, rate, offset):
...     return amplitude * jnp.exp(-rate * x) + offset
>>>
>>> # Generate data
>>> x = np.linspace(0, 5, 50)
>>> y = 3 * np.exp(-0.5 * x) + 1 + np.random.normal(0, 0.1, 50)
>>>
>>> # Use p0='auto' for automatic estimation
>>> popt, pcov = curve_fit(exponential_decay, x, y, p0='auto')
>>>
>>> # Note: p0=None (or omitting p0) uses default behavior [1.0, 1.0, ...]
>>> # for backward compatibility
>>> popt, pcov = curve_fit(exponential_decay, x, y)  # Uses default p0
>>>
>>> print(f"Fitted: amplitude={popt[0]:.2f}, rate={popt[1]:.2f}, offset={popt[2]:.2f}")
>>> # Output: Fitted: amplitude=2.95, rate=0.51, offset=1.04

Notes

The automatic parameter estimation works as follows:

  1. Custom estimation: Checks if function has .estimate_p0(xdata, ydata) method

  2. Pattern detection: Analyzes data shape to detect function type

  3. Heuristic estimation: Uses data statistics to estimate parameters:

    • First parameter (amplitude): y_range

    • Second parameter (rate/slope): 1/x_range

    • Third parameter (offset): y_mean

    • Fourth parameter (center): x_mean

  4. Fallback: Returns sensible defaults if all else fails

See also

nlsq.minpack.curve_fit

Main curve fitting function

nlsq.error_messages

Enhanced error messages

nlsq.precision.parameter_estimation.estimate_initial_parameters(f, xdata, ydata, p0=None)[source]

Estimate initial parameters if p0 is None or ‘auto’.

This function attempts to intelligently guess initial parameter values based on the data characteristics when p0 is not provided.

The estimation strategy follows this order: 1. If p0 is provided (not None or ‘auto’), return it unchanged 2. If function has .estimate_p0() method, use it (for library functions) 3. Otherwise, use generic heuristics based on data statistics

Parameters:
  • f (callable) – Model function f(x, p0, p1, …) → y

  • xdata (array_like) – Independent variable data

  • ydata (array_like) – Dependent variable data

  • p0 (array_like or None or 'auto', optional) – Initial guess. If None or ‘auto’, estimate from data.

Returns:

p0_estimated – Initial parameter guess

Return type:

ndarray

Raises:

ValueError – If cannot determine number of parameters from function signature

Examples

Automatic estimation for exponential decay:

>>> import numpy as np
>>> def exponential(x, a, b, c):
...     return a * np.exp(-b * x) + c
>>> xdata = np.linspace(0, 5, 50)
>>> ydata = 3 * np.exp(-0.5 * xdata) + 1
>>> p0 = estimate_initial_parameters(exponential, xdata, ydata)
>>> # p0 ≈ [2.0, 0.2, 1.5] (estimated from data statistics)

Estimation works with any number of parameters:

>>> def linear(x, a, b):
...     return a * x + b
>>> xdata = np.array([1, 2, 3, 4, 5])
>>> ydata = np.array([2, 4, 6, 8, 10])
>>> p0 = estimate_initial_parameters(linear, xdata, ydata)
>>> # p0 ≈ [8.0, 0.25] (based on y_range and 1/x_range)

Custom functions can provide their own estimation:

>>> class GaussianModel:
...     def __call__(self, x, amp, mu, sigma):
...         return amp * np.exp(-(x - mu)**2 / (2 * sigma**2))
...
...     def estimate_p0(self, xdata, ydata):
...         amp = np.max(ydata) - np.min(ydata)
...         mu = xdata[np.argmax(ydata)]
...         sigma = (np.max(xdata) - np.min(xdata)) / 4
...         return [amp, mu, sigma]
>>>
>>> model = GaussianModel()
>>> xdata = np.linspace(-5, 5, 100)
>>> ydata = 2 * np.exp(-(xdata - 1)**2 / 2)
>>> p0 = estimate_initial_parameters(model, xdata, ydata)
>>> # Uses custom estimate_p0 method

See also

detect_function_pattern

Detect likely function pattern from data

estimate_p0_for_pattern

Pattern-specific estimation

nlsq.precision.parameter_estimation.detect_function_pattern(ydata, xdata)[source]

Detect likely function pattern from data shape.

This function analyzes the shape of the data to identify common patterns. It uses simple heuristics like monotonicity, peak detection, and correlation.

Parameters:
  • ydata (ndarray) – Dependent variable data

  • xdata (ndarray) – Independent variable data

Returns:

pattern – Detected pattern: - ‘linear’: Strong linear correlation (|r| > 0.95) - ‘exponential_decay’: Monotonically decreasing - ‘exponential_growth’: Monotonically increasing - ‘gaussian’: Bell-shaped curve with peak in middle - ‘sigmoid’: S-shaped curve going from low to high (or vice versa) - ‘unknown’: No clear pattern detected

Return type:

str

Notes

This is a simple heuristic detector, not a rigorous statistical test. It’s designed to be fast and provide reasonable guidance for initial parameter estimation, not to be 100% accurate.

Examples

Detect exponential decay:

>>> import numpy as np
>>> xdata = np.linspace(0, 5, 50)
>>> ydata = 3 * np.exp(-0.5 * xdata)
>>> pattern = detect_function_pattern(ydata, xdata)
>>> print(pattern)
'exponential_decay'

Detect Gaussian peak:

>>> xdata = np.linspace(-5, 5, 100)
>>> ydata = 2 * np.exp(-(xdata - 1)**2 / 2)
>>> pattern = detect_function_pattern(ydata, xdata)
>>> print(pattern)
'gaussian'

See also

estimate_p0_for_pattern

Estimate parameters based on detected pattern

nlsq.precision.parameter_estimation.estimate_p0_for_pattern(pattern, xdata, ydata, n_params)[source]

Estimate p0 based on detected pattern.

This function uses pattern-specific heuristics to estimate initial parameters. Each pattern has its own estimation strategy based on the mathematical properties of that function type.

Parameters:
  • pattern (str) – Detected function pattern (‘linear’, ‘exponential_decay’, ‘gaussian’, ‘sigmoid’, etc.)

  • xdata (ndarray) – Independent variable data

  • ydata (ndarray) – Dependent variable data

  • n_params (int) – Number of parameters to estimate

Returns:

p0 – Estimated initial parameters (length n_params)

Return type:

ndarray

Notes

Pattern-specific estimation strategies:

  • linear: Uses least squares to fit y = a*x + b

  • exponential_decay: Estimates amplitude from range, rate from half-life

  • gaussian: Estimates amplitude, mean from peak, sigma from FWHM

  • sigmoid: Estimates L, x0, k from data range and midpoint

  • unknown: Falls back to generic heuristics

Examples

Estimate parameters for exponential decay:

>>> import numpy as np
>>> xdata = np.linspace(0, 5, 50)
>>> ydata = 3 * np.exp(-0.5 * xdata) + 1
>>> p0 = estimate_p0_for_pattern('exponential_decay', xdata, ydata, 3)
>>> print(p0)
[2.0, 0.277..., 1.0]  # [amplitude, rate, offset]

Estimate parameters for Gaussian:

>>> xdata = np.linspace(-5, 5, 100)
>>> ydata = 2 * np.exp(-(xdata - 1)**2 / (2 * 0.5**2))
>>> p0 = estimate_p0_for_pattern('gaussian', xdata, ydata, 3)
>>> print(p0)
[2.0, 1.0, 0.5]  # [amplitude, mean, sigma]

See also

detect_function_pattern

Detect pattern from data

estimate_initial_parameters

Main parameter estimation function

Overview

The parameter_estimation module provides utilities for estimating initial parameter values from data.

Key Features

  • Automatic initial guess generation from data characteristics

  • Problem-specific heuristics for common model types

  • Bounds inference based on data range

  • Multi-start optimization with parameter space exploration

Functions

nlsq.parameter_estimation.estimate_initial_parameters(f, xdata, ydata, p0=None)[source]

Estimate initial parameters if p0 is None or ‘auto’.

This function attempts to intelligently guess initial parameter values based on the data characteristics when p0 is not provided.

The estimation strategy follows this order: 1. If p0 is provided (not None or ‘auto’), return it unchanged 2. If function has .estimate_p0() method, use it (for library functions) 3. Otherwise, use generic heuristics based on data statistics

Parameters:
  • f (callable) – Model function f(x, p0, p1, …) → y

  • xdata (array_like) – Independent variable data

  • ydata (array_like) – Dependent variable data

  • p0 (array_like or None or 'auto', optional) – Initial guess. If None or ‘auto’, estimate from data.

Returns:

p0_estimated – Initial parameter guess

Return type:

ndarray

Raises:

ValueError – If cannot determine number of parameters from function signature

Examples

Automatic estimation for exponential decay:

>>> import numpy as np
>>> def exponential(x, a, b, c):
...     return a * np.exp(-b * x) + c
>>> xdata = np.linspace(0, 5, 50)
>>> ydata = 3 * np.exp(-0.5 * xdata) + 1
>>> p0 = estimate_initial_parameters(exponential, xdata, ydata)
>>> # p0 ≈ [2.0, 0.2, 1.5] (estimated from data statistics)

Estimation works with any number of parameters:

>>> def linear(x, a, b):
...     return a * x + b
>>> xdata = np.array([1, 2, 3, 4, 5])
>>> ydata = np.array([2, 4, 6, 8, 10])
>>> p0 = estimate_initial_parameters(linear, xdata, ydata)
>>> # p0 ≈ [8.0, 0.25] (based on y_range and 1/x_range)

Custom functions can provide their own estimation:

>>> class GaussianModel:
...     def __call__(self, x, amp, mu, sigma):
...         return amp * np.exp(-(x - mu)**2 / (2 * sigma**2))
...
...     def estimate_p0(self, xdata, ydata):
...         amp = np.max(ydata) - np.min(ydata)
...         mu = xdata[np.argmax(ydata)]
...         sigma = (np.max(xdata) - np.min(xdata)) / 4
...         return [amp, mu, sigma]
>>>
>>> model = GaussianModel()
>>> xdata = np.linspace(-5, 5, 100)
>>> ydata = 2 * np.exp(-(xdata - 1)**2 / 2)
>>> p0 = estimate_initial_parameters(model, xdata, ydata)
>>> # Uses custom estimate_p0 method

See also

detect_function_pattern

Detect likely function pattern from data

estimate_p0_for_pattern

Pattern-specific estimation

Example Usage

from nlsq.parameter_estimation import estimate_initial_parameters
import jax.numpy as jnp


# Define exponential model
def exponential(x, a, b):
    return a * jnp.exp(-b * x)


# Generate data
x = jnp.linspace(0, 10, 100)
y = 2.5 * jnp.exp(-0.5 * x) + 0.1 * jnp.random.randn(100)

# Automatically estimate initial parameters
p0 = estimate_initial_parameters(exponential, x, y, n_params=2)
print(f"Estimated initial parameters: {p0}")

# Use in curve fitting
from nlsq import curve_fit

popt, pcov = curve_fit(exponential, x, y, p0=p0)

Supported Model Types

Automatic estimation for common model types:

  • Exponential decay: y = a * exp(-b * x) + c

  • Gaussian: y = a * exp(-((x-b)/c)^2)

  • Linear: y = a * x + b

  • Polynomial: y = sum(a_i * x^i)

  • Logistic: y = L / (1 + exp(-k*(x-x0)))

See Also