Source code for pykinbiont.fit

"""Public fit() and preprocess() functions."""

from __future__ import annotations

from typing import Optional, Union
import numpy as np

from pykinbiont._core import get_jl
from pykinbiont._convert import (
    py_to_jl_growth_data,
    py_to_jl_irregular,
    py_to_jl_fit_options,
    py_to_jl_model_spec,
    jl_to_py_growth_fit_results,
)
from pykinbiont.types import (
    GrowthData,
    IrregularGrowthData,
    FitOptions,
    ModelSpec,
    GrowthFitResults,
)

_AnyData = Union[GrowthData, IrregularGrowthData]


def _to_jl_data(data: _AnyData):
    if isinstance(data, IrregularGrowthData):
        return py_to_jl_irregular(data)
    return py_to_jl_growth_data(data)


[docs] def fit( data: _AnyData, spec: ModelSpec, opts: Optional["FitOptions"] = None, ) -> GrowthFitResults: """Fit every curve in data to every model in spec and select best by AICc. Preprocessing (smoothing, blank subtraction, clustering, …) is applied according to opts before fitting. Parameters ---------- data: GrowthData or IrregularGrowthData container. spec: Models to try and their initial parameters. opts: All preprocessing and fitting configuration. Defaults to ``FitOptions()`` (no preprocessing, log-linear model selection). Returns ------- GrowthFitResults One CurveFitResult per curve plus the post-preprocessing GrowthData (with cluster assignments if clustering was requested). """ if opts is None: opts = FitOptions() jl = get_jl() jl_data = _to_jl_data(data) jl_opts = py_to_jl_fit_options(opts) jl_spec = py_to_jl_model_spec(spec) jl_res = jl.Kinbiont.kinbiont_fit(jl_data, jl_spec, jl_opts) return jl_to_py_growth_fit_results(jl_res)
[docs] def preprocess( data: _AnyData, opts: FitOptions, ) -> Union[GrowthData, IrregularGrowthData]: """Apply the preprocessing pipeline to data and return a new GrowthData. When opts.cluster=True, the returned GrowthData has .clusters, .centroids, and .wcss populated. Parameters ---------- data: GrowthData or IrregularGrowthData. opts: Preprocessing configuration. Returns ------- GrowthData Preprocessed data (new instance, input is never modified). """ jl = get_jl() jl_data = _to_jl_data(data) jl_opts = py_to_jl_fit_options(opts) jl_processed = jl.Kinbiont.preprocess(jl_data, jl_opts) clusters = ( np.array(jl_processed.clusters, dtype=int) if jl_processed.clusters is not None else None ) centroids = ( np.array(jl_processed.centroids, dtype=np.float64) if jl_processed.centroids is not None else None ) wcss = float(jl_processed.wcss) if jl_processed.wcss is not None else None return GrowthData( curves = np.array(jl_processed.curves, dtype=np.float64), times = np.array(jl_processed.times, dtype=np.float64), labels = [str(lb) for lb in jl_processed.labels], clusters = clusters, centroids = centroids, wcss = wcss, )