ENH: Performance monitoring for explainers (#5071)

* Init asv

Co-authored-by: Zhihao Dai <zhihao.dai@eng.ox.ac.uk>

* Add exact explainer suite

Co-authored-by: Zhihao Dai <zhihao.dai@eng.ox.ac.uk>

* Add partition explainer suite

Co-authored-by: Zhihao Dai <zhihao.dai@eng.ox.ac.uk>

* Add permutation explainer suite

Co-authored-by: Zhihao Dai <zhihao.dai@eng.ox.ac.uk>

* Clear out init py

Co-authored-by: Zhihao Dai <zhihao.dai@eng.ox.ac.uk>

* Remove basic suite

Co-authored-by: Zhihao Dai <zhihao.dai@eng.ox.ac.uk>

---------

Co-authored-by: Tobias Pitters <31857876+CloseChoice@users.noreply.github.com>
This commit is contained in:
Zhihao Dai
2026-07-14 20:49:23 +01:00
committed by GitHub
parent 8c056b9098
commit 846f28c79a
7 changed files with 141 additions and 0 deletions
+4
View File
@@ -47,3 +47,7 @@ uv.lock
# Auto-generated by nanobind_add_stub
*.pyi
# Performance monitoring using asv
monitoring/html/
monitoring/results/
+21
View File
@@ -0,0 +1,21 @@
{
"version": 1,
"project": "shap",
"project_url": "https://github.com/shap/shap",
"repo": ".",
"branches": ["master"],
"environment_type": "uv",
"build_command": [
"python -m build --wheel --outdir {build_cache_dir} {build_dir}"
],
"matrix": {
"req": {
"xgboost": []
}
},
"show_commit_url": "https://github.com/shap/shap/commit/",
"pythons": ["3.13"],
"benchmark_dir": "monitoring",
"html_dir": "monitoring/html",
"results_dir": "monitoring/results"
}
View File
+43
View File
@@ -0,0 +1,43 @@
from xgboost import XGBClassifier
from shap.datasets import adult
from shap.explainers import ExactExplainer
from shap.maskers import Partition
class ExactSuite:
# Adapted from tests/explainers/test_exact.py
max_samples = 100
def setup(self):
self.model = XGBClassifier(tree_method="exact", base_score=0.5)
# get a dataset on income prediction
self.X, self.y = adult()
if self.max_samples is not None:
self.X = self.X.iloc[: self.max_samples]
self.y = self.y[: self.max_samples]
self.X = self.X.values
# fit the model on the data
self.model.fit(self.X, self.y)
def time_single_output(self):
ex = ExactExplainer(self.model.predict, self.X)
_ = ex(self.X)
def time_multi_output(self):
ex = ExactExplainer(self.model.predict_proba, self.X)
_ = ex(self.X)
def time_interactions(self):
ex = ExactExplainer(self.model.predict, self.X)
_ = ex(self.X, interactions=True)
def time_single_output_partition_masker(self):
ex = ExactExplainer(self.model.predict, masker=Partition(self.X))
_ = ex(self.X)
def time_multi_output_partition_masker(self):
ex = ExactExplainer(self.model.predict_proba, masker=Partition(self.X))
_ = ex(self.X)
+32
View File
@@ -0,0 +1,32 @@
from xgboost import XGBClassifier
from shap.datasets import adult
from shap.explainers import PartitionExplainer
class PartitionSuite:
# Adapted from tests/explainers/test_partition.py
# TODO: should we add translation tests here too?
# This would introduce a dependency on torch and transformers.
max_samples = 100
def setup(self):
self.model = XGBClassifier(tree_method="exact", base_score=0.5)
# get a dataset on income prediction
self.X, self.y = adult()
if self.max_samples is not None:
self.X = self.X.iloc[: self.max_samples]
self.y = self.y[: self.max_samples]
self.X = self.X.values
# fit the model on the data
self.model.fit(self.X, self.y)
def time_single_output(self):
ex = PartitionExplainer(self.model.predict, self.X)
_ = ex(self.X)
def time_multi_output(self):
ex = PartitionExplainer(self.model.predict_proba, self.X)
_ = ex(self.X)
+39
View File
@@ -0,0 +1,39 @@
from xgboost import XGBClassifier
from shap.datasets import adult
from shap.explainers import PermutationExplainer
from shap.maskers import Partition
class PermutationSuite:
# Adapted from tests/explainers/test_permutation.py
max_samples = 100
def setup(self):
self.model = XGBClassifier(tree_method="exact", base_score=0.5)
# get a dataset on income prediction
self.X, self.y = adult()
if self.max_samples is not None:
self.X = self.X.iloc[: self.max_samples]
self.y = self.y[: self.max_samples]
self.X = self.X.values
# fit the model on the data
self.model.fit(self.X, self.y)
def time_single_output(self):
ex = PermutationExplainer(self.model.predict, self.X)
_ = ex(self.X)
def time_multi_output(self):
ex = PermutationExplainer(self.model.predict_proba, self.X)
_ = ex(self.X)
def time_single_output_partition_masker(self):
ex = PermutationExplainer(self.model.predict, masker=Partition(self.X))
_ = ex(self.X)
def time_multi_output_partition_masker(self):
ex = PermutationExplainer(self.model.predict_proba, masker=Partition(self.X))
_ = ex(self.X)
+2
View File
@@ -102,6 +102,8 @@ test = [
# that were removed in scikit-learn 1.9. See https://github.com/uber/causalml/issues/926
"scikit-learn<1.9",
"selenium", # needed to test the javascript based plots
# performance monitoring for time-critical explainers
"asv",
]
nbtest = [
"jupyter",