Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
328cf41
PolySHAP file integration
May 3, 2026
520fd58
test: add cross-approximator conformance + convergence test scaffold
42logos May 11, 2026
6d4d29f
test: extend conformance harness to ALL SV approximators
42logos May 11, 2026
e017f78
PolySHAPKAdd, PolySHAPPartial, PolySHAPPrior
May 11, 2026
df4958f
docstring: removed ref to removed para
May 11, 2026
20229f6
feat(benchmark): cross-method performance harness for SV approximators
42logos May 20, 2026
6bede21
feat/gitignore: Add benchmark/results/* to .gitignore
FabianK-Dev May 25, 2026
79ae357
PolySHAP unit tests
May 26, 2026
a7d3165
PolySHAP docstrings; underdefined problem warning
May 26, 2026
bd30983
PolySHAP removed time measurements; fixed docstring
May 26, 2026
f0f5898
Cross-Method Performance Benchmark into PolySHAP
May 26, 2026
a8a76b5
PolySHAP benchmark discovery
May 26, 2026
d507ba6
PolySHAP: removed efficient_sampling.py
Jun 9, 2026
23311c4
PolySHAP seeded unit tests
Jun 23, 2026
da4f1e9
PolySHAP paper reproduction notebook
Jun 23, 2026
b0aa326
FIX PolySHAP interaction values
Jun 23, 2026
6e1f5b4
PolySHAP maxorder showcase notebook
Jun 23, 2026
149bf27
PolySHAPPrior excluded from benchmarking
Jun 23, 2026
f7db098
PolySHAP bib-reference and mini-demo
Jun 25, 2026
875a9c6
Merge branch 'main' into polyshap
Jun 25, 2026
8083528
PolySHAP changelog entry
Jun 25, 2026
83942ef
PolySHAP lint fixes
Jun 30, 2026
435f4a9
PolySHAP removal of additional benchmark and notebooks
Jun 30, 2026
a86d8c2
Merge branch 'main' into PolySHAP
ThrashLion Jun 30, 2026
9d47b72
PolySHAP OddSHAP Fumagalli bib references
Jul 4, 2026
f621c15
Merge branch 'main' into PolySHAP
ThrashLion Jul 4, 2026
41f49cd
PolySHAP make overrides ty-compatible
Jul 7, 2026
c4f9c90
Merge branch 'main' into PolySHAP
ThrashLion Jul 7, 2026
5764ff7
PolySHAP unified class; improved unit tests
Jul 16, 2026
4989032
PolySHAP docstring: unbounded max_order
Jul 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ illustration_sources/
src/shapiq_games/datasets/data/tabarena_*.csv

shapiq/games/benchmark/precomputed/
benchmark/results/*
precomputed.zip
game_storage/*

Expand All @@ -189,6 +190,7 @@ src/shapiq/_version.py

# Claude
.claude/
.claude

# C-Extension files
*.so
Expand All @@ -199,5 +201,8 @@ docs/source/sg_execution_times.rst
docs/source/generated/
docs/source/gen_modules/

# Cache
cache/

# Local debug / scratch scripts (not public)
scripts/
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

### New Features

- adds the `PolySHAP` approximator in `shapiq.approximator.regression` for Shapley value estimation via interaction-informed polynomial regression (PolySHAP, [Fumagalli et al., ICLR 2026](https://arxiv.org/abs/2601.18608)). PolySHAP generalizes `KernelSHAP` by fitting a *k*-additive polynomial surrogate of the game before reading off the Shapley values. The interaction frontier can be the full *k*-additive frontier up to `max_order` (with `max_order=1` recovering `KernelSHAP`), a budget-controlled partial frontier (`max_terms`), or a user-supplied set of interaction terms (`prior_frontier`). Registered as a Shapley-value (`SV`) approximator.

## v1.6.0 (2026-07-06)

### Highlights of new Features
Expand Down
7 changes: 7 additions & 0 deletions docs/source/references.bib
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ @article{Fumagalli.2026
eprinttype = {arXiv},
eprint = {2602.01399}
}
@inproceedings{Fumagalli.2026a,
title = {{PolySHAP}: Extending {KernelSHAP} with Interaction-Informed Polynomial Regression},
author = {Fabian Fumagalli and R. Teal Witter and Christopher Musco},
year = {2026},
booktitle = {The Fourteenth International Conference on Learning Representations ({ICLR} 2026)},
url = {https://arxiv.org/abs/2601.18608}
}
@inproceedings{Harris.2022,
title = {Joint Shapley values: a measure of joint feature importance},
author = {Chris Harris and Richard Pymar and Colin Rowat},
Expand Down
76 changes: 76 additions & 0 deletions examples/approximators/plot_polyshap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
"""
PolySHAP
========

Shapley value approximation with interaction-informed polynomial regression
using :class:`~shapiq.approximator.PolySHAP` :footcite:t:`Fumagalli.2026a`.

PolySHAP extends KernelSHAP by fitting a *k-additive* surrogate of the game -- a
polynomial of degree ``max_order`` over the players -- and reading the Shapley
values off that surrogate. ``max_order=1`` reduces to plain KernelSHAP, while
higher orders capture interactions explicitly. When the game's interactions do
not exceed ``max_order``, PolySHAP recovers the exact Shapley values.
"""

from __future__ import annotations

import numpy as np

import shapiq
from shapiq.approximator import PolySHAP

N_PLAYERS = 8
BUDGET = 200
feature_names = [f"x{i}" for i in range(N_PLAYERS)]

weights = np.array([0.4, 0.3, 0.2, 0.1, 0.05, -0.1, -0.2, -0.3])


def game_fun(coalitions: np.ndarray) -> np.ndarray:
# A linear game plus a single pairwise interaction between x0 and x1.
# This game is exactly 2-additive: its interactions never exceed order 2.
coalitions = np.atleast_2d(coalitions)
return (coalitions @ weights) + 0.5 * coalitions[:, 0] * coalitions[:, 1]


# %%
# Approximate Shapley values
# --------------------------
# The game has a pairwise interaction, so we fit a second-order (``max_order=2``)
# polynomial surrogate to recover the Shapley values.

approximator = PolySHAP(n=N_PLAYERS, max_order=2, random_state=42)
iv = approximator.approximate(BUDGET, game_fun)
print(iv)

# %%
# Force plot
# ----------

iv.plot_force(feature_names=feature_names)

# %%
# Higher order improves accuracy
# ------------------------------
# Because the game is exactly 2-additive, raising ``max_order`` to match its
# interaction order recovers the exact Shapley values, whereas ``max_order=1``
# (equivalent to KernelSHAP) leaves a visible approximation error. We compare
# both against the exact Shapley values from :class:`~shapiq.ExactComputer`.

exact = np.asarray(
shapiq.ExactComputer(game_fun, n_players=N_PLAYERS)(index="SV", order=1).get_n_order_values(1)
)

for max_order in (1, 2):
est = np.asarray(
PolySHAP(n=N_PLAYERS, max_order=max_order, random_state=42)
.approximate(BUDGET, game_fun)
.get_n_order_values(1)
)
mse = float(np.mean((est - exact) ** 2))
print(f"max_order={max_order}: MSE vs. exact Shapley = {mse:.2e}")

# %%
# References
# ----------
# .. footbibliography::
3 changes: 3 additions & 0 deletions src/shapiq/approximator/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
KernelSHAP,
KernelSHAPIQ,
OddSHAP,
PolySHAP,
RegressionFBII,
RegressionFSII,
kADDSHAP,
Expand Down Expand Up @@ -64,6 +65,7 @@ def __init__(self, *_args: object, **_kwargs: object) -> None:
ProxySPEX,
OddSHAP,
ShaplEIG,
PolySHAP,
]

# contains all SI approximators
Expand Down Expand Up @@ -149,4 +151,5 @@ def __init__(self, *_args: object, **_kwargs: object) -> None:
"STII_APPROXIMATORS",
"FSII_APPROXIMATORS",
"FBII_APPROXIMATORS",
"PolySHAP",
]
2 changes: 2 additions & 0 deletions src/shapiq/approximator/regression/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from .kernelshap import KernelSHAP
from .kernelshapiq import InconsistentKernelSHAPIQ, KernelSHAPIQ
from .oddshap import OddSHAP
from .polyshap import PolySHAP

__all__ = [
"kADDSHAP",
Expand All @@ -15,5 +16,6 @@
"InconsistentKernelSHAPIQ",
"Regression",
"RegressionFBII",
"PolySHAP",
"OddSHAP",
]
Loading