Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
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
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
2447992
leverageSHAP sceleton
May 3, 2026
67400f8
feat/SG-20/leverageshap: Add budget validation, initialize seen_coali…
FabianK-Dev May 6, 2026
80f4248
feat/SG-20/leverageshap: Add leverage score sampling loop
FabianK-Dev May 6, 2026
f02e5ed
feat/SG-20/leverageshap: Run uv run pre-commit run --all-files and fi…
FabianK-Dev May 6, 2026
e4d2ff6
feat/SG-20/leverageshap: Add comments to document and explain code
FabianK-Dev May 6, 2026
0f8a940
implementation of _solver function + first tests
Naxsos May 8, 2026
6a1bb98
feat/SG-20/leverageshap: Add reference for Lemma 3.2
FabianK-Dev May 11, 2026
44ba153
feat/SG-22/testing: Add basic test_reproducibility test => Tests for …
FabianK-Dev May 11, 2026
bfa15ee
feat/SG-22/testing: Improve test_reproducibility(): Split up into dif…
FabianK-Dev May 11, 2026
aecacdf
feat/SG-22/testing: Test whether different seeds of identical dummy g…
FabianK-Dev May 11, 2026
109d14a
feat/SG-22/testing: Test whether approximation error decreases with i…
FabianK-Dev May 11, 2026
2fbabae
feat/SG-22/testing: Add comments to make test more understandable
FabianK-Dev May 12, 2026
030aa00
Fix: DRY principle applied
May 15, 2026
1337b00
fix: solve_regression for rank-deficient matrices
Naxsos May 19, 2026
30acd7b
feat/SG-22/testing: Add tests for exact matches with ExactComputer an…
FabianK-Dev May 22, 2026
8e4e5a0
feat/SG-22/testing: removed test_reproducibility_different_seeds beca…
FabianK-Dev May 22, 2026
058e5d7
feat/SG-22/testing: Split test_reproducibility_different_seeds up int…
FabianK-Dev May 22, 2026
e09f1f0
feat/SG-22/testing: Add test for pairing trick variance reduction in …
FabianK-Dev May 23, 2026
7267e63
feat/SG-22/testing: Add test_leverageshap_vs_kernelshap_mean_error, t…
FabianK-Dev May 23, 2026
4cb7602
reproduceability test and changes necessary to actually reproduce pap…
Naxsos May 23, 2026
6ff9ad3
feat/SG-22/testing: Update test_empirical_convergence_rate to use hig…
FabianK-Dev May 23, 2026
097de27
feat/gitignore: Add benchmark/results/* to .gitignore
FabianK-Dev May 25, 2026
0d87b9c
feat/Add DISCUSSION.md (WIP)
FabianK-Dev May 25, 2026
a772261
feat/SG-69/refactor: Refactor leverageshap.py to move solve method in…
FabianK-Dev May 30, 2026
3a06f5a
feat/SG-69/refactor: handle NaN/Inf values in regression calculations
FabianK-Dev May 30, 2026
9fed440
feat/SG-22/testing: Add a list of different fixed seeds and evaluate …
FabianK-Dev May 30, 2026
3a48458
feat/SG-22/testing: Fix test by expecting game.access_counter <= 2**n
FabianK-Dev May 30, 2026
bcfc038
additional unit tests
Naxsos Jun 5, 2026
45b0035
chore/leverageshap: remove WIP notebook DISCUSSION.md file and WIP 1-…
FabianK-Dev Jun 8, 2026
fbed1d6
Merge branch 'main' into leverageSHAP
mmschlk Jun 10, 2026
34b9a26
fix: typo in comment: "ovefitting" -> "overfitting"
FabianK-Dev Jun 14, 2026
0be7cf3
fix: Implement suggestions by copilot
FabianK-Dev Jun 16, 2026
b98d617
feat: replace custom data sets with shapiq_games.datasets.load_commun…
FabianK-Dev Jun 17, 2026
ad74f97
ruff: Add ruff changes in seperate commit (i.e. ruff split style chan…
FabianK-Dev Jun 17, 2026
e70f9d6
refactor: Refactor faulty solve_regression() method and remove old un…
FabianK-Dev Jun 17, 2026
67d05fc
ruff: Apply automatic ruff format changes and fix remaining type hint…
FabianK-Dev Jun 17, 2026
c28409b
refactor: simplify IS weight math and optimize solver
FabianK-Dev Jun 17, 2026
e98266a
test: reproduce figure 9 of the paper: compare KernelSHAP, LeverageSH…
FabianK-Dev Jun 18, 2026
cd7c0b6
fix: correct LaTeX formula rendering
FabianK-Dev Jun 23, 2026
e3e4841
feat(benchmark): Extend benchmark with more instances, different data…
FabianK-Dev Jul 3, 2026
a0083f9
docs: Add empirical evaluation of Custom LeverageSHAP vs. Uniform Wei…
FabianK-Dev Jul 3, 2026
6b020e4
feat: remove empirical evaluation comments where I'm unsure (I don't …
FabianK-Dev Jul 3, 2026
49394e6
fix: Remove NBs from current branch and move to branch 'submission' (…
FabianK-Dev Jul 3, 2026
bd6d472
Merge branch 'main' into leverageSHAP
FabianK-Dev Jul 3, 2026
dfd68ce
Merge branch 'main' of github.com:mmschlk/shapiq
FabianK-Dev Jul 3, 2026
598ef5f
Merge branch 'main' into leverageSHAP
FabianK-Dev Jul 3, 2026
079ab89
ruff: auto format
FabianK-Dev Jul 3, 2026
3b40fc1
Revert "Merge remote-tracking branch 'origin/wu/conformance-test' int…
FabianK-Dev Jul 3, 2026
a141ebb
test: add testing to add coverage for remaining code lines
FabianK-Dev Jul 3, 2026
6c4d22a
fix: Fix docstring to ensure sphinx builds
FabianK-Dev Jul 3, 2026
3d81549
Merge branch 'main' into leverageSHAP
mmschlk Jul 6, 2026
23d8de4
refactor: delete solve_regression() re-export and use direct module-l…
FabianK-Dev Jul 6, 2026
52ae4cf
Merge branch 'leverageSHAP' of github.com:FabianK-Dev/shapiq into lev…
FabianK-Dev Jul 6, 2026
4e16c85
docs: Add example usage to LeverageSHAP class docstring
FabianK-Dev Jul 6, 2026
508df24
docs: Enhance _sample method docstring with custom Bernoulli sampling…
FabianK-Dev Jul 6, 2026
ac8bb67
refactor: replace hardcoded magic number bisect iteration limit with …
FabianK-Dev Jul 6, 2026
ae56264
docs: Update comment to clarify use of math.comb for arbitrary-precis…
FabianK-Dev Jul 6, 2026
6fabdd9
refactoring: Adjusted docstrings and other adjustments
Naxsos Jul 12, 2026
adf80d2
fix: Extend exception handling in solve_regression to include ValueError
FabianK-Dev Jul 15, 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
1 change: 1 addition & 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 Down
7 changes: 7 additions & 0 deletions docs/source/references.bib
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ @inproceedings{Witter.2025
year = {2025},
url = {https://openreview.net/forum?id=Qabko39AS5}
}
@inproceedings{Musco.2025,
title = {Provably Accurate Shapley Value Estimation via Leverage Score Sampling},
author = {Christopher Musco and R. Teal Witter},
booktitle = {Proceedings of the International Conference on Learning Representations {(ICLR)}},
year = {2025},
url = {https://arxiv.org/abs/2410.01917}
}
@article{Arya.2020,
title = {{AI} Explainability 360: An Extensible Toolkit for Understanding Data and Machine Learning Models},
author = {Vijay Arya and Rachel K. E. Bellamy and Pin{-}Yu Chen and Amit Dhurandhar and Michael Hind and Samuel C. Hoffman and Stephanie Houde and Q. Vera Liao and Ronny Luss and Aleksandra Mojsilovic and Sami Mourad and Pablo Pedemonte and Ramya Raghavendra and John T. Richards and Prasanna Sattigeri and Karthikeyan Shanmugam and Moninder Singh and Kush R. Varshney and Dennis Wei and Yunfeng Zhang},
Expand Down
2 changes: 2 additions & 0 deletions src/shapiq/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
InconsistentKernelSHAPIQ,
KernelSHAP,
KernelSHAPIQ,
LeverageSHAP,
OddSHAP,
OwenSamplingSV,
PermutationSamplingSII,
Expand Down Expand Up @@ -103,6 +104,7 @@
"StratifiedSamplingSV",
"OwenSamplingSV",
"KernelSHAP",
"LeverageSHAP",
"RegressionFSII",
"RegressionFBII",
"KernelSHAPIQ",
Expand Down
3 changes: 3 additions & 0 deletions src/shapiq/approximator/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
InconsistentKernelSHAPIQ,
KernelSHAP,
KernelSHAPIQ,
LeverageSHAP,
OddSHAP,
RegressionFBII,
RegressionFSII,
Expand Down Expand Up @@ -58,6 +59,7 @@ def __init__(self, *_args: object, **_kwargs: object) -> None:
UnbiasedKernelSHAP,
PermutationSamplingSV,
KernelSHAP,
LeverageSHAP,
kADDSHAP,
SPEX,
RegressionMSR,
Expand Down Expand Up @@ -128,6 +130,7 @@ def __init__(self, *_args: object, **_kwargs: object) -> None:
"StratifiedSamplingSV",
"OwenSamplingSV",
"KernelSHAP",
"LeverageSHAP",
"RegressionFSII",
"RegressionFBII",
"KernelSHAPIQ",
Expand Down
2 changes: 2 additions & 0 deletions src/shapiq/approximator/regression/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from .kadd_shap import kADDSHAP
from .kernelshap import KernelSHAP
from .kernelshapiq import InconsistentKernelSHAPIQ, KernelSHAPIQ
from .leverageshap import LeverageSHAP
from .oddshap import OddSHAP

__all__ = [
Expand All @@ -13,6 +14,7 @@
"KernelSHAP",
"KernelSHAPIQ",
"InconsistentKernelSHAPIQ",
"LeverageSHAP",
"Regression",
"RegressionFBII",
"OddSHAP",
Expand Down
46 changes: 31 additions & 15 deletions src/shapiq/approximator/regression/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ def kernel_shap_iq_routine(
X=regression_matrix,
y=residual_game_values[interaction_size],
kernel_weights=regression_weights,
use_svd=False,
)
else:
# for order > 2 use ground truth weights for sizes < interaction_size and > n -
Expand All @@ -314,6 +315,7 @@ def kernel_shap_iq_routine(
X=regression_matrix,
y=game_values_plus,
kernel_weights=regression_weights,
use_svd=False,
)

sii_values_current_size = (
Expand Down Expand Up @@ -372,6 +374,7 @@ def regression_routine(
X=regression_matrix,
y=regression_response,
kernel_weights=regression_weights,
use_svd=False,
)

if index_approximation in ["kADD-SHAP", "FBII"]:
Expand Down Expand Up @@ -638,31 +641,44 @@ def _get_regression_matrices(
return regression_matrix, regression_weights


def solve_regression(X: np.ndarray, y: np.ndarray, kernel_weights: FloatVector) -> np.ndarray:
"""Solves the Shapley regression problem.
def solve_regression(
X: np.ndarray,
y: np.ndarray,
kernel_weights: FloatVector,
*,
use_svd: bool = False,
) -> np.ndarray:
"""Solves the Shapley regression problem using weighted least squares (WLS).

Solves the regression problem using the weighted least squares method. Returns all approximated
interactions.
By default, this attempts a fast solution using the normal equations. If the
Gram matrix is singular or ill-conditioned, it falls back to a robust
Singular Value Decomposition (SVD) solver.

Args:
X: The regression matrix of shape ``[n_coalitions, n_interactions]``.
y: The response vector for each coalition of shape ``[n_coalitions]``.
kernel_weights: The weights for the regression problem for each coalition.
kernel_weights: The weights for the regression problem of shape ``[n_coalitions]``.
use_svd: If ``True``, skips the fast normal equation solver and directly uses
the robust SVD-based least squares solver (``np.linalg.lstsq``). Useful
for cases with extreme weight initializations or known rank-deficiencies.

Returns:
The solution to the regression problem.

The approximated interaction values of shape ``[n_interactions]``.
"""
# Explicit override: go straight to the robust, SVD-backed solver
if use_svd:
W_sqrt = np.sqrt(kernel_weights)
return np.linalg.lstsq(W_sqrt[:, np.newaxis] * X, W_sqrt * y, rcond=None)[0]

# Standard fast path (try the fast way, catch the error if it fails)
try:
# try solving via solve function
WX = kernel_weights[:, np.newaxis] * X
with warnings.catch_warnings():
warnings.simplefilter("ignore", category=RuntimeWarning)
phi = np.linalg.solve(X.T @ WX, WX.T @ y)
except np.linalg.LinAlgError:
# solve WLSQ via lstsq function and throw warning
# Solves (X^T * W * X) * phi = X^T * W * y
return np.linalg.solve(X.T @ WX, WX.T @ y)

except (np.linalg.LinAlgError, ValueError):
# Fallback: Gram matrix is singular. Use robust SVD approach.
W_sqrt = np.sqrt(kernel_weights)
X = W_sqrt[:, np.newaxis] * X
y = W_sqrt * y
phi = np.linalg.lstsq(X, y, rcond=None)[0]
return phi
return np.linalg.lstsq(W_sqrt[:, np.newaxis] * X, W_sqrt * y, rcond=None)[0]
Loading