migration.md
424 lines · skills/shap/references/migration.md at 5f2bc03
Most marks come from matching words in the file, so treat them as pointers.
SHAP Migration and Compatibility
This guide covers migration to SHAP 0.52.0 and the modern shap.Explanation API.
Version Baseline
| SHAP release | Python requirement | Important compatibility note |
|---|---|---|
| 0.52.0 | >=3.12 | Current release; NumPy >=2; native bindings moved to nanobind/scikit-build-core |
| 0.51.0 | >=3.11 | Latest release suitable for Python 3.11 |
| 0.50.0 | >=3.11 | First release after Python 3.9/3.10 support ended |
| 0.49.1 | >=3.9 | Last release line supporting Python 3.9 and 3.10; fixes the broken 0.49.0 publication |
For a new environment:
uv venv --python 3.12
source .venv/bin/activate
uv pip install "shap[plots]==0.52.0"For a project that cannot move off Python 3.11:
uv pip install "shap[plots]==0.51.0"For Python 3.9 or 3.10, upgrade Python if possible. If temporarily constrained:
uv pip install "shap[plots]==0.49.1"Do not claim 0.49.1 behavior is identical to 0.52. Read the release notes and test model-library compatibility.
Raw lines 5 to 35Major Changes Affecting Existing Code
Raw lines 36 to 370.45.0
- Python 3.8 support ended.
- Multi-output SHAP values changed from a list to a NumPy array with the output dimension last.
- Deprecated
feature_dependenceparameters were removed fromTreeExplainerandLinearExplainer. - Python 3.12 support was added.
0.46.0
- NumPy 2, Keras 3, and TensorFlow 2.16 support was added.
- The deprecated
auto_size_plotargument tosummary_plotwas removed.
0.47.0
TreeExplainer(feature_perturbation="auto")became the default behavior: interventional when background data are supplied, tree-path-dependent otherwise.- Passing
approximateto theTreeExplainerconstructor was deprecated; pass it when calling the explainer. - Plotting APIs continued moving toward
Explanationinputs and returned axes. - Legacy bar plotting gained deprecation guidance.
0.49.x
- 0.49.1 repaired the 0.49.0 release publication.
- 0.49.x was the final line supporting Python 3.9 and 3.10.
- C++ categorical-split support expanded.
0.50.0–0.51.0
- Python 3.11 became the minimum.
- Type coverage and tree/path-dependent behavior continued to improve.
0.52.0
- Python 3.12 became the minimum.
- NumPy 2 became a core minimum requirement.
- Native bindings moved from legacy extension/setup.py machinery to nanobind with scikit-build-core and CMake.
- Tree/GPU fixes improved missing-value routing, vector-valued XGBoost base scores, and multiclass additivity.
TreeExplainergained a pandas nullable-dtype fix.- Plot and documentation examples continued moving to the modern API.
Verified 0.52.0 traps
- Tabular backgrounds are capped at 100 by default; set the masker's
max_samplesexplicitly for larger experiments. Explainer(algorithm="deep")fails through unsupported dispatch keywords; useDeepExplainerdirectly.- Kernel SHAP defaults to
l1_reg="num_features(10)"; declare regularization and sampling budgets. - Tree interactions require the raw, tree-path-dependent path; do not reuse a probability/interventional explainer.
- Loss baselines may be callable and label-dependent, and classifier loss transforms require model-specific verification.
- A one-output deep array can retain a final singleton output axis;
ranked_outputsbelongs on.shap_values, not the constructor.
Explanation API Migration
Raw lines 86 to 87Compute explanations
Legacy:
values = explainer.shap_values(X)Modern:
explanation = explainer(X)
values = explanation.values
base_values = explanation.base_valuesKeep the Explanation object instead of immediately extracting .values; plots and slicing use its metadata.
Base values
Legacy:
base_value = explainer.expected_valueModern:
base_values = explanation.base_valuesbase_values can be scalar, per-row, per-output, or per-row/per-output. Inspect shape.
Multi-output values
Pre-0.45 code often assumed a list:
positive_values = values[1]Modern tabular code uses the final output axis:
positive_exp = explanation[..., 1]
positive_values = explanation.values[..., 1]explanation[1] selects the second sample, not the second class.
For scikit-learn RandomForestClassifier, a typical shape is:
(samples, features, classes)For XGBoost binary classification with default raw output, a typical shape is:
(samples, features)Do not hard-code a binary shape across model families.
Raw lines 122 to 152Plot Migration
Raw lines 153 to 154Summary plot to beeswarm
Legacy:
shap.summary_plot(values, X)Modern:
shap.plots.beeswarm(explanation)Raw lines 155 to 168Summary bar to bar
Legacy:
shap.summary_plot(values, X, plot_type="bar")Modern:
shap.plots.bar(explanation)Raw lines 169 to 182Dependence plot to scatter
Legacy:
shap.dependence_plot("age", values, X, interaction_index="bmi")Modern:
shap.plots.scatter(
explanation[:, "age"],
color=explanation[:, "bmi"],
)Raw lines 183 to 199Force plot
Legacy:
shap.force_plot(
explainer.expected_value,
values[row_index],
X.iloc[row_index],
)Modern:
shap.plots.force(explanation[row_index])Raw lines 200 to 217Local waterfall
Legacy code often manually built an Explanation from arrays. Modern:
shap.plots.waterfall(explanation[row_index])Raw lines 218 to 225Image plot
Legacy:
shap.image_plot(values, images)Modern:
shap.plots.image(explanation)Raw lines 226 to 239Decision plot
shap.plots.decision remains largely array-oriented:
shap.plots.decision(
base_value,
values,
features=X_display,
feature_names=feature_names,
)Select one output and compatible base value before calling it.
Raw lines 240 to 254TreeExplainer Migration
Raw lines 255 to 256feature_dependence
Removed:
shap.TreeExplainer(model, feature_dependence="independent")Current:
shap.TreeExplainer(
model,
data=background,
feature_perturbation="interventional",
)Or:
shap.TreeExplainer(
model,
feature_perturbation="tree_path_dependent",
)These are not mechanical synonyms for every old setting. Reconfirm the intended game and baseline.
Raw lines 257 to 285Default feature perturbation
Old code could rely on an interventional default. Current "auto" behavior depends on whether data are passed.
Make reproducibility explicit:
explainer = shap.TreeExplainer(
model,
data=background,
feature_perturbation="interventional",
model_output="raw",
)Raw lines 286 to 300Approximation
Deprecated constructor use:
explainer = shap.TreeExplainer(model, approximate=True)
values = explainer(X)Current:
explainer = shap.TreeExplainer(model)
explanation = explainer(X, approximate=True)Label approximate values and do not treat them as ordinary Tree SHAP.
Raw lines 301 to 318Probability output
Use:
explainer = shap.TreeExplainer(
model,
data=background,
feature_perturbation="interventional",
model_output="probability",
)
explanation = explainer(X)Probability and log-loss output modes are currently supported only under interventional feature perturbation.
Raw lines 319 to 334DeepExplainer Output Migration
Pre-0.45 code:
values_by_class = explainer.shap_values(X)
class_values = values_by_class[class_index]Modern one-input, multi-output result:
values = explainer.shap_values(X)
class_values = values[..., class_index]Multiple model inputs still produce a list, one array per input. ranked_outputs=k returns (values, indexes); preserve the indexes because selected outputs can differ per row.
Link and Output Migration
Do not use a display link to pretend an explanation was computed in another space.
shap.plots.force(raw_margin_exp[row], link="logit")This labels raw margins as probabilities for display. It is not equivalent to:
shap.TreeExplainer(
model,
data=background,
feature_perturbation="interventional",
model_output="probability",
)(X)The two additive decompositions can differ.
Raw lines 353 to 373End-to-End Migration Recipe
- Pin old and new environments.
- Capture model predictions and existing SHAP outputs on a small immutable fixture.
- Prefer
explainer(X)where it exposes the required controls. Keep specialized.shap_valuescalls for Kernelnsamples, deep ranked outputs, and gradient sampling budgets. - Print every result shape.
- Replace list-based output selection with final-axis slicing.
- Replace legacy plotting calls.
- Make tree perturbation and output explicit.
- Validate additive reconstruction against the exact selected output.
- Compare baselines and local values; do not require numerical identity if the game/default changed.
- Run model-library compatibility tests, especially for XGBoost, LightGBM, CatBoost, TensorFlow, Keras, and PyTorch.
- Update stored report metadata and migration notes.
Compatibility Diagnostic
import importlib.metadata
import platform
packages = [
"shap",
"numpy",
"pandas",
"scikit-learn",
"xgboost",
"lightgbm",
"catboost",
"tensorflow",
"keras",
"torch",
]
print("Python", platform.python_version())
for package in packages:
try:
print(package, importlib.metadata.version(package))
except importlib.metadata.PackageNotFoundError:
passAttach this output to reproducible bug reports, without environment variables or credentials.
Raw lines 388 to 416Sources
- SHAP release notes: https://shap.readthedocs.io/en/latest/release_notes.html
- SHAP 0.52.0 release: https://github.com/shap/shap/releases/tag/v0.52.0
- PyPI metadata: https://pypi.org/project/shap/0.52.0/
- Explanation migration guide: https://shap.readthedocs.io/en/latest/example_notebooks/api_examples/migrating-to-new-api.html
- TreeExplainer API: https://shap.readthedocs.io/en/latest/generated/shap.TreeExplainer.html
- Plot API: https://shap.readthedocs.io/en/latest/api.html#plots