clophfit.fitting.model_validation#

Reusable model-validation helpers for ClopHfit fitting workflows.

These utilities are designed to live in clophfit.fitting and be reused by both package tests and manuscript-analysis scripts. They intentionally avoid any manuscript-specific paths, file formats, or plate names.

Functions#

residual_normal_scores(likelihood_residual, *[, ...])

Map likelihood-scale residuals onto a Normal diagnostic scale.

robust_residual_outlier_mask(likelihood_residual, *[, ...])

Flag observations by calibrated Normal-score residual magnitude.

excess_tail_outlier_mask(likelihood_residual, *[, ...])

Mask only residual outliers beyond an allowed tail fraction.

mark_excess_residual_outliers(residuals, *[, ...])

Annotate residual rows to remove only excess calibrated tail outliers.

masked_datasets_from_residual_outliers(results, ...[, ...])

Return datasets with residual rows marked by exclude_col masked out.

posterior_dataset(trace)

Return the posterior xarray Dataset from ArviZ InferenceData or DataTree.

sample_stats_dataset(trace)

Return sample_stats Dataset from InferenceData or DataTree.

x_axis_sanity(trace)

Check pH/x-axis invariants for traces with x_per_well.

trace_diagnostics(trace, *[, compute_loo, ...])

Collect basic MCMC and optional LOO diagnostics from a PyMC trace.

merge_log_likelihoods(trace)

Merge multiple pointwise log-likelihood variables for ArviZ LOO/compare.

residuals_from_multifit(multi, trace_id, ...[, ...])

Build a long calibrated-residual table from a MultiFitResult.

residuals_from_fit_results(results, trace_id, ...[, ...])

Build a long calibrated residual table from classical FitResult objects.

model_residual_score_table(res_df)

Return model-level and detailed residual summary tables.

Module Contents#

clophfit.fitting.model_validation.residual_normal_scores(likelihood_residual, *, robust=False, student_t_nu=STUDENT_T_NU)#

Map likelihood-scale residuals onto a Normal diagnostic scale.

For Normal likelihoods this is the identity. For Student-t likelihoods, (y - mu) / sigma follows a t distribution, so Normal QQ plots and abs(residual) > 2 style diagnostics should use the probability integral transform to an equivalent standard-Normal score.

Parameters:
  • likelihood_residual (ArrayLike)

  • robust (bool)

  • student_t_nu (float)

Return type:

numpy.ndarray

clophfit.fitting.model_validation.robust_residual_outlier_mask(likelihood_residual, *, threshold=3.0, robust=False, student_t_nu=STUDENT_T_NU)#

Flag observations by calibrated Normal-score residual magnitude.

Parameters:
  • likelihood_residual (ArrayLike)

  • threshold (float)

  • robust (bool)

  • student_t_nu (float)

Return type:

numpy.ndarray

clophfit.fitting.model_validation.excess_tail_outlier_mask(likelihood_residual, *, threshold=3.0, allowed_tail_fraction=0.01, min_allowed_tail_count=1, robust=False, student_t_nu=STUDENT_T_NU)#

Mask only residual outliers beyond an allowed tail fraction.

The residuals are first mapped to the calibrated Normal diagnostic scale. Observations with abs(z) <= threshold are never removed. If more than allowed_tail_fraction of finite observations exceed the threshold, only the largest excess observations are marked for removal.

Parameters:
  • likelihood_residual (ArrayLike)

  • threshold (float)

  • allowed_tail_fraction (float)

  • min_allowed_tail_count (int)

  • robust (bool)

  • student_t_nu (float)

Return type:

numpy.ndarray

clophfit.fitting.model_validation.mark_excess_residual_outliers(residuals, *, residual_col='std_res', group_cols=('trace_id', 'label'), threshold=3.0, allowed_tail_fraction=0.01, min_allowed_tail_count=1, exclude_col='exclude_residual_outlier')#

Annotate residual rows to remove only excess calibrated tail outliers.

Parameters:
  • residuals (pandas.DataFrame)

  • residual_col (str)

  • group_cols (tuple[str, Ellipsis])

  • threshold (float)

  • allowed_tail_fraction (float)

  • min_allowed_tail_count (int)

  • exclude_col (str)

Return type:

pandas.DataFrame

clophfit.fitting.model_validation.masked_datasets_from_residual_outliers(results, residuals, *, exclude_col='exclude_residual_outlier', min_keep=3)#

Return datasets with residual rows marked by exclude_col masked out.

This is intended for the second pass of a sensitivity analysis: fit once, compute residuals, annotate excess-tail outliers, mask those rows, then refit.

Parameters:
  • results (Mapping[str, Any])

  • residuals (pandas.DataFrame)

  • exclude_col (str)

  • min_keep (int)

Return type:

dict[str, Any]

clophfit.fitting.model_validation.posterior_dataset(trace)#

Return the posterior xarray Dataset from ArviZ InferenceData or DataTree.

PyMC/ArviZ versions differ in whether returned objects are InferenceData-like or xarray DataTree-like. This helper hides that difference for validation code.

Parameters:

trace (Any)

Return type:

Any

clophfit.fitting.model_validation.sample_stats_dataset(trace)#

Return sample_stats Dataset from InferenceData or DataTree.

Parameters:

trace (Any)

Return type:

Any

clophfit.fitting.model_validation.x_axis_sanity(trace)#

Check pH/x-axis invariants for traces with x_per_well.

For per-well x models with a shared start pH, all wells at step 0 should be identical within each draw. x_step0_max_abs_spread should therefore be close to zero.

Parameters:

trace (Any)

Return type:

dict[str, Any]

clophfit.fitting.model_validation.trace_diagnostics(trace, *, compute_loo=False, summary_var_names=None)#

Collect basic MCMC and optional LOO diagnostics from a PyMC trace.

Parameters:
  • trace (Any)

  • compute_loo (bool)

  • summary_var_names (list[str] | None)

Return type:

dict[str, Any]

clophfit.fitting.model_validation.merge_log_likelihoods(trace)#

Merge multiple pointwise log-likelihood variables for ArviZ LOO/compare.

Parameters:

trace (Any)

Return type:

Any

clophfit.fitting.model_validation.residuals_from_multifit(multi, trace_id, binding_function, *, include_fit_params=False, robust=False, student_t_nu=STUDENT_T_NU, outlier_threshold=3.0)#

Build a long calibrated-residual table from a MultiFitResult.

likelihood_res is always (observed - predicted) / sigma. For Student-t robust fits, std_res is the equivalent standard-Normal score from the t CDF, suitable for Normal QQ plots and z-style outlier flags.

Parameters:
  • multi (Any)

  • trace_id (str)

  • binding_function (Callable[Ellipsis, ArrayLike])

  • include_fit_params (bool)

  • robust (bool)

  • student_t_nu (float)

  • outlier_threshold (float)

Return type:

pandas.DataFrame

clophfit.fitting.model_validation.residuals_from_fit_results(results, trace_id, binding_function, *, include_fit_params=False, robust=False, student_t_nu=STUDENT_T_NU, outlier_threshold=3.0)#

Build a long calibrated residual table from classical FitResult objects.

Parameters:
  • results (dict[str, Any])

  • trace_id (str)

  • binding_function (Callable[Ellipsis, ArrayLike])

  • include_fit_params (bool)

  • robust (bool)

  • student_t_nu (float)

  • outlier_threshold (float)

Return type:

pandas.DataFrame

clophfit.fitting.model_validation.model_residual_score_table(res_df)#

Return model-level and detailed residual summary tables.

Parameters:

res_df (pandas.DataFrame)

Return type:

tuple[pandas.DataFrame, pandas.DataFrame, pandas.DataFrame, pandas.DataFrame, pandas.DataFrame]