shap is exact for tree ensembles and an approximation for deep networks
A game theoretic approach to explain the output of any machine learning model.
At a glance
- What is it?
- A Python library for attributing a model's output to its inputs, built on Shapley values from game theory, with one Explainer constructor that dispatches on what you hand it. What the dispatch hides is the most important thing to know before you rely on a number: the tree path is exact, the deep learning path is a high-speed approximation, and the GPU path needs the cuda extra plus the CUDA toolkit on your system.
- Who is it for?
- SHAP fits a team explaining a model it has to defend, where an additive attribution with a stated theoretical basis is worth more than a feature importance ranking. It does not fit a setting where the attribution has to be exact, because the deep learning path is explicitly an approximation and the approximations are tuned for speed.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Jupyter Notebook, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 13, 2026, and from our analysis. They are not legal advice.
Star history
- shap/shap25,861 ★ · +112
| Repository | 2026-09-13 | 2026-11-13 |
|---|---|---|
| shap/shap | 25.7k | 25.9k |
112 Stars in the last 61 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
One Explainer constructor, and the algorithm is chosen for you
The modern API surface of this library is small, and the reason it is small is that the constructor dispatches on the model you pass it.
explainer = shap.Explainer(model)
shap_values = explainer(X)That is the whole sequence for a tree model, and the comment in the example notes that the same syntax works for LightGBM, CatBoost, scikit-learn, transformers and Spark. So the call site does not change when your model family does. You hand over a fitted model and a set of rows, and the library decides how to attribute them.
This is the right ergonomic decision and it hides a decision you should probably make consciously. There is a materially faster exact algorithm for tree ensembles, backed by a paper in a machine intelligence journal, with C++ implementations for several of the common tree libraries. There is a separate high-speed approximation for deep networks. And for natural language models there is a third path again, built by adding coalitional rules so that a large model can be explained using very few function evaluations. Three mechanisms, one constructor.
The visualisation API is similarly flat. A waterfall plot shows what pushed one prediction from a base value to its output, with features raising the prediction in one colour and lowering it in the other, where the base value is the average model output over the training rows you passed. A force plot does the same for one row and, rotated and stacked, for a whole batch. A scatter plot relates one feature's attribution to its value across the dataset and picks a second feature to colour by when you hand it the full explanation, and a beeswarm summarises every feature and every sample at once, sorting by total attribution magnitude.
So the ergonomics are excellent. The question is only whether you know which of the three mechanisms produced the number.
Exact for trees, an approximation for deep networks, and the README says which
The distinction is stated in the documentation rather than buried, and it is the single most important thing to read before you quote a SHAP value to anyone.
For tree ensembles, the project describes a high-speed exact algorithm. Exact means the attribution is the Shapley value, not an estimate of it. For those models the cost of computing the exact answer is low enough that there is no reason to approximate, which is a rare and good property in this field.
For deep learning, the documentation calls it a high-speed approximation algorithm. The implementation builds on a connection with an earlier method for deep network attribution and differs from it in two specific ways: it uses a distribution of background samples rather than a single reference value, and it uses Shapley equations to linearise components such as max, softmax, products and divisions. It also notes that some of those enhancements have since been folded back into the earlier method, so the two are converging rather than one superseding the other.
The support surface differs too. TensorFlow models and Keras models on the TensorFlow backend are supported, and the wording about PyTorch is preliminary support. So on the deep learning path there is both an approximation and a smaller support matrix, while on the tree path there is an exact answer and a fast one.
For natural language models, the coalitional rules reduce the number of function evaluations needed, which is a cost reduction rather than a claim of exactness. Getting a per-class explanation from a text pipeline also requires asking the pipeline for all classes rather than the default top one, since the example passes that argument explicitly so it can then visualise one class.
The practical consequence: an attribution from a gradient-boosted tree is a Shapley value, and an attribution from a neural network is a Shapley-derived estimate whose accuracy depends on the background distribution you chose. Those are different objects and should not be presented in the same chart without saying so.
GPU Tree SHAP cannot be installed from a wheel
The install section has a second path under a heading about GPU support, and the requirement in it is the kind that changes a deployment plan.
GPU-accelerated Tree SHAP (`GPUTreeExplainer`) is enabled by installing the `cuda` extra, and it requires the CUDA toolkit to be installed on your system:
pip install shap[cuda]The manifest maps the cuda extra to a separate shap-cuda package. The plain install, whether from the package index or from a conda channel, does not include that extra.
If you want the accelerated path in a container image, the image needs the CUDA toolkit as well as the extra.
The broader point is that this library is not a pure-Python package. The build configuration in the project manifest names scikit-build-core as the build backend together with nanobind, and the repository has a CMakeLists.txt, which is how the C++ parts are compiled and bound.
If you need the GPU path, plan for the CUDA toolkit at image build time.
The dependency floor is set by SPEC 0, not by this project
The supported versions section is one sentence and it delegates the decision to somebody else.
The project states that it follows a published specification for minimum supported dependency versions, that it tests against the versions specified there, and that it may not fix bugs for older versions. That specification is the one the scientific Python community agrees on as the lowest common denominator its packages support.
So the reason a bug in your SHAP might not be fixed is not that this project does not care, but that your version of a dependency is below the floor everyone else agreed to test against. That is a genuinely better arrangement than each project picking its own floor, because it means a fix in SHAP does not get held up by a constraint that only matters to one package.
The flip side is that your dependency set is constrained by consensus rather than by need. If your environment is pinned below the floor for a good reason of your own, you are in the position of choosing between raising your pins and accepting that bug fixes will not reach you, and that conversation is with the rest of your stack rather than with this project.
The Python floor is the project's own and it is a high one. The manifest requires 3.12 or newer, and the classifiers claim support for 3.12 through 3.15.
Three different one-line descriptions, and the strongest claim is commented out
A small detail that tells you how this project's story has changed, and it is checkable by reading the file.
There are three descriptions in play. The repository's own description field says it is a game theoretic approach to explain the output of any machine learning model. The README's opening line says the same thing in almost the same words. And the package manifest's description field says it is a unified approach to explain the output of any machine learning model.
So the package metadata on the index still carries the older framing, and the README has moved to a narrower one.
The reason is visible too, because the README keeps the previous sentence in the file, commented out. That earlier version claimed to be a unified approach, said it unites several previous methods, and added that it represents the only possible consistent and locally accurate additive feature attribution method based on expectations.
That is a very strong claim, a uniqueness claim about the entire field, and it has been removed from the live text while the older wording survives in the package metadata and the removed sentence survives as a comment. Removing a claim of uniqueness while keeping the weaker factual claim is a good editorial decision, and the residue of the old wording in the metadata is a small inconsistency that will outlive it.
The live text is now narrower and more precise. It says the approach connects optimal credit allocation with local explanations using the classic Shapley values and their related extensions, and it points to a papers section for detail. That is a description you can defend in a review, and the one in the package index is one you would have to explain.
A runtime dependency is pinned to an exact 0.0.8
The dependency list is short and one entry in it deserves a second look.
The runtime dependencies are a numeric library, a scientific library, a machine learning library, a dataframe library, a progress bar, a packaging helper, a serialisation helper, and one entry with an exact version pin: a package called slicer, pinned to a specific release.
The number is what makes it interesting. A version in the zero series, at the eighth release of the zeroth minor, pinned with no range at all. Every other entry in the list is either a floor or unpinned. So the project has decided that this one dependency must not move.
There are usually only two reasons for a pin like that, and both are worth checking before you install. Either a specific version is the only one that works, in which case a bug fixed in a later release will not reach you, or a later version broke something and the project has not moved off it, in which case you are depending on an abandoned release of a package with no stability guarantee, since a project whose releases are numbered that way has not promised you anything about the next one.
The same applies to a related risk that a version range would at least let you see. A transitive dependency of a zero-version package can pull in whatever its author declares, with none of the compatibility signalling you get from a mature dependency.
None of this means the pin is wrong. It means it is the kind of line in a manifest that deserves a look rather than a glance, and it is the only place in a short, careful dependency list where that is true.
The newest release is a release candidate, and the version comes from git tags
The release history and the version scheme together tell you where this project is in its life.
The most recent release is v0.54.1, published on 2026-10-16. Before that there is v0.53.0 from 2026-10-09 and the release candidate v0.53.0rc0 from 2026-09-07. The last push to the repository was on 2026-10-04 and the repository is not archived.
So the version line is still in the zero series, and development continues. For a library classified in its own metadata as production and stable, staying in the zero series means you are choosing a version by a different convention than semver would give you.
That convention is visible in the manifest. The version is declared dynamic, and the build system uses a version-from-tags tool, so the number you install is derived from the git tag rather than typed into a file. There is no second place for the version to be wrong, which is a real advantage, and it also means a release candidate tag is a normal thing to encounter rather than a special one.
The repository also tells you what the maintainers care about keeping honest. There is a file configuring an open-source benchmarking harness, which is how a numerical library tracks whether a change made it slower. There is a directory for monitoring, and a directory of notebooks, and a directory for a JavaScript component in a Python project, which is consistent with the batched force plot being described in the documentation as interactive. There is a configuration for automated formatting and one for ignoring bulk commits in version-control blame.
A benchmark harness in a library whose selling point is exactness is the right thing to find, because the exactness is a performance claim as much as a correctness one.
Editorial conclusion
SHAP fits a team explaining a model it has to defend, where an additive attribution with a stated theoretical basis is worth more than a feature importance ranking. It does not fit a setting where the attribution has to be exact, because the deep learning path is explicitly an approximation and the approximations are tuned for speed. Verify first which algorithm your Explainer actually selected, since the constructor looks the same either way and the difference is between an exact and an approximate answer, and confirm on your own data that the values are stable before a single one goes in front of anyone who is not a modeller.
Frequently asked questions
what is shap shapley additive explanations
SHAP stands for SHapley Additive exPlanations and is a game theoretic approach to explaining the output of a machine learning model. It connects optimal credit allocation with local explanations using the classic Shapley values and their related extensions, and it computes a value per feature describing how much that feature pushed a prediction up or down from an average baseline.
what does shap stand for
It stands for SHapley Additive exPlanations, named after the Shapley values it applies from cooperative game theory. The package is distributed simply as shap.
what is shap
It is an MIT licensed Python library, installable from a package index or a conda channel, that explains machine learning model output with Shapley values. The current API is a single Explainer constructor that dispatches on the model type, with plot helpers for waterfall, force, scatter, beeswarm and bar views of the same explanation.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/shap-shap)Star history chart for your README
[](https://hysenlabs.com/projects/shap-shap)Was this useful?