Skip to content

SHAP Report

Beyond the standard per-source / per-feature / per-value JSON and PNG outputs (see Interpretation overview), interpret() can render a parallel SHAP-library-style report designed for client hand-off. It writes beeswarm, global bar, heatmap, per-entity waterfall, and interactive force plots under a shap/ subdirectory, plus a single static shap_report.html index that links everything — no Jupyter runtime required.

Prerequisite

The SHAP report requires the optional shap extra. Install with poetry install -E interpretability (or pip install '.[interpretability]'). The default attribution flow does not depend on it — shap is imported lazily, only when save_shap_plots=True.

One-Call Rendering

Add save_shap_plots=True to interpret(). GradientSHAP is the recommended companion method for denser, SHAP-shaped attributions, but the report renders identically with Integrated Gradients.

Python
from pathlib import Path
from datetime import datetime, timezone
from monad.interpretability import interpret

interpret(
    predictions_path=Path("./predictions.tsv"),
    output_path=Path("./interpretations"),
    checkpoint_path=Path("./my_model"),
    device="cuda",
    method="gradient_shap",
    save_shap_plots=True,
    prediction_date=datetime(2024, 6, 1, tzinfo=timezone.utc),
)

The standard interpretation outputs land at the root of output_path/, and the SHAP-style artifacts go under output_path/shap/:

interpretations/
├── source_importance.json
├── source_importance.png
├── {data_source}/
│   └── ...
└── shap/                           # Added by save_shap_plots=True
    ├── shap_beeswarm.png
    ├── shap_bar_global.png
    ├── shap_heatmap.png            # Only when n_entities ≥ 10
    ├── shap_waterfall_top1.png
    ├── shap_waterfall_top2.png
    ├── ...
    ├── shap_force_top1.html
    ├── shap_force_top2.html
    ├── ...
    └── shap_report.html            # Static index — open this first

Open shap/shap_report.html in a browser; it embeds the PNGs and links to each interactive force plot.

Rendering from Existing Attributions

When you already have attributions in memory — for example from a batched custom pipeline that calls a GradientShapInterpreter directly — skip re-running interpret() and render the report from the two public helpers:

Python
from pathlib import Path
from datetime import datetime, timezone
from monad.core import load_from_checkpoint
from monad.interpretability import (
    ClassificationGradientShapInterpreter,
    MonadExplainer,
    attributions_to_shap_explanation,
    save_shap_report,
)

checkpoint_path = Path("./my_model")
predictions_path = Path("./predictions.tsv")
output_path = Path("./interpretations")

training_module = load_from_checkpoint(checkpoint_path=checkpoint_path)
interpreter = ClassificationGradientShapInterpreter(
    training_module=training_module,
    checkpoint_path=checkpoint_path,
    predictions_path=predictions_path,
    resample=False,
    group_size=500,
)

attributions = interpreter.get_attributions(
    prediction_date=datetime(2024, 6, 1, tzinfo=timezone.utc),
    target=0,
    limit_batches=None,
    device="cuda",
)

explainer = MonadExplainer(
    attributions=attributions,
    trained_features=training_module.data_provider.dataset_provider.data.trained_features,
)

explanation = attributions_to_shap_explanation(
    attributions=attributions,
    feature_slicer=explainer.feature_slicer,
    base_value=0.0,            # Or compute E[f(baseline)] yourself
    output_name="target_0",
)

save_shap_report(
    explanation=explanation,
    output_path=output_path,
    top_n_waterfalls=5,
)

This is the right shape when you want to render the report against a custom subset of entities or alongside other downstream consumers of the raw attributions tensors.

Plot Reference

Artifact What it shows
shap_beeswarm.png Per-feature signed distribution across all entities — positive vs. negative contributions at a glance.
shap_bar_global.png Global mean-absolute attribution per feature — the SHAP equivalent of source_importance.png, but at the feature level.
shap_heatmap.png Per-entity × per-feature signed heatmap. Rendered only when n_entities ≥ 10, since the layout assumes a reasonable number of rows.
shap_waterfall_top{i}.png Single-entity additive breakdown — how each feature pushes the prediction up or down from the base value. One file per entity in the top-N by total \|Σ values\|.
shap_force_top{i}.html Interactive HTML version of the waterfall for the same top-N entities. Each file embeds ~2 MB of shap.js, so the count is capped low by default.
shap_report.html Single static index linking everything above. Self-contained — safe to email or zip.

Individual plot failures (e.g., a SHAP version mismatch on heatmap) are logged and skipped rather than aborting the whole report — shap_report.html only links what successfully rendered.

Tuning

  • top_n_waterfalls (default 5): controls how many highest-impact entities get a dedicated waterfall + force plot. Each force HTML embeds ~2 MB of shap.js, so keep this modest unless the bundle size doesn't matter.
  • GradientSHAP knobs (n_samples, stdevs, seed): not exposed through interpret(). To tune them, instantiate GradientShapInterpreter directly and call save_shap_report() yourself (see the example above).

For the full parameter list of the helpers, see Reference: Interpretability — SHAP-Style Report.