tbnpy.diagnostics¶
Checks of a model’s numbers, where tbnpy.check_model() checks its protocol:
run_sense_check()forward-samples the prior and reports marginals, bound violations, rank correlations, and how each discrete variable moves the others, which catches unit errors, sign flips, dead variables and NaN paths;check_evidence()refuses, with an explanation, conditioning that cannot work, such as an exact observation of a deterministic continuous node;posterior()wraps likelihood weighting (tbnpy.inference.sample_evidence()) and returns summaries together with the effective sample size that qualifies them.
from tbnpy import diagnostics
report = diagnostics.run_sense_check(probs, varis, n_sample=20_000)
print(report.flags)
r = diagnostics.posterior(probs, ["C"], {"OC": -0.3}, n_sample=50_000, varis=varis)
print(r.summary(varis), r.ess)
API¶
Model diagnostics: prior sense checks, evidence validation, and weighted posterior summaries.
Everything here is plain torch/numpy/pandas and lives in core deliberately.
A pip install tbnpy user gets the same checks the GUI shows, and the GUI
stays a thin presentation layer over this module rather than the place where
the real work happens.
Three groups of functions:
- Prior sense check
run_sense_check()forward-samples the whole model and reports marginals, bound violations, rank correlations, and how each discrete variable moves the rest. Catches unit errors, sign flips, dead variables, and NaN paths.- Evidence validation
check_evidence()refuses, with an explanation, the conditioning requests that cannot work – most importantly a hard observation of a deterministic continuous node, which has probability zero and yields a NaN posterior rather than an error.- Weighted posterior
posterior()wrapstbnpy.inference.sample_evidence(), which is likelihood weighting, and returns summaries together with the effective sample size. ESS is not decoration: at 20k particles a tail observation can leave a few hundred real ones behind a perfectly smooth-looking histogram, and nothing else in the output reveals it.
- class tbnpy.diagnostics.SenseCheckReport(samples: 'pd.DataFrame', marginals: 'pd.DataFrame', discrete_pmfs: 'dict', correlation: 'pd.DataFrame', conditionals: 'dict', flags: 'pd.DataFrame', n_sample: 'int')[source]¶
- tbnpy.diagnostics.run_sense_check(probs, varis, n_sample=20000, bounds=None, seed=0, batch_size=50000, method='spearman')[source]¶
Forward-sample the prior and assemble the full diagnostic report.
- tbnpy.diagnostics.forward_sample_all(probs, n_sample=20000, batch_size=50000, seed=0)[source]¶
Prior-sample every node into a tidy
(n_sample, n_vars)DataFrame.inference.samplereturns each node’s child samples only, shaped(N,)for a generated or custom single-child node and(N, n_childs)for a tabularCpt, so both layouts are unpacked here.
- tbnpy.diagnostics.plot_report(report, varis, stem, max_vars=30)[source]¶
Correlation heatmap plus a grid of marginal histograms.
matplotlib is imported here rather than at module scope: it is not a dependency of tbnpy, so the rest of this module works without it.
- class tbnpy.diagnostics.EvidenceIssue(node: 'str', severity: 'str', issue: 'str', detail: 'str', suggestions: 'list' = <factory>)[source]¶
- tbnpy.diagnostics.check_evidence(probs, varis, evidence) list[source]¶
Check a conditioning request before spending any sampling on it.
- Parameters:
evidence – A DataFrame of evidence rows, or
{node: value}/{node: [values]}.- Returns:
Empty when the request is sound. Errors mean the posterior would be undefined, not merely poor.
- Return type:
list[EvidenceIssue]
- class tbnpy.diagnostics.PosteriorResult(samples: dict, log_weights: torch.Tensor, weights: numpy.ndarray, ess: torch.Tensor, n_sample: int, evidence: pandas.DataFrame, issues: list = <factory>)[source]¶
Weighted particles, their summaries, and the ESS that qualifies them.
- is_degenerate(threshold=0.01)[source]¶
Rows whose ESS has collapsed below
thresholdof the particles.
- tbnpy.diagnostics.posterior(probs, query_nodes, evidence, n_sample=20000, varis=None, seed=0, batch_size=50000, validate=True) PosteriorResult[source]¶
Posterior particles for
query_nodesgivenevidence.inference.sample_evidenceis likelihood weighting: it clamps the observed nodes, resamples everything else, and returns each node’s log-density. The importance weight of a particle is the sum of those log-densities over the evidence nodes only – the sampled nodes’ densities are the proposal and cancel.- Raises:
ValueError – If
validateand the evidence cannot be conditioned on at all. Passvalidate=Falseto get the degenerate result anyway.
- tbnpy.diagnostics.effective_sample_size(log_weights) torch.Tensor[source]¶
Kish effective sample size from unnormalised log weights.
log_weightsis(n_sample,)or(n_evi, n_sample). Rows whose weights are all-inf– an impossible observation – give 0.0 rather than NaN, so the caller can report the cause instead of a silent NaN.