Epistemic variance¶
TRIAD needs a variance \(v\) for every fitted value: how uncertain is the model about this bin (exact mode) or this attribution (approximate mode)? That variance is the denominator of the support weight — without it there is no information/epistemic split.
Why bagging¶
No mainstream GBM exposes usable per-feature epistemic variance natively. The research verdict recorded in decision 2:
| Package | Native epistemic variance | Verdict for TRIAD |
|---|---|---|
| CatBoost | Yes — SGLB virtual ensembles | Per-instance only, not per-feature/per-bin; a fast-path is on the roadmap |
| XGBoost | No (quantile objectives are aleatoric) | Generic bagging |
| LightGBM | No | Generic bagging (triadxai.bagging, default K = 8) |
| AdaBoost (sklearn) | No (stages measure convergence, not epistemic spread) | Generic bagging |
| EBM (interpret) | Yes — outer-bag SDs (standard_deviations_) |
Used directly as per-bin v |
So TRIAD refits K bootstrap replicas of the model and reads variance from their disagreement. In sparse regions each replica sees a different handful of points, so split thresholds and leaf values there are pinned by few observations and the replicas diverge; where thousands of points constrain the fit, replicas agree. The disagreement is a density/extrapolation signal on the score scale, produced by the data itself (decision 3).
The two forms¶
- Exact mode — per-bin shape variance: each replica's shape function is
evaluated on the term's bin representatives, centered, and the across-replica
variance (
ddof=1) becomes the bin'sv.fit_lgbm_gam(..., n_bags=8)fits the deployed booster plus its replicas in one call; with no replicas, per-bin variances are zero and a warning notes that D will be degenerate. - Approximate mode — per-instance attribution variance: \(v_j(x) = \operatorname{Var}_k \phi_j^{(k)}(x)\) across the replicas' TreeSHAP attributions. At least 2 replicas are required.
Using fit_bagged directly¶
For approximate mode (or any custom model-fitting routine), fit_bagged refits a
user-supplied fit_fn(X_boot, y_boot, bag_seed) on bootstrap resamples, one
distinct seed per bag; bootstraps that collapse to a single class (binary targets
with rare positives) are redrawn:
from triadxai.bagging import fit_bagged
bags = fit_bagged(fit_fn, X, y, n_bags=8, seed=0)
Provenance¶
Attributions always come from the single deployed model; the replicas contribute only variance. The reconciliation guarantees (C1/C2) therefore hold exactly on the deployed model's outputs (decision 4).