Skip to main content
Once you have fit a model with HMC, you usually want to know how well it predicts data it has not seen. Catalax answers this with PSIS-LOO — Pareto-smoothed importance-sampling leave-one-out cross-validation — computed directly from the posterior on the results object. You do not refit the model; LOO reuses the fit’s own likelihood to estimate the held-out predictive accuracy for every measured point at once.
This is different from dataset.leave_one_out(), which is a dataset-splitting helper that yields train/test folds for you to refit and score yourself (see Data Management). PSIS-LOO here scores an already-fitted model in one pass, with no refitting.

What LOO measures

The held-out unit is a real concentration measurement, scored against the model’s integrated trajectory. This works the same way regardless of how the posterior was obtained:
  • Integrated (mechanistic) fit — the measured concentrations are scored directly against the ODE solution, reproducing the native ArviZ statistic.
  • Surrogate (rate-matching) fit — the sampled rates are Euler-integrated along the measurement times and scored in concentration space, so a surrogate fit is validated on the same concentration-level footing as a mechanistic one.
Because HMCResults does not store the training data, you pass the measured dataset back in.

Basic usage

The return value is an arviz.ELPDData object, so anything you already do with ArviZ LOO results applies.

Choosing the held-out unit

Where the noise comes from

By default LOO reuses the fit’s own inferred observation noise sigma_y (the error model), which makes it a proper posterior predictive statistic.
For surrogate fits you can also choose how the rates are integrated:

Reading the Pareto-k diagnostic

The headline diagnostic is the per-observation Pareto-k. It flags high-influence points — the ones whose removal would most change the fit, and exactly the points a naive train/test split would wrongly discard.

Comparing models

compare() ranks several fits on the same concentration-space footing, even when they were trained in different modes (mechanistic vs. surrogate). The current fit is added automatically under the name "self".
Pass a single dataset for all fits, or a {name: dataset} mapping (which must include "self") if the fits were trained on different data.

Pointwise diagnostics and plots

loo_pointwise() scatters the per-point elpd and pareto_k back onto the data grid, shaped (n_measurements, n_timepoints, n_observables) with NaN where a point was not scored.
Two plots consume that structure directly:
Both accept yerrs, sigma_source, integration, and max_draws with the same meaning as loo(), plus measurements=[...] to restrict the panels and path=... to save the figure.

Validating the reconstruction

For a mechanistic fit you can confirm that Catalax’s reconstruction matches ArviZ’s native LOO. This is mostly useful as a sanity check on the machinery that the surrogate path relies on (the surrogate path has no native counterpart).
This raises if called on a surrogate-mode fit.
LOO answers “does the fit generalize”, not “is each parameter individually identifiable”. Pair it with posterior-correlation and prior-sensitivity analysis for structurally traded-off parameters (for example an E0kcat trade-off), which LOO will not flag.