Fitting lmfit.Models to xarray objects#
xarray-lmfit adds some methods to xarray objects that allows you to fit data with lmfit models: xarray.DataArray.xlm.modelfit() and xarray.Dataset.xlm.modelfit(), depending on whether you want to fit a single DataArray or multiple DataArrays in a Dataset.
Hint
The syntax of the accessors are similar to the xarray native methods xarray.DataArray.curvefit() and xarray.Dataset.curvefit().
First, let us generate a Gaussian peak on a linear background.
import numpy as np
import xarray as xr
import matplotlib.pyplot as plt
import lmfit
# Generate Gaussian peak on linear background
x = np.linspace(0, 10, 50)
y = -0.1 * x + 2 + 3 * np.exp(-((x - 5) ** 2) / (2 * 1**2))
# Add some noise with fixed seed for reproducibility
rng = np.random.default_rng(5)
yerr = np.full_like(x, 0.3)
y = rng.normal(y, yerr)
y_arr = xr.DataArray(y, dims=("x",), coords={"x": x})
y_arr
<xarray.DataArray (x: 50)> Size: 400B
array([1.75943175, 1.58231452, 1.88475436, 2.06510701, 2.25965595,
1.93196286, 1.71416562, 1.62680659, 2.07170706, 2.32691224,
1.91538585, 1.47294052, 1.58349782, 2.40570597, 2.07715715,
1.6322706 , 2.31469126, 2.23390379, 2.68841232, 3.06370507,
3.34563648, 4.0619544 , 4.16597499, 4.21645875, 4.61751752,
4.7231746 , 3.83915663, 4.00584093, 3.45885951, 3.32401046,
2.59879139, 2.61809975, 2.26538341, 1.90156002, 1.449778 ,
1.46886389, 1.12891382, 0.95421068, 1.35935443, 0.9089135 ,
1.5549131 , 1.38859024, 0.54860997, 1.20649644, 0.77261759,
1.09202446, 1.07451202, 0.44436656, 0.95041178, 0.92327417])
Coordinates:
* x (x) float64 400B 0.0 0.2041 0.4082 0.6122 ... 9.592 9.796 10.0Here, y_arr is the DataArray that contains both the values we want to fit, along with the independent variable x as a coordinate.
After importing xarray_lmfit, we can use xarray.DataArray.xlm.modelfit() to fit the data to a model.
import xarray_lmfit
model = lmfit.models.GaussianModel() + lmfit.models.LinearModel()
params = model.make_params(slope=-0.1, center=5.0, sigma={"value": 0.1, "min": 0})
result = y_arr.xlm.modelfit("x", model=model, params=params)
The fit result Dataset#
xarray.DataArray.xlm.modelfit() returns a xarray.Dataset including the best-fit parameters and the fit statistics:
result
<xarray.Dataset> Size: 2kB
Dimensions: (param: 5, cov_i: 5, cov_j: 5, fit_stat: 9, x: 50)
Coordinates:
* x (x) float64 400B 0.0 0.2041 0.4082 ... 9.796 10.0
* param (param) <U9 180B 'amplitude' 'center' ... 'intercept'
* fit_stat (fit_stat) <U8 288B 'nfev' 'nvarys' ... 'rsquared'
* cov_i (cov_i) <U9 180B 'amplitude' 'center' ... 'intercept'
* cov_j (cov_j) <U9 180B 'amplitude' 'center' ... 'intercept'
Data variables:
modelfit_results object 8B <lmfit.model.ModelResult object at 0x77d...
modelfit_coefficients (param) float64 40B 7.166 4.992 0.943 -0.1138 2.006
modelfit_stderr (param) float64 40B 0.3762 0.04221 ... 0.08441
modelfit_covariance (cov_i, cov_j) float64 200B 0.1415 ... 0.007126
modelfit_stats (fit_stat) float64 72B 43.0 5.0 ... -118.4 0.9468
modelfit_data (x) float64 400B 1.759 1.582 1.885 ... 0.9504 0.9233
modelfit_best_fit (x) float64 400B 2.006 1.983 1.96 ... 0.8915 0.8683Let’s take a closer look at the data variables in the resulting Dataset.
modelfit_resultscontains the underlyinglmfit.model.ModelResultobject from the fit.modelfit_coefficientsandmodelfit_stderrcontain the best-fit coefficients and their errors, respectively.modelfit_statscontains the goodness-of-fit statistics.
When called on a Dataset instead of a DataArray, these variables will be prefixed with the name of the data variable they correspond to.
It may not be immediately obvious how this is useful, but the true power of the accessor comes from its ability to utilize xarray’s powerful broadcasting capabilities, as described in the next section.