dosma.CurveFitter

class dosma.CurveFitter(func: Callable, p0: Optional[Sequence[float]] = None, y_bounds: Optional[Tuple[float]] = None, out_ufuncs: Optional[Union[Callable, Sequence[Callable]]] = None, out_bounds=None, r2_threshold: float = 'preferences', nan_to_num: Optional[float] = None, num_workers: int = 0, chunksize: Optional[int] = None, verbose: bool = False, **kwargs)[source]

The class using non-linear least squares to fit a function to data.

This class is a wrapper around the dosma.utils.fits.curve_fit() function that handles MedicalVolume data and supports additional post-processing on fitted parameters.

self.fit(x, y, mask=None) will fit independent variables x with observed MedicalVolumes y. To only fit certain regions of volumes y, specify mask.

Parameters:
  • func (callable) – The model function, f(x, …). It must take the independent variable as the first argument and the parameters to fit as separate remaining arguments.

  • p0 (Sequence, optional) – Initial guess for the parameters (length N). If None, then the initial values will all be 1 (if the number of parameters for the function can be determined using introspection, otherwise a ValueError is raised).

  • y_bounds (tuple, optional) – Lower and upper bound on y values. Defaults to no bounds. Sequences with observations out of this range will not be processed.

  • out_ufuncs (Callable, Sequence[Callable]) – Function(s) to post-process parameter maps. Defaults to no post-processing. Each function must operate on ndarrays in an element-by-element fashion, should only take one argument, which will be the parameter map, and output the processed parameter map (an ndarray). If isinstance(out_ufuncs, Callable), operates on map of all parameters, where last dimension (axis=-1) corresponds to different parameters. If isinstance(out_ufuncs, Sequence), each ufunc corresponds to one parameter.

  • out_bounds (array-like, optional) – Lower and upper bounds (inclusive) on fitted parameters. Defaults to no bounds. Fitted parameters outside of this range will be set to np.nan. Last dimension should have size 2. If out_bounds.ndim == 1, bounds will be applied to all parameters.

  • r2_threshold (float) – Minimum \(r^2\) goodness of fit value to accept fit per sample. Parameter values below this threshold will be set to np.nan. Defaults to preferences.fitting_r2_threshold. To ignore, set to None.

  • nan_to_num (float, optional) – If specified, all fitted parameters equal to np.nan will be converted to this value. This uses numpy.nan_to_num, which will also replace posinf and neginf values with very large positive and negative values, respectively. See numpy.nan_to_num for more details.

  • num_workers (int, optional) – Maximum number of workers to use for fitting.

  • chunksize (int, optional) – Size of chunks sent to worker processes when num_workers > 0. When show_pbar=True, this defaults to the standard value in tqdm.concurrent.process_map().

  • verbose (bool, optional) – If True, show progress bar. Note this can increase runtime slightly when using multiple workers.

  • kwargs – Keyword args for dosma.utils.fits.curve_fit().

Examples

Fitting monoexponential() (\(y = a * e^{b*x}\)) to independent variables x and dependent variables y with initial guesses a=1.0 and b=-0.2:

>>> fitter = CurveFitter(monoexponential, p0=(1.0, -0.2))
>>> popt, r2 = fitter.fit(x, y)
>>> a_hat, b_hat = popt[..., 0], popt[..., 1]

Post-process b by taking the inverse of its absolute value of b (i.e. \(\frac{1}{|b|}\)). Set all values not in domain \(0 \leq \frac{1}{|b|} \leq 100\) or with a goodness of fit less than 0.9 (\(r^2\) < 0.9) to np.nan:

>>> ufunc = lambda x: 1 / np.abs(x)
>>> out_bounds = ((-np.inf, np.inf), (0, 100))
>>> fitter = CurveFitter(
...     monoexponential, p0=(1.0, -0.2), out_ufuncs=[None, ufunc], out_bounds=out_bounds)
>>> popt, r2 = fitter.fit(x, y)
>>> a_hat, inv_abs_b_hat = popt[..., 0], popt[..., 1]
__init__(func: Callable, p0: Optional[Sequence[float]] = None, y_bounds: Optional[Tuple[float]] = None, out_ufuncs: Optional[Union[Callable, Sequence[Callable]]] = None, out_bounds=None, r2_threshold: float = 'preferences', nan_to_num: Optional[float] = None, num_workers: int = 0, chunksize: Optional[int] = None, verbose: bool = False, **kwargs)[source]

Methods

__init__(func[, p0, y_bounds, out_ufuncs, ...])

fit(x, y[, mask, p0, copy_headers])

Perform non-linear least squares fit.

Attributes