API reference

The public API is the RegimeSHAPAnalyzer class plus the module-level functions it builds on.

RegimeSHAPAnalyzer

class regime_shap.core.RegimeSHAPAnalyzer(model, X, regimes, *, date_column=None, small_sample_threshold=10, moderate_threshold=0.3, stable_threshold=0.6, random_state=42)[source]

Regime-aware SHAP feature-importance stability analysis for a tree model.

Supported models are tree-based (XGBoost, LightGBM, or scikit-learn tree ensembles), computed through shap.TreeExplainer. This is deliberate: TreeExplainer is exact and fast, which is what makes the bootstrap confidence intervals feasible, since they recompute SHAP many times per regime. The stability methodology itself is model-agnostic (everything downstream operates on SHAP arrays, not the model), so support for other model types via pluggable explainers is a possible future extension, with the caveat that the bootstrap becomes expensive and approximate for non-tree models.

Parameters:
  • model (object)

  • X (pd.DataFrame)

  • regimes (object)

  • date_column (str | None)

  • small_sample_threshold (int)

  • moderate_threshold (float)

  • stable_threshold (float)

  • random_state (int)

global_importance()[source]

Global mean absolute SHAP per feature, most important first.

Return type:

Series

per_regime_importance()[source]

Feature-by-regime mean absolute SHAP.

Return type:

DataFrame

per_regime_rankings()[source]

Feature-by-regime importance rankings (1 = most important).

Return type:

DataFrame

sample_sizes()[source]

Per-regime observation counts with the small-sample flag.

Return type:

DataFrame

small_regimes()[source]

The set of regime labels flagged small-sample.

Return type:

Set[str]

stability_matrix()[source]

Regime-by-regime Spearman correlation of the feature rankings.

Return type:

DataFrame

stability_classified()[source]

Every regime pair with its Spearman rho, Akoglu band, and small-regime flag.

Return type:

DataFrame

bootstrap_cis(*, n_bootstrap=1000)[source]

Bootstrap confidence intervals for every regime pair involving a small regime.

Parameters:

n_bootstrap (int) – Number of bootstrap resamples per regime.

Returns:

A DataFrame of regime_a, regime_b, ci_lower, ci_upper, and effective_n (the smaller regime’s size), one row per pair that involves a small-sample regime. Empty if no regime is small.

Return type:

DataFrame

plot_global(**kwargs)[source]

Global importance bar chart (see plots.plot_global_importance).

Return type:

Figure

plot_per_regime(**kwargs)[source]

Per-regime importance heatmap (see plots.plot_per_regime_importance).

Return type:

Figure

plot_stability(**kwargs)[source]

Stability heatmap, with the small regimes flagged and the analyzer’s bands.

Return type:

Figure

results()[source]

The result tables, ready for report (HTML, dict, or CSV).

Return type:

dict[str, DataFrame | Series]

to_html(**kwargs)[source]

Render the results as a self-contained HTML report.

Return type:

str

save_csv(output_dir)[source]

Write the result tables to CSV files in output_dir.

Parameters:

output_dir (str | Path)

Return type:

list[Path]

regime_shap.breaks

Turn regime specifications into per-row regime labels.

Per-row labels are the package’s internal representation: a label for every row of the feature matrix, saying which regime that row belongs to. Users can supply labels directly (the most general, domain-agnostic form) or, for date-indexed data, give date ranges as a list of (start, end) tuples or a {label: (start, end)} dict, which the adapters here convert to per-row labels.

Optionally, when the user has no regimes in mind, detect_breaks wraps the ruptures change-point library to propose break points from a series; ruptures is an optional dependency (install with the detection extra).

regime_shap.breaks.regimes_to_labels(X, regimes, *, date_column=None)[source]

Resolve any accepted regime specification into a per-row label Series.

Parameters:
  • X (DataFrame) – The feature matrix whose rows are being labelled.

  • regimes (object) – One of three forms: - a per-row sequence of labels, length len(X) (most general); - a list of (start, end) date ranges (labelled by position); - a {label: (start, end)} mapping. The date-range forms require X to be datetime-indexed or to have a date_column.

  • date_column (str | None) – Name of a datetime column to use instead of the index for the date-range forms. Ignored for per-row labels.

Returns:

A Series of regime labels aligned to X (same length and index).

Raises:

ValueError – If a per-row sequence has the wrong length, if a date-range form is given without usable dates, or if a row falls outside every supplied range.

Return type:

Series

regime_shap.breaks.detect_breaks(series, *, n_breaks=3, model='l2')[source]

Propose change-point positions in a 1D series using ruptures (optional dependency).

Parameters:
  • series (Series) – The 1D series to search for structural breaks.

  • n_breaks (int) – Number of break points to return (uses ruptures’ Dynp).

  • model (str) – The ruptures cost model (“l2”, “l1”, “rbf”, …).

Returns:

A list of break-point row positions (integer indices into series), excluding the final endpoint.

Raises:

ImportError – If ruptures is not installed (pip install regime-shap[detection]).

Return type:

list

regime_shap.compare

Per-regime SHAP feature importance and rankings.

Given SHAP values and a per-row regime label, this computes, within each regime, the mean absolute SHAP value per feature (that regime’s feature importance) and the resulting importance ranking. It also reports each regime’s sample size and flags small samples, whose rankings carry more uncertainty. The functions operate on plain arrays, not a fitted model, so they are model-agnostic and cheap to test.

regime_shap.compare.per_regime_importance(shap_values, feature_names, labels)[source]

Mean absolute SHAP value per feature, within each regime.

Parameters:
  • shap_values (ndarray) – A 2D array of SHAP values, rows by features, aligned to the rows the labels describe.

  • feature_names (Sequence[str]) – Column names for the features, length must match the number of SHAP columns.

  • labels (Series) – A per-row regime label for each row of shap_values.

Returns:

A DataFrame indexed by feature, one column per regime (in first- appearance order), holding the regime’s mean absolute SHAP per feature.

Raises:

ValueError – If shap_values is not 2D, if the lengths of labels or feature_names do not match, or if any regime has fewer than two observations (a single row cannot give a meaningful importance).

Return type:

DataFrame

regime_shap.compare.per_regime_rankings(importance)[source]

Rank features within each regime, 1 being the most important.

Parameters:

importance (DataFrame) – A feature-by-regime DataFrame of mean absolute SHAP, as returned by per_regime_importance().

Returns:

A DataFrame of the same shape holding ranks per regime; tied features share the average of the ranks they span.

Return type:

DataFrame

regime_shap.compare.regime_sample_sizes(labels, *, small_sample_threshold=10)[source]

Per-regime observation counts with a small-sample flag.

Parameters:
  • labels (Series) – A per-row regime label.

  • small_sample_threshold (int) – Regimes with fewer observations than this are flagged; their rankings should be read with the bootstrap confidence intervals rather than at face value.

Returns:

regime, n_observations, and small_sample (bool).

Return type:

A DataFrame with one row per regime

regime_shap.stability

Cross-regime stability of SHAP feature-importance rankings.

The question this module answers: do the features the model leans on stay the same across regimes, or do they reshuffle? Two regimes’ feature rankings are compared with Spearman rank correlation (rho): 1 means identical orderings, -1 reversed, near 0 unrelated. pairwise_spearman_matrix builds the full regime-by-regime table, and classify_stability labels a rho using the Akoglu (2018) bands.

Small regimes give noisy rankings, so bootstrap_rankings resamples a regime’s rows with replacement and recomputes the SHAP rankings each time, and bootstrap_spearman_ci turns those into a confidence interval on rho, the honest uncertainty a handful of observations carries rather than a single falsely precise number. Rankings, not raw SHAP magnitudes, are compared, so the result is not confounded by volatility differences between regimes.

Akoglu, H. (2018) ‘User’s guide to correlation coefficients’, Turkish Journal of Emergency Medicine, 18(3), pp. 91-93.

regime_shap.stability.pairwise_spearman_matrix(rankings)[source]

Regime-by-regime Spearman correlation of the per-regime feature rankings.

Parameters:

rankings (DataFrame) – A feature-by-regime DataFrame of ranks, as returned by compare.per_regime_rankings.

Returns:

A square regime-by-regime DataFrame of Spearman rho, symmetric with a unit diagonal.

Return type:

DataFrame

regime_shap.stability.classify_stability(rho, *, moderate_threshold=0.3, stable_threshold=0.6)[source]

Label a Spearman rho by the Akoglu (2018) bands.

Parameters:
  • rho (float) – A Spearman rank correlation.

  • moderate_threshold (float) – Upper edge of the unstable band (default 0.3).

  • stable_threshold (float) – Upper edge of the moderate band (default 0.6).

Returns:

“stable” when rho > stable_threshold, “moderately stable” when moderate_threshold < rho <= stable_threshold, else “unstable”.

Return type:

str

regime_shap.stability.bootstrap_rankings(model, X_regime, *, n_bootstrap=1000, random_state=42)[source]

Bootstrap the SHAP feature rankings within one regime.

Resamples the regime’s rows with replacement n_bootstrap times, and for each resample recomputes TreeSHAP and ranks the features by mean absolute SHAP. Exploratory: this quantifies the uncertainty a small regime’s ranking already has, it does not remove it.

Parameters:
  • model (object) – A fitted tree model compatible with shap.TreeExplainer. The explainer is recomputed once per resample, so its speed matters here; this exact, fast path is the reason the package is tree-only for now.

  • X_regime (DataFrame) – The feature rows belonging to one regime.

  • n_bootstrap (int) – Number of resamples.

  • random_state (int) – Seed, so the result is reproducible.

Returns:

An (n_bootstrap, n_features) array of rankings, one row per resample.

Warns:
  • If the regime has fewer than ``MIN_BOOTSTRAP_OBS`` rows, the CI derived

  • from these rankings will be unreliable.

Return type:

ndarray

regime_shap.stability.bootstrap_spearman_ci(rankings_a, rankings_b, *, n_bootstrap=1000, ci=0.95)[source]

Confidence interval for Spearman rho between two regimes’ bootstrap rankings.

Pairs resample i of one regime with resample i of the other, computes rho for each pair, and returns the requested percentile interval of that distribution. For a pair involving a small regime this interval is often wide, which honestly reflects the uncertainty already present.

Parameters:
  • rankings_a (ndarray) – An (n_bootstrap, n_features) array from bootstrap_rankings.

  • rankings_b (ndarray) – The other regime’s array of the same shape.

  • n_bootstrap (int) – Cap on the number of paired draws used.

  • ci (float) – Confidence level (default 0.95 for a 95% interval).

Returns:

A (lower, upper) tuple of rho at the interval’s edges.

Return type:

tuple[float, float]

regime_shap.plots

Figures for regime-aware SHAP analysis.

Each function returns a matplotlib Figure; the caller saves or displays it. The figures are model- and domain-agnostic, they take the importance and stability tables the other modules produce, not any project-specific data. The stability heatmap colours cells by the Akoglu (2018) bands and can flag small-sample regimes so a reader does not over-read their rows.

regime_shap.plots.plot_global_importance(importance, *, title='Global SHAP feature importance')[source]

Horizontal bar chart of global mean absolute SHAP per feature.

Parameters:
  • importance (Series) – A Series of mean absolute SHAP indexed by feature.

  • title (str) – The figure title.

Returns:

A matplotlib Figure, most-important feature at the top.

Return type:

Figure

regime_shap.plots.plot_per_regime_importance(importance, *, title='Per-regime SHAP feature importance')[source]

Heatmap of mean absolute SHAP per feature (rows) within each regime (columns).

Parameters:
  • importance (DataFrame) – A feature-by-regime DataFrame of mean absolute SHAP.

  • title (str) – The figure title.

Returns:

A matplotlib Figure with a colour bar.

Return type:

Figure

regime_shap.plots.plot_stability_heatmap(matrix, *, small_regimes=None, moderate_threshold=0.3, stable_threshold=0.6, title='SHAP ranking stability across regimes (Spearman rho)')[source]

Regime-by-regime Spearman heatmap coloured by the Akoglu (2018) bands.

Parameters:
  • matrix (DataFrame) – A square regime-by-regime DataFrame of Spearman rho.

  • small_regimes (Set[str] | None) – Regime labels to flag with an asterisk (small samples, whose rows should be read with the bootstrap confidence intervals).

  • moderate_threshold (float) – Upper edge of the unstable band (default 0.3).

  • stable_threshold (float) – Upper edge of the moderate band (default 0.6).

  • title (str) – The figure title.

Returns:

cells coloured red (unstable), orange (moderate), or green (stable), annotated with rho to two decimals.

Return type:

A matplotlib Figure

regime_shap.report

Assemble the regime-aware SHAP results into shareable reports.

The analysis produces a handful of tables (global importance, per-regime rankings, the stability matrix and its band classifications, sample sizes, and any bootstrap confidence intervals). This module turns that collection into a self-contained HTML report as the headline output, and exposes the same tables as a plain dictionary and as CSV files so the results stay machine-readable. Callers pass a mapping of {name: table}; the module does not assume any particular set of tables, so it stays general.

regime_shap.report.to_dict(tables)[source]

Return the result tables as JSON-serialisable nested dicts.

Parameters:

tables (Mapping[str, DataFrame | Series]) – A mapping of table name to DataFrame or Series.

Returns:

A dict keyed by table name; each DataFrame becomes a {column: {index: value}} dict and each Series an {index: value} dict.

Return type:

dict

regime_shap.report.save_csv(tables, output_dir)[source]

Write each table to output_dir/<name>.csv.

Parameters:
  • tables (Mapping[str, DataFrame | Series]) – A mapping of table name to DataFrame or Series.

  • output_dir (str | Path) – Directory to write into; created if it does not exist.

Returns:

The list of written file paths, in the order of tables.

Return type:

list[Path]

regime_shap.report.to_html(tables, *, title='regime-shap stability report', notes=None)[source]

Render the tables as a single self-contained HTML report.

Parameters:
  • tables (Mapping[str, DataFrame | Series]) – A mapping of table name to DataFrame or Series, rendered in order under headings.

  • title (str) – The page and top heading title.

  • notes (list[str] | None) – Optional caveats shown near the top, for example that small regimes should be read with their bootstrap confidence intervals.

Returns:

A complete HTML document as a string.

Return type:

str