"""save_results() — write GrowthFitResults to CSV files (pure Python)."""
from __future__ import annotations
import csv
from pathlib import Path
from pykinbiont.types import GrowthFitResults
[docs]
def save_results(
results: GrowthFitResults,
dir: str,
prefix: str = "kinbiont",
) -> dict[str, str]:
"""Write fitting results to CSV files inside dir.
Three files are written:
- ``<prefix>_summary.csv``: one row per curve (best model, AICc, params).
- ``<prefix>_fitted_curves.csv``: long-format (label, time, observed, fitted).
- ``<prefix>_all_models.csv``: one row per (curve, candidate model).
Parameters
----------
results:
GrowthFitResults returned by fit().
dir:
Directory path (created if it does not exist).
prefix:
File name prefix. Default ``"kinbiont"``.
Returns
-------
dict with keys ``"summary"``, ``"fitted_curves"``, ``"all_models"`` pointing
to the written file paths.
"""
out = Path(dir)
out.mkdir(parents=True, exist_ok=True)
base = out / prefix
summary_path = str(base) + "_summary.csv"
fitted_curves_path = str(base) + "_fitted_curves.csv"
all_models_path = str(base) + "_all_models.csv"
_write_summary(results, summary_path)
_write_fitted_curves(results, fitted_curves_path)
_write_all_models(results, all_models_path)
return {
"summary": summary_path,
"fitted_curves": fitted_curves_path,
"all_models": all_models_path,
}
def _write_summary(results: GrowthFitResults, path: str) -> None:
n_max = max((len(r.best_params) for r in results.results), default=0)
header = [
"label", "cluster", "best_model", "n_params", "param_names",
"aic", "loss",
] + [f"param_{k+1}" for k in range(n_max)]
with open(path, "w", newline="") as f:
w = csv.writer(f)
w.writerow(header)
for r in results.results:
idx = results.data.labels.index(r.label)
cluster = (
int(results.data.clusters[idx])
if results.data.clusters is not None else ""
)
param_names = ";".join(r.param_names)
row = [r.label, cluster, r.best_model, len(r.best_params),
param_names, r.best_aic, r.loss]
for k in range(n_max):
row.append(r.best_params[k] if k < len(r.best_params) else "")
w.writerow(row)
print(f"[ Info: Saved summary → {path}")
def _write_fitted_curves(results: GrowthFitResults, path: str) -> None:
with open(path, "w", newline="") as f:
w = csv.writer(f)
w.writerow(["label", "time", "observed", "fitted"])
for r in results.results:
idx = results.data.labels.index(r.label)
obs = results.data.curves[idx]
n_fit = len(r.fitted_curve)
for j, t in enumerate(r.times[:n_fit]):
obs_j = float(obs[j]) if j < len(obs) else ""
w.writerow([r.label, t, obs_j, r.fitted_curve[j]])
print(f"[ Info: Saved fitted curves → {path}")
def _write_all_models(results: GrowthFitResults, path: str) -> None:
# Determine max params across all candidate models
n_max = 0
for r in results.results:
for c in r.all_results:
n_max = max(n_max, len(c.get("params", [])))
header = [
"label", "model_name", "param_names", "aic", "loss", "is_best",
] + [f"param_{k+1}" for k in range(n_max)]
with open(path, "w", newline="") as f:
w = csv.writer(f)
w.writerow(header)
for r in results.results:
for c in r.all_results:
params = c.get("params", [])
is_best = c.get("model_name") == r.best_model
row = [
r.label,
c.get("model_name", ""),
"", # param_names not stored per candidate
c.get("aic", ""),
c.get("loss", ""),
is_best,
]
for k in range(n_max):
row.append(params[k] if k < len(params) else "")
w.writerow(row)
print(f"[ Info: Saved all models → {path}")