> ## Documentation Index
> Fetch the complete documentation index at: https://docs.synthefy.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Glass-box Models

> Distill Nori into a readable, shippable glass-box model (EBM) in one call — feature importance, pruning, and an auditable additive model.

Nori is accurate but, like any deep model, a black box. `NoriInterpreter` turns
it into a standalone **glass-box [Explainable Boosting Machine](https://interpret.ml)**
(EBM / GA²M) — an additive model whose entire decision logic is a set of readable
per-feature curves. You keep most of Nori's accuracy but get a model you can
inspect, ship, and audit line by line, which is often what a review or a
regulated deployment actually needs.

<Icon icon="github" /> [`examples/explainability_credit.py`](https://github.com/Synthefy/synthefy-nori/blob/main/examples/explainability_credit.py)

<Note>
  Needs the `explainability` extra (`interpret-core`, `joblib`, `scipy`). The
  SHAP-based importance path additionally needs the `interpretability` extra
  (`shapiq`).

  ```bash theme={null}
  pip install "synthefy-nori[explainability]"
  ```
</Note>

## How it works

A single `fit(X, y)` runs three steps and stores every artifact:

<Steps>
  <Step title="Measure importance">
    Fit Nori and score each raw input column by **permutation importance** — the
    drop in held-out skill when that column is shuffled.
  </Step>

  <Step title="Prune to what matters">
    Drop the low-importance columns, keeping the smallest subset that still
    retains ≥ `retain` (default 95%) of Nori's skill.
  </Step>

  <Step title="Distill a glass-box">
    Fit an EBM on the surviving features. It learns one shape function per
    feature (plus a few pairwise interactions), so the whole model reads as
    `baseline + Σ per-feature contributions`.
  </Step>
</Steps>

The task (regression or classification) is auto-detected — Nori itself stays
regression-only and scores the pruning, while the distilled EBM matches the
target type.

## Quickstart

```python theme={null}
from synthefy_nori.explainability import NoriInterpreter

interp = NoriInterpreter().fit(X, y)      # full table; model="nori-6m" by default

interp.feature_importances_    # per input column (skill drop when shuffled)
interp.importance_ranking_     # [{feature, index, importance}], most-important first
interp.selected_features_      # the pruned feature set (kept ≥ retain of Nori's skill)
interp.ebm_                    # the fitted glass-box model (shippable)
interp.summary()               # {task, metric, n_selected, nori/ebm scores, top_features}
interp.plot_model()            # draw the glass-box shape functions (below)
interp.predict(X_new)          # score with the glass-box on the selected features
```

## Worked example — UCI Credit Default

[`examples/explainability_credit.py`](https://github.com/Synthefy/synthefy-nori/blob/main/examples/explainability_credit.py)
runs the full flow on the UCI Credit Default table (23 features, \~30k rows,
downloaded fresh). The permutation ranking is dominated by `PAY_0` — the most
recent repayment status — with the credit limit and earlier repayment months
trailing it:

<Frame caption="Nori-permutation importance (top 10). PAY_0 — the latest repayment status — carries most of the signal; importance = drop in test AUC when that column is shuffled.">
  <img src="https://mintcdn.com/synthefy/84wJ-dSadd8Wxm1p/assets/nori-explainability-importance.png?fit=max&auto=format&n=84wJ-dSadd8Wxm1p&q=85&s=664bb902df4aad64d3e444a3da6231a5" alt="Nori feature importance bar chart for the credit-default dataset" width="1335" height="700" data-path="assets/nori-explainability-importance.png" />
</Frame>

Pruning keeps **7 of 23** features at the 95% bar, and distilling those into an
EBM costs very little: Nori scores **AUC 0.781** on all features, and the
glass-box EBM reaches **0.766** on the 7 it kept. The distilled model is fully
legible — each middle panel is one feature's contribution to the predicted
default probability, the right-hand heatmaps are pairwise interactions, and the
`Σ → σ` node adds the baseline and every contribution into the final prediction:

<Frame caption="The distilled glass-box EBM (7 features, test AUC 0.766). Read left-to-right: each shape function maps a feature's value to how much it pushes default probability up (+) or down (−); grey bars show where the data is dense (trustworthy) vs sparse (extrapolated); Σ then σ combine the baseline and all contributions into ŷ.">
  <img src="https://mintcdn.com/synthefy/84wJ-dSadd8Wxm1p/assets/nori-explainability-glassbox.png?fit=max&auto=format&n=84wJ-dSadd8Wxm1p&q=85&s=7acc2b155d7a01ff0a112d947267fb59" alt="Glass-box EBM model diagram distilled from Nori on the credit-default dataset" width="2903" height="3107" data-path="assets/nori-explainability-glassbox.png" />
</Frame>

## Configuration

<AccordionGroup>
  <Accordion title="NoriInterpreter parameters" icon="sliders">
    | Parameter          | Default     | Description                                                                                                          |
    | ------------------ | ----------- | -------------------------------------------------------------------------------------------------------------------- |
    | `model`            | `"nori-6m"` | Nori checkpoint used to measure importance and score the pruning.                                                    |
    | `retain`           | `0.95`      | Skill fraction to keep when pruning — the EBM is fit on the smallest subset that holds ≥ this share of Nori's score. |
    | `reduce_threshold` | `16`        | Only prune when the table has more than this many features; smaller tables keep every column.                        |
    | `test_size`        | `0.3`       | Held-out fraction used to measure importance and score the pruning sweep.                                            |
    | `random_state`     | `0`         | Seed for the internal split and permutation shuffles.                                                                |
  </Accordion>
</AccordionGroup>

For finer control, the same steps are exposed as standalone functions — import
from the submodules: `explainability.importance` (`nori_permutation_importance`,
`nori_shap_importance`), `explainability.ebm` (`fit_ebm`, `ebm_structure`), and
`explainability.pipeline` (`run`, the end-to-end importance → EBM driver).

## Good to know

* Runs on the **local Python package** (`synthefy-nori`), not the hosted API.
* Nori remains the source of truth for accuracy — the EBM is a faithful,
  auditable *approximation* on the selected features, so expect a small score
  gap (≈0.01 AUC on the credit example).
* For single-prediction attributions, feature interactions, and partial
  dependence, see [Explainability](/nori/explainability).

## Next steps

<CardGroup cols={2}>
  <Card title="Explainability" icon="magnifying-glass-chart" href="/nori/explainability">
    SHAP / Shapley values, interactions, PDP, and feature selection.
  </Card>

  <Card title="Categorical & Ordinal Targets" icon="list-ol" href="/nori/categorical-targets">
    Predict labels on a discrete scale instead of a continuous estimate.
  </Card>
</CardGroup>
