Non-linear least-squares minimization and curve-fitting with enhanced parameter management and confidence interval estimation
—
The Model class provides a high-level interface for curve fitting, transforming user-defined functions into fitting models with automatic parameter creation, initial value guessing, and comprehensive result analysis. Models can be combined using arithmetic operators to create composite models for complex data.
High-level curve fitting interface that wraps user functions with parameter management and fitting capabilities.
class Model:
"""Create fitting models from user-supplied functions"""
def __init__(self, func, independent_vars=None, param_names=None,
nan_policy='raise', prefix='', name='', **kws):
"""
Create a Model from a user function.
Args:
func: Function to convert to model (should return numpy array)
independent_vars (list): Names of independent variables (default: ['x'])
param_names (list): Names of parameters (auto-detected if None)
nan_policy (str): Policy for NaN values ('raise', 'propagate', 'omit')
prefix (str): Prefix for parameter names to avoid conflicts
name (str): Name for the model
**kws: Additional keyword arguments
"""
def fit(self, data, params=None, weights=None, method='leastsq',
iter_cb=None, scale_covar=True, verbose=False, fit_kws=None, **kws):
"""
Fit the model to data.
Args:
data (array-like): Data to fit
params (Parameters): Parameters for fit (uses make_params() if None)
weights (array-like): Weights for data points
method (str): Optimization method
iter_cb: Iteration callback function
scale_covar (bool): Scale covariance matrix
verbose (bool): Print fit progress
fit_kws (dict): Additional arguments for minimizer
**kws: Values for independent variables
Returns:
ModelResult: Comprehensive fit results
"""
def guess(self, data, **kws):
"""
Guess initial parameter values from data.
Args:
data (array-like): Data to analyze for parameter guessing
**kws: Values for independent variables and other options
Returns:
Parameters: Parameters with guessed initial values
"""
def make_params(self, verbose=False, **kws):
"""
Create Parameters for the model.
Args:
verbose (bool): Print parameter creation info
**kws: Initial values for parameters
Returns:
Parameters: Parameters object for the model
"""
def eval(self, params=None, **kws):
"""
Evaluate the model function.
Args:
params (Parameters): Parameter values to use
**kws: Values for independent variables
Returns:
array: Model values
"""
def set_param_hint(self, name, **kws):
"""
Set parameter hints for automatic parameter creation.
Args:
name (str): Parameter name
**kws: Parameter attributes (value, min, max, vary, expr, etc.)
"""
def print_param_hints(self, columns=['name', 'value', 'min', 'max', 'vary', 'expr']):
"""
Print table of parameter hints.
Args:
columns (list): Columns to display in table
"""Composite models created by combining Model instances with arithmetic operators.
class CompositeModel(Model):
"""Model created by combining other models with operators"""
def __init__(self, left, right, op, **kws):
"""
Create composite model (usually created automatically via operators).
Args:
left (Model): Left operand model
right (Model): Right operand model
op (function): Operator function (+, -, *, /)
**kws: Additional keyword arguments
"""
# Inherits all Model methods with combined functionalityComprehensive results from Model.fit() with enhanced analysis capabilities.
class ModelResult(MinimizerResult):
"""Results from Model.fit() with enhanced model-specific features"""
def eval_components(self, params=None, **kws):
"""
Evaluate individual components of composite models.
Args:
params (Parameters): Parameter values (uses best-fit if None)
**kws: Values for independent variables
Returns:
dict: Component names mapped to their evaluated values
"""
def plot(self, datafmt='o', fitfmt='-', initfmt='--', xlabel=None,
ylabel=None, yerr=None, numpoints=None, fig=None,
data_kws=None, fit_kws=None, init_kws=None,
ax_res_kws=None, ax_fit_kws=None, fig_kws=None,
show_init=False, parse_complex='abs'):
"""
Plot data, initial fit, and best fit with residuals.
Args:
datafmt (str): Format for data points
fitfmt (str): Format for fit line
initfmt (str): Format for initial fit line
xlabel (str): X-axis label
ylabel (str): Y-axis label
yerr (array): Error bars for data
numpoints (int): Number of points for fit line
fig: Matplotlib figure to use
data_kws (dict): Keyword arguments for data plot
fit_kws (dict): Keyword arguments for fit plot
init_kws (dict): Keyword arguments for initial fit plot
ax_res_kws (dict): Keyword arguments for residuals axis
ax_fit_kws (dict): Keyword arguments for fit axis
fig_kws (dict): Keyword arguments for figure
show_init (bool): Show initial parameter fit
parse_complex (str): How to handle complex values
Returns:
Figure with data, fit, and residuals
"""
def plot_fit(self, ax=None, datafmt='o', fitfmt='-', initfmt='--',
xlabel=None, ylabel=None, yerr=None, numpoints=None,
data_kws=None, fit_kws=None, init_kws=None, ax_kws=None,
show_init=False, parse_complex='abs'):
"""
Plot data and fit without residuals.
Args:
ax: Matplotlib axis to plot on
Other args: Same as plot() method
"""
def plot_residuals(self, ax=None, datafmt='o', yerr=None,
data_kws=None, fit_kws=None, ax_kws=None,
parse_complex='abs'):
"""
Plot fit residuals.
Args:
ax: Matplotlib axis to plot on
datafmt (str): Format for residual points
yerr (array): Error bars for residuals
data_kws (dict): Keyword arguments for data plot
fit_kws (dict): Keyword arguments for fit plot
ax_kws (dict): Keyword arguments for axis
parse_complex (str): How to handle complex residuals
"""def save_modelresult(modelresult, fname):
"""
Save ModelResult to file.
Args:
modelresult (ModelResult): Results to save
fname (str): Filename for saving
"""
def load_modelresult(fname, **kws):
"""
Load ModelResult from file.
Args:
fname (str): Filename to load from
**kws: Additional keyword arguments
Returns:
ModelResult: Loaded results
"""import numpy as np
from lmfit import Model
def exponential_decay(x, amplitude, decay, offset):
"""Exponential decay function"""
return amplitude * np.exp(-decay * x) + offset
# Create model from function
model = Model(exponential_decay)
# Generate sample data
x = np.linspace(0, 10, 101)
data = 5.0 * np.exp(-0.8 * x) + 2.0 + np.random.normal(size=101, scale=0.1)
# Fit the model
result = model.fit(data, x=x, amplitude=10, decay=1, offset=1)
print(result.fit_report())# Set parameter hints for better automatic behavior
model.set_param_hint('amplitude', min=0, value=5)
model.set_param_hint('decay', min=0, value=1)
model.set_param_hint('offset', value=0)
# Create parameters with hints
params = model.make_params()
# Or let the model guess initial values
guess_params = model.guess(data, x=x)
# Fit with guessed parameters
result = model.fit(data, guess_params, x=x)from lmfit.models import GaussianModel, LinearModel
# Create individual models
gaussian = GaussianModel(prefix='g_')
linear = LinearModel(prefix='l_')
# Combine models with operators
composite = gaussian + linear
# The composite model has parameters from both components:
# g_amplitude, g_center, g_sigma, l_slope, l_intercept
params = composite.make_params()
# Set initial values
params['g_amplitude'].set(value=10, min=0)
params['g_center'].set(value=5)
params['g_sigma'].set(value=1, min=0.01)
params['l_slope'].set(value=0)
params['l_intercept'].set(value=0)
# Fit composite model
result = composite.fit(data, params, x=x)def multi_peak(x, **params):
"""Multi-peak function with variable number of peaks"""
y = params.get('background', 0)
i = 1
while f'amp{i}' in params:
amp = params[f'amp{i}']
cen = params[f'cen{i}']
wid = params[f'wid{i}']
y += amp * np.exp(-(x - cen)**2 / (2 * wid**2))
i += 1
return y
# Create model with custom independent variables
model = Model(multi_peak, independent_vars=['x'])
# Set parameter hints for multiple peaks
for i in range(1, 4): # 3 peaks
model.set_param_hint(f'amp{i}', value=1, min=0)
model.set_param_hint(f'cen{i}', value=i*3)
model.set_param_hint(f'wid{i}', value=1, min=0.1)
model.set_param_hint('background', value=0)
# Create and fit
params = model.make_params()
result = model.fit(data, params, x=x)# Evaluate model at best-fit parameters
best_fit = result.best_fit
# Evaluate at custom parameters
custom_params = result.params.copy()
custom_params['amplitude'].value = 8.0
custom_fit = model.eval(custom_params, x=x)
# For composite models, evaluate individual components
if hasattr(result, 'eval_components'):
components = result.eval_components(x=x)
gaussian_component = components['g_']
linear_component = components['l_']# Plot data and fit with residuals
result.plot()
# Plot just the fit
result.plot_fit(show_init=True) # Include initial parameters
# Plot just residuals
result.plot_residuals()
# Customize plots
result.plot(datafmt='ko', fitfmt='r-', xlabel='Time (s)',
ylabel='Signal', data_kws={'markersize': 4})Install with Tessl CLI
npx tessl i tessl/pypi-lmfit