Getting started¶
Install¶
pip install triadxai # core: numpy, pandas, scipy, lightgbm
pip install triadxai[viz] # + matplotlib waterfalls
pip install triadxai[ebm] # + InterpretML EBM adapter
Exact mode: additive LightGBM¶
fit_lgbm_gam fits a LightGBM booster constrained so every tree splits on a
single feature — an additive model — plus K bootstrap replicas that provide
per-bin epistemic variance:
import numpy as np
from triadxai import TriadExplainer, fit_lgbm_gam
from triadxai.synthetic import make_missingness
data = make_missingness(n=5000, mechanism="MNAR", missing_effect=1.0, seed=0)
result = fit_lgbm_gam(data.X, data.y, n_bags=8, seed=0)
explainer = TriadExplainer(result)
exp = explainer.explain(data.X.head(100))
exp.channels # long frame: (instance, feature) x [I, D, M, w, oov]
exp.epistemic_score() # ES, ES_signed, KR per instance
exp.reasons(k=4) # ranked, group-tagged adverse-action reasons
exp.plot_waterfall(0) # three-channel waterfall (D hatched)
Thin-file rows (many missing values) show low knowledge ratio KR and
Group B ("insufficient information") reasons; rows with well-supported
derogatory signal show Group A reasons carried by the I channel.
The audit payload required by spec §4.4 is available as
explainer.shrinkage (per-term τ², σ², k) plus the per-feature w column in
the channels frame.
Approximate mode: any LightGBM booster¶
For an unconstrained (interacting) booster, TRIAD reallocates native TreeSHAP attributions instead. Provide bag replicas for the variance signal:
import lightgbm as lgb
from triadxai.bagging import fit_bagged
def fit_fn(X, y, seed):
return lgb.train(
{"objective": "binary", "verbosity": -1, "seed": seed},
lgb.Dataset(X, label=y), num_boost_round=300,
)
booster = fit_fn(data.X, data.y, 0)
bags = fit_bagged(fit_fn, data.X, data.y, n_bags=8, seed=0)
explainer = TriadExplainer(booster, bag_boosters=bags, X_ref=data.X)
exp = explainer.explain(data.X.head(100))
exp.approximate # True — waterfalls carry an "approximate" badge
EBM (optional extra)¶
from interpret.glassbox import ExplainableBoostingClassifier
ebm = ExplainableBoostingClassifier(interactions=2, outer_bags=8)
ebm.fit(X_train, y_train)
exp = TriadExplainer(ebm).explain(X_test) # exact mode; outer-bag SDs as v