Skip to content

v1.7.0 (2026-08-27)

Choose a tag to compare

@mmschlk mmschlk released this 27 Aug 11:45
· 84 commits to main since this release
827d695

v1.7.0 (2026-08-27)

New and Improved Tree support.

This release focuses on a greatly improved support of tree-based models as provided by sklearn, XGBoost, LightGBM, or CatBoost.

TreeExplainer remains the single entry point for explaining tree-based models and routes to the fastest available algorithms.
With this release, tree explanations are numerically stable at any tree depth and substantially faster on all kinds of trees, in both pathdependent and interventional mode.
In mode="pathdependent", explanations are now computed by the new QuadratureTreeSHAP algorithm, which replaces the polynomial algorithms LinearTreeSHAP and TreeSHAPIQ as the default.
In mode="interventional", smaller inputs are computed by InterventionalTreeSHAPIQ and larger inputs route to the new vectorized Woodelf fast path.
All four algorithms share a common interface and can also be used directly, independently of TreeExplainer.

Woodelf-IQ integration #572

Together with Ron Wettenstein, we add a Woodelf fast path to shapiq.tree.TreeExplainer (Nadel and Wettenstein, 2026; Wettenstein et al., 2026).
Woodelf is very fast. It computes explanations fully vectorized over all explained instances and reference rows scaling much more favorably with large explanation points or reference data than existing algorithms.
It is also not limited to Shapley values and also computes interaction indices "SII" and "k-SII" and Banzhaf values "BV" "BII".
TreeExplainer.explain_X explains all instances in one vectorized run and returns the new InteractionValuesBatch: a lazy sequence of one InteractionValues per instance whose .values attribute exposes the raw vectorized arrays (Explainer.explain_X is now typed as returning a Sequence[InteractionValues]).
The fast path requires the new optional tree dependency group (pip install shapiq[tree] — woodelf-explainer); without it, the explainer falls back to the shapiq implementation with a WoodelfNotAvailableWarning.
The new backend parameter ("auto", "woodelf", "shapiq") overrides the automatic routing, whose cut-off between the two backends was benchmarked and set to n * m >= 100_000 (n explained instances × m reference rows) #591.

image

QuadratureSHAP #588

We add QuadratureTreeSHAP in shapiq.tree.quadrature as the default path-dependent algorithm of TreeExplainer, computing all supported indices ("SV", "SII", "k-SII", "BV", "BII") at any order natively replacing LinearTreeSHAP and TreeSHAPIQ.
QuadratureTreeSHAP is a new efficient pathdependent TreeSHAP algorithm (Wettenstein et al., 2026; Li et al., 2026) computing Shapley values and any-order Shapley interactions ("SV", "SII", "k-SII") as well as the Banzhaf indices ("BV"/"BII") numerically exact in float64 at any tree depth and any number of features per decision path.
This resolves the numerical instability of the existing polynomial algorithms which started at around 28 unique features per path #545.
QuadratureTreeSHAP is implemented with a C++ kernel that benchmarks substantially faster than the existing explainers at every measured setting.
We see about 2× improvements vs LinearTreeSHAP, which is the fastest algorithm for Shapley values and 100×+ vs TreeSHAPIQ for interactions.
We can compute order-4 interactions in milliseconds.
Ensembles are computed in a single batched C++ kernel invocation over a shared feature space, which benchmarks at parity with XGBoost's native pred_contribs TreeSHAP on a single thread.

image image

New LeverageSHAP Approximator #524, #583

Adds the LeverageSHAP approximator in shapiq.approximator.regression for Shapley value estimation via leverage score sampling (Musco and Witter, 2025).
LeverageSHAP is the modernized variant of KernelSHAP and should be used as a direct replacement improving sample-efficiency without additional costs.
The implementation follows the paper's released implementation: a functional pairing_trick, deterministic per-size sample counts (deterministic_counts=True by default), and exact budget accounting #583.

Additional new Features

  • adds support of any-order BII and STII to ProxySHAP (in addition to SV, BV, SII, k-SII, FSII, and FBII). ProxySHAP is registered for both indices wherever setup_approximator resolves the "proxyshap" string. MoebiusConverter gained the matching BII conversion, and computes BV through it. #587
  • adds a k_folds parameter to ProxySHAP and RegressionMSR for out-of-fold proxy residuals, i.e. the cross-fitting variant of Witter et al. (2025). The default k_folds=1 fits a single proxy on all sampled coalitions, which the paper recommends in practice. #587
  • aligns RegressionMSR more with the theory of the paper by adding sampling weights for the RegressionMSR estimator which are coherent to the papers proposed sampling Witter et al. (2025). #587
  • adds TreeExplainer support for scikit-learn gradient boosting models: GradientBoostingRegressor, GradientBoostingClassifier, HistGradientBoostingRegressor, and HistGradientBoostingClassifier can now be converted to the internal tree format. #577
  • adds categorical split support to the tree explainers: models trained with native categorical features -- sklearn HistGradientBoosting* (categorical_features), LightGBM (categorical_feature), and XGBoost (enable_categorical) -- are now converted and explained exactly on all paths (TreeSHAP-IQ, LinearTreeSHAP, Interventional TreeSHAP-IQ, and QuadratureSHAP). TreeModel stores per-node category sets in a CSR layout (cat_values/cat_start/cat_size) with the unified routing rule "category in set → left child, NaN → missing child". #577
  • adds the ConfoundingSHAP local and global explanation game in shapiq_games.benchmark.causal_xai for the first causal machine learning based value functions (Brockschmidt et al., 2026) based on the paper. #551

Breaking Changes

  • renames InterventionalTreeExplainer to InterventionalTreeSHAPIQ in shapiq.tree.interventional for consistency with TreeSHAPIQ, LinearTreeSHAP, and the newly added QuadratureSHAP. The old name is no longer available; import shapiq.tree.InterventionalTreeSHAPIQ instead. #580
  • turns ProxySHAP's adjustment parameter into a boolean (default False; RegressionMSR always applies it). The residual correction is now a built-in closed-form MSR routine rather than a second approximator, so the "svarm" and "kernel" variants are no longer available. random_state=None is also no longer silently replaced by a fixed seed, which the single shared coalition sampler makes unnecessary. #587
  • changes RegressionMSR's default sampling_weights to the closed-form kernel of Witter et al. (2025), including their separate Leverage-SHAP kernel for linear proxies with index="SV". Passing sampling_weights explicitly still overrides the default. #587

Bugfix

  • fixes wrong explanations for XGBoost and CatBoost models on instances whose float64 feature values round across a split threshold in float32: both libraries cast prediction inputs to float32 before routing, which the converted trees now reproduce via TreeModel.input_precision/cast_input (LightGBM compares in float64 and is untouched; sklearn's thresholds are exact midpoints of adjacent float32 values, making its internal cast unobservable). Previously all tree explainers could explain a different leaf than the model actually predicts — on measured XGBoost hist models roughly half the instances routed differently somewhere in the ensemble #588
  • fixes silently permuted attributions for trees whose feature-id set iterates in non-ascending order (e.g. features {6, 14}): reduce_feature_complexity assigned reduced ids in raw set iteration order while the returned interaction_lookup sorts players, pairing values with the wrong features in TreeSHAPIQ. #588
  • fixes a bug with categorical LightGBM/XGBoost models, which were silently mis-parsed (bitset indices read as numeric thresholds), producing wrong explanations without any error #577
  • fixes missing-value (NaN) routing in the LinearTreeSHAP and interventional C++ kernels: -ffast-math had compiled away the std::isnan checks (now built with -fno-finite-math-only), and TreeSHAP-IQ now routes NaN values through the per-node missing direction exactly like predict_one #577
  • removes the stale and broken STII/FSII/BII code path from the path-dependent TreeSHAPIQ algorithm, which crashed with broadcasting errors on wider trees. TreeSHAPIQ now raises a clear ValueError for indices other than SV, SII, and k-SII. #571 #575
  • removes KernelSHAPIQ and InconsistentKernelSHAPIQ from the STII_APPROXIMATORS and FSII_APPROXIMATORS registries in shapiq.approximator, since both only support the SV, SII, and k-SII indices #571 #575
  • fixes the BV index losing estimated and estimation_budget when interactions are read out of a linear proxy: MoebiusConverter now computes BV through the base-interaction routine (as it already did for SV) instead of the faithful-index routine, which did not carry those fields through. #587

Maintenance

  • adds numerical precision guards to the polynomial tree explainers: LinearTreeSHAP and TreeSHAPIQ now emit a TreeNumericalPrecisionWarning from 24 distinct features per decision path (they become numerically unstable there) and raise a TreeNumericalPrecisionError from 30 (unreliable values), instead of silently returning wrong attributions or crashing with an unexplained LinAlgError #545. #588
  • rewrites ProxySHAP's MSR residual adjustment as a self-contained vectorized routine that estimates all interactions in a single matrix product over the coalitions already sampled, instead of re-sampling an independent CoalitionSampler and running a second Monte Carlo pass on a residual game. #587
  • removes the dead non-log weight computations from the approximator base classes, which were superseded by their log-space counterparts: Regression._init_kernel_weights (superseded by _init_log_kernel_weights) and the MonteCarlo family _get_standard_form_weights/_weight/_sii_weight/_bii_weight/_chii_weight/_stii_weight/_fsii_weight/_fbii_weight (superseded by _get_standard_form_log_weights and the _log_*_weight methods). #578
  • vectorizes the k-SII aggregation (aggregate_base_attributions): all subset projections and Bernoulli weightings are built as array operations and summed per subset via integer-coded bincount, ~12–27× faster than the previous per-subset dict loop. #590
  • KNNExplainer, WeightedKNNExplainer, and their ground-truth games now raise a ValueError at construction when the model was fitted on fewer training samples than n_neighbors, mirroring scikit-learn's own "Expected n_neighbors <= n_samples_fit" error on predict. Previously, KNNExplainer silently returned Shapley values that disagreed with KNNExplainerGame in this regime #582
  • moves the hot paths of InterventionalTreeSHAPIQ for non-boolean trees to C++, for a ~263× end-to-end speedup: a fused dense kernel (compute_interactions_cohort) replaces the per-explanation Python E/R preprocessing with one DFS per tree that shares the walk across all reference samples, and the interventional baseline_value now routes the reference data through a C++ ensemble-prediction kernel (predict_ensemble_sum) instead of a Python per-(row, tree) loop (up to ~500× on large backgrounds). #590
  • harmonizes the tree computation algorithms: LinearTreeSHAP, TreeSHAPIQ, QuadratureTreeSHAP, and InterventionalTreeSHAPIQ now all validate their own models, accept ensembles as well as single trees (aggregating internally), take a class_index argument, and expose a common explain(x) entry point — each algorithm can be used independently of TreeExplainer, which now simply instantiates one explainer per mode. Note that TreeExplainer is still the intended access points for users. Their modules are named computer (shapiq.tree.linear.computer, shapiq.tree.quadrature.computer, shapiq.tree.interventional.computer), keeping shapiq.tree.explainer unambiguous as the user-facing TreeExplainer entry point. #588
  • the interventional TreeSHAP-IQ C kernels now compute in float64 (previously float32 inputs, thresholds, and accumulation on the dense path); the three unused kernel entry points (compute_interactions, compute_interactions_batched, compute_interactions_sparse) were removed #588

New Contributors

Full Changelog: v1.6.0...v1.7.0