shapiq 1.2.0__tar.gz → 1.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. {shapiq-1.2.0 → shapiq-1.2.2}/CHANGELOG.md +11 -1
  2. {shapiq-1.2.0/shapiq.egg-info → shapiq-1.2.2}/PKG-INFO +16 -5
  3. {shapiq-1.2.0 → shapiq-1.2.2}/README.md +2 -1
  4. {shapiq-1.2.0 → shapiq-1.2.2}/pyproject.toml +2 -2
  5. {shapiq-1.2.0 → shapiq-1.2.2}/setup.py +2 -2
  6. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/__init__.py +1 -1
  7. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/approximator/_base.py +9 -9
  8. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/approximator/marginals/owen.py +2 -2
  9. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/approximator/marginals/stratified.py +2 -2
  10. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/approximator/montecarlo/_base.py +2 -2
  11. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/approximator/montecarlo/shapiq.py +5 -6
  12. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/approximator/montecarlo/svarmiq.py +5 -6
  13. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/approximator/permutation/sii.py +3 -3
  14. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/approximator/permutation/stii.py +2 -2
  15. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/approximator/permutation/sv.py +3 -7
  16. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/approximator/regression/_base.py +3 -3
  17. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/approximator/regression/fsi.py +2 -4
  18. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/approximator/regression/kadd_shap.py +2 -4
  19. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/approximator/regression/kernelshap.py +3 -4
  20. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/approximator/regression/kernelshapiq.py +4 -6
  21. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/approximator/sampling.py +12 -15
  22. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/benchmark/configuration.py +2 -2
  23. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/benchmark/load.py +3 -3
  24. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/benchmark/metrics.py +1 -2
  25. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/benchmark/plot.py +8 -8
  26. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/benchmark/precompute.py +8 -8
  27. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/benchmark/run.py +20 -24
  28. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/datasets/_all.py +9 -5
  29. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/explainer/_base.py +3 -3
  30. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/explainer/tabpfn.py +15 -6
  31. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/explainer/tabular.py +13 -6
  32. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/explainer/tree/base.py +12 -12
  33. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/explainer/tree/conversion/lightgbm.py +25 -35
  34. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/explainer/tree/conversion/sklearn.py +2 -4
  35. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/explainer/tree/conversion/xgboost.py +23 -31
  36. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/explainer/tree/explainer.py +4 -4
  37. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/explainer/tree/treeshapiq.py +10 -4
  38. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/explainer/tree/validation.py +6 -4
  39. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/explainer/utils.py +6 -3
  40. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/game_theory/aggregation.py +1 -2
  41. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/game_theory/core.py +1 -2
  42. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/game_theory/exact.py +5 -5
  43. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/game_theory/moebius_converter.py +2 -2
  44. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/base.py +19 -20
  45. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/data_valuation/base.py +2 -2
  46. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/data_valuation/benchmark.py +3 -5
  47. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/dataset_valuation/base.py +10 -10
  48. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/dataset_valuation/benchmark.py +6 -8
  49. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/ensemble_selection/base.py +6 -6
  50. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/ensemble_selection/benchmark.py +6 -8
  51. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/ensemble_selection/benchmark_random_forest.py +3 -5
  52. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/feature_selection/base.py +5 -4
  53. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/feature_selection/benchmark.py +3 -5
  54. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/global_xai/base.py +2 -2
  55. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/global_xai/benchmark_tabular.py +3 -5
  56. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/local_xai/base.py +4 -4
  57. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/local_xai/benchmark_image.py +1 -2
  58. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/local_xai/benchmark_tabular.py +7 -9
  59. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/setup.py +5 -6
  60. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/synthetic/dummy.py +1 -3
  61. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/synthetic/soum.py +5 -7
  62. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/treeshapiq_xai/base.py +1 -2
  63. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/treeshapiq_xai/benchmark.py +8 -10
  64. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/uncertainty/base.py +2 -4
  65. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/uncertainty/benchmark.py +2 -4
  66. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/unsupervised_cluster/base.py +4 -6
  67. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/unsupervised_cluster/benchmark.py +3 -5
  68. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/imputer/base.py +4 -5
  69. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/imputer/baseline_imputer.py +2 -3
  70. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/imputer/conditional_imputer.py +3 -4
  71. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/imputer/marginal_imputer.py +3 -4
  72. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/imputer/tabpfn_imputer.py +4 -4
  73. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/interaction_values.py +34 -20
  74. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/plot/bar.py +16 -10
  75. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/plot/force.py +5 -6
  76. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/plot/network.py +13 -13
  77. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/plot/sentence.py +3 -4
  78. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/plot/si_graph.py +12 -15
  79. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/plot/stacked_bar.py +6 -6
  80. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/plot/upset.py +2 -3
  81. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/plot/utils.py +1 -2
  82. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/plot/watefall.py +3 -5
  83. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/utils/datasets.py +1 -3
  84. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/utils/modules.py +2 -2
  85. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/utils/sets.py +6 -6
  86. {shapiq-1.2.0 → shapiq-1.2.2/shapiq.egg-info}/PKG-INFO +16 -5
  87. {shapiq-1.2.0 → shapiq-1.2.2}/tests/test_base_interaction_values.py +23 -0
  88. {shapiq-1.2.0 → shapiq-1.2.2}/LICENSE +0 -0
  89. {shapiq-1.2.0 → shapiq-1.2.2}/MANIFEST.in +0 -0
  90. {shapiq-1.2.0 → shapiq-1.2.2}/setup.cfg +0 -0
  91. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/approximator/__init__.py +0 -0
  92. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/approximator/marginals/__init__.py +0 -0
  93. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/approximator/montecarlo/__init__.py +0 -0
  94. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/approximator/permutation/__init__.py +0 -0
  95. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/approximator/regression/__init__.py +0 -0
  96. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/benchmark/__init__.py +0 -0
  97. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/datasets/__init__.py +0 -0
  98. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/explainer/__init__.py +0 -0
  99. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/explainer/tree/__init__.py +0 -0
  100. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/explainer/tree/conversion/__init__.py +0 -0
  101. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/explainer/tree/conversion/edges.py +0 -0
  102. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/explainer/tree/utils.py +0 -0
  103. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/game_theory/__init__.py +0 -0
  104. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/game_theory/indices.py +0 -0
  105. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/__init__.py +0 -0
  106. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/__init__.py +0 -0
  107. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/_setup/__init__.py +0 -0
  108. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/_setup/_california_torch_setup.py +0 -0
  109. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/_setup/_resnet_setup.py +0 -0
  110. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/_setup/_vit_setup.py +0 -0
  111. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/data_valuation/__init__.py +0 -0
  112. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/dataset_valuation/__init__.py +0 -0
  113. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/ensemble_selection/__init__.py +0 -0
  114. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/feature_selection/__init__.py +0 -0
  115. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/global_xai/__init__.py +0 -0
  116. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/local_xai/__init__.py +0 -0
  117. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/local_xai/benchmark_language.py +0 -0
  118. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/synthetic/__init__.py +0 -0
  119. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/treeshapiq_xai/__init__.py +0 -0
  120. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/uncertainty/__init__.py +0 -0
  121. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/unsupervised_cluster/__init__.py +0 -0
  122. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/unsupervised_data/__init__.py +0 -0
  123. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/unsupervised_data/base.py +0 -0
  124. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/benchmark/unsupervised_data/benchmark.py +0 -0
  125. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/games/imputer/__init__.py +0 -0
  126. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/plot/__init__.py +0 -0
  127. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/plot/_config.py +0 -0
  128. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/utils/__init__.py +0 -0
  129. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq/utils/types.py +0 -0
  130. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq.egg-info/SOURCES.txt +0 -0
  131. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq.egg-info/dependency_links.txt +0 -0
  132. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq.egg-info/requires.txt +0 -0
  133. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq.egg-info/top_level.txt +0 -0
  134. {shapiq-1.2.0 → shapiq-1.2.2}/shapiq.egg-info/zip-safe +0 -0
  135. {shapiq-1.2.0 → shapiq-1.2.2}/tests/test_abstract_classes.py +0 -0
  136. {shapiq-1.2.0 → shapiq-1.2.2}/tests/test_configuration.py +0 -0
  137. {shapiq-1.2.0 → shapiq-1.2.2}/tests/test_integration_import_all.py +0 -0
@@ -1,7 +1,17 @@
1
1
  ## Changelog
2
2
 
3
3
  ### Development
4
- ...
4
+
5
+ ### v1.2.2 (2025-03-11)
6
+ - changes python support to 3.10-3.13 [#318](https://github.com/mmschlk/shapiq/pull/318)
7
+ - fixes a bug that prohibited importing shapiq in environments without write access [#326](https://github.com/mmschlk/shapiq/issues/326)
8
+ - adds `ExtraTreeRegressors` to supported models [#309](https://github.com/mmschlk/shapiq/pull/309)
9
+
10
+ ### v1.2.1 (2025-02-17)
11
+ - fixes bugs regarding plotting [#315](https://github.com/mmschlk/shapiq/issues/315) and [#316](https://github.com/mmschlk/shapiq/issues/316)
12
+ - fixes a bug with TreeExplainer and Trees that consist of only one feature [#286](https://github.com/mmschlk/shapiq/issues/286)
13
+ - fixes SV init with explainer for permutation, svarm, kernelshap, and unbiased kernelshap [#319](https://github.com/mmschlk/shapiq/issues/319)
14
+ - adds a progress bar to `explain_X()` [#324](https://github.com/mmschlk/shapiq/issues/324)
5
15
 
6
16
  ### v1.2.0 (2025-01-15)
7
17
  - adds ``shapiq.TabPFNExplainer`` as a specialized version of the ``shapiq.TabularExplainer`` which offers a streamlined variant of the explainer for the TabPFN model [#301](https://github.com/mmschlk/shapiq/issues/301)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: shapiq
3
- Version: 1.2.0
3
+ Version: 1.2.2
4
4
  Summary: Shapley Interactions for Machine Learning
5
5
  Home-page: https://github.com/mmschlk/shapiq
6
6
  Author: Maximilian Muschalik et al.
@@ -17,11 +17,11 @@ Classifier: Intended Audience :: Science/Research
17
17
  Classifier: Topic :: Scientific/Engineering
18
18
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
19
  Classifier: Programming Language :: Python
20
- Classifier: Programming Language :: Python :: 3.9
21
20
  Classifier: Programming Language :: Python :: 3.10
22
21
  Classifier: Programming Language :: Python :: 3.11
23
22
  Classifier: Programming Language :: Python :: 3.12
24
- Requires-Python: >=3.9.0
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Requires-Python: >=3.10.0
25
25
  Description-Content-Type: text/markdown
26
26
  License-File: LICENSE
27
27
  Requires-Dist: numpy
@@ -91,6 +91,7 @@ Dynamic: summary
91
91
 
92
92
  # shapiq: Shapley Interactions for Machine Learning <img src="https://raw.githubusercontent.com/mmschlk/shapiq/main/docs/source/_static/logo/logo_shapiq_light.svg" alt="shapiq_logo" align="right" height="250px"/>
93
93
 
94
+ [![PyPI version](https://badge.fury.io/py/shapiq.svg)](https://badge.fury.io/py/shapiq)
94
95
  [![License](https://img.shields.io/badge/License-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT)
95
96
  [![Coverage Status](https://coveralls.io/repos/github/mmschlk/shapiq/badge.svg?branch=main)](https://coveralls.io/github/mmschlk/shapiq?branch=main)
96
97
  [![Tests](https://github.com/mmschlk/shapiq/actions/workflows/unit-tests.yml/badge.svg)](https://github.com/mmschlk/shapiq/actions/workflows/unit-tests.yml)
@@ -107,7 +108,7 @@ Dynamic: summary
107
108
  Shapley Interaction Quantification (`shapiq`) is a Python package for (1) approximating any-order Shapley interactions, (2) benchmarking game-theoretical algorithms for machine learning, (3) explaining feature interactions of model predictions. `shapiq` extends the well-known [shap](https://github.com/shap/shap) package for both researchers working on game theory in machine learning, as well as the end-users explaining models. SHAP-IQ extends individual Shapley values by quantifying the **synergy** effect between entities (aka **players** in the jargon of game theory) like explanatory features, data points, or weak learners in ensemble models. Synergies between players give a more comprehensive view of machine learning models.
108
109
 
109
110
  ## 🛠️ Install
110
- `shapiq` is intended to work with **Python 3.9 and above**. Installation can be done via `pip`:
111
+ `shapiq` is intended to work with **Python 3.10 and above**. Installation can be done via `pip`:
111
112
 
112
113
  ```sh
113
114
  pip install shapiq
@@ -282,7 +283,17 @@ Built with ❤️ by the shapiq team.
282
283
  ## Changelog
283
284
 
284
285
  ### Development
285
- ...
286
+
287
+ ### v1.2.2 (2025-03-11)
288
+ - changes python support to 3.10-3.13 [#318](https://github.com/mmschlk/shapiq/pull/318)
289
+ - fixes a bug that prohibited importing shapiq in environments without write access [#326](https://github.com/mmschlk/shapiq/issues/326)
290
+ - adds `ExtraTreeRegressors` to supported models [#309](https://github.com/mmschlk/shapiq/pull/309)
291
+
292
+ ### v1.2.1 (2025-02-17)
293
+ - fixes bugs regarding plotting [#315](https://github.com/mmschlk/shapiq/issues/315) and [#316](https://github.com/mmschlk/shapiq/issues/316)
294
+ - fixes a bug with TreeExplainer and Trees that consist of only one feature [#286](https://github.com/mmschlk/shapiq/issues/286)
295
+ - fixes SV init with explainer for permutation, svarm, kernelshap, and unbiased kernelshap [#319](https://github.com/mmschlk/shapiq/issues/319)
296
+ - adds a progress bar to `explain_X()` [#324](https://github.com/mmschlk/shapiq/issues/324)
286
297
 
287
298
  ### v1.2.0 (2025-01-15)
288
299
  - adds ``shapiq.TabPFNExplainer`` as a specialized version of the ``shapiq.TabularExplainer`` which offers a streamlined variant of the explainer for the TabPFN model [#301](https://github.com/mmschlk/shapiq/issues/301)
@@ -1,5 +1,6 @@
1
1
  # shapiq: Shapley Interactions for Machine Learning <img src="https://raw.githubusercontent.com/mmschlk/shapiq/main/docs/source/_static/logo/logo_shapiq_light.svg" alt="shapiq_logo" align="right" height="250px"/>
2
2
 
3
+ [![PyPI version](https://badge.fury.io/py/shapiq.svg)](https://badge.fury.io/py/shapiq)
3
4
  [![License](https://img.shields.io/badge/License-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT)
4
5
  [![Coverage Status](https://coveralls.io/repos/github/mmschlk/shapiq/badge.svg?branch=main)](https://coveralls.io/github/mmschlk/shapiq?branch=main)
5
6
  [![Tests](https://github.com/mmschlk/shapiq/actions/workflows/unit-tests.yml/badge.svg)](https://github.com/mmschlk/shapiq/actions/workflows/unit-tests.yml)
@@ -16,7 +17,7 @@
16
17
  Shapley Interaction Quantification (`shapiq`) is a Python package for (1) approximating any-order Shapley interactions, (2) benchmarking game-theoretical algorithms for machine learning, (3) explaining feature interactions of model predictions. `shapiq` extends the well-known [shap](https://github.com/shap/shap) package for both researchers working on game theory in machine learning, as well as the end-users explaining models. SHAP-IQ extends individual Shapley values by quantifying the **synergy** effect between entities (aka **players** in the jargon of game theory) like explanatory features, data points, or weak learners in ensemble models. Synergies between players give a more comprehensive view of machine learning models.
17
18
 
18
19
  ## 🛠️ Install
19
- `shapiq` is intended to work with **Python 3.9 and above**. Installation can be done via `pip`:
20
+ `shapiq` is intended to work with **Python 3.10 and above**. Installation can be done via `pip`:
20
21
 
21
22
  ```sh
22
23
  pip install shapiq
@@ -7,10 +7,10 @@ testpaths = "tests"
7
7
 
8
8
  [tool.black]
9
9
  line-length = 100
10
- target-version = ['py39', 'py310', 'py311']
10
+ target-version = ['py310', 'py311', 'py312', 'py313']
11
11
 
12
12
  [tool.ruff]
13
13
  lint.select = ["E", "F", "I", "UP"] # https://beta.ruff.rs/docs/rules/
14
14
  lint.ignore = ["E501"]
15
15
  line-length = 100
16
- target-version = "py39"
16
+ target-version = "py310"
@@ -9,7 +9,7 @@ LONG_DESCRIPTION_CONTENT_TYPE = "text/markdown"
9
9
  URL = "https://github.com/mmschlk/shapiq"
10
10
  EMAIL = "maximilian.muschalik@ifi.lmu.de"
11
11
  AUTHOR = "Maximilian Muschalik et al."
12
- REQUIRES_PYTHON = ">=3.9.0"
12
+ REQUIRES_PYTHON = ">=3.10.0"
13
13
 
14
14
  work_directory = os.path.abspath(os.path.dirname(__file__))
15
15
 
@@ -89,10 +89,10 @@ setuptools.setup(
89
89
  "Topic :: Scientific/Engineering",
90
90
  "Topic :: Scientific/Engineering :: Artificial Intelligence",
91
91
  "Programming Language :: Python",
92
- "Programming Language :: Python :: 3.9",
93
92
  "Programming Language :: Python :: 3.10",
94
93
  "Programming Language :: Python :: 3.11",
95
94
  "Programming Language :: Python :: 3.12",
95
+ "Programming Language :: Python :: 3.13",
96
96
  ],
97
97
  keywords=[
98
98
  "python",
@@ -2,7 +2,7 @@
2
2
  the well established Shapley value and its generalization to interaction.
3
3
  """
4
4
 
5
- __version__ = "1.2.0"
5
+ __version__ = "1.2.2"
6
6
 
7
7
  # approximator classes
8
8
  from .approximator import (
@@ -2,7 +2,7 @@
2
2
 
3
3
  import copy
4
4
  from abc import ABC, abstractmethod
5
- from typing import Callable, Optional
5
+ from collections.abc import Callable
6
6
 
7
7
  import numpy as np
8
8
 
@@ -66,8 +66,8 @@ class Approximator(ABC):
66
66
  top_order: bool,
67
67
  min_order: int = 0,
68
68
  pairing_trick: bool = False,
69
- sampling_weights: Optional[np.ndarray[float]] = None,
70
- random_state: Optional[int] = None,
69
+ sampling_weights: np.ndarray[float] | None = None,
70
+ random_state: int | None = None,
71
71
  ) -> None:
72
72
  # check if index can be approximated
73
73
  self.index: str = index
@@ -92,8 +92,8 @@ class Approximator(ABC):
92
92
  )
93
93
 
94
94
  # set up random state and random number generators
95
- self._random_state: Optional[int] = random_state
96
- self._rng: Optional[np.random.Generator] = np.random.default_rng(seed=self._random_state)
95
+ self._random_state: int | None = random_state
96
+ self._rng: np.random.Generator | None = np.random.default_rng(seed=self._random_state)
97
97
 
98
98
  # set up a coalition sampler
99
99
  self._big_M: int = 100_000_000 # large number for sampling weights
@@ -178,8 +178,8 @@ class Approximator(ABC):
178
178
  result,
179
179
  baseline_value: float,
180
180
  *,
181
- estimated: Optional[bool] = None,
182
- budget: Optional[int] = None,
181
+ estimated: bool | None = None,
182
+ budget: int | None = None,
183
183
  ) -> InteractionValues:
184
184
  """Finalizes the result dictionary.
185
185
 
@@ -303,8 +303,8 @@ class Approximator(ABC):
303
303
  @staticmethod
304
304
  def aggregate_interaction_values(
305
305
  base_interactions: InteractionValues,
306
- order: Optional[int] = None,
307
- player_set: Optional[set[int]] = None,
306
+ order: int | None = None,
307
+ player_set: set[int] | None = None,
308
308
  ) -> InteractionValues:
309
309
  """Aggregates the interaction values.
310
310
 
@@ -2,7 +2,7 @@
2
2
  Okhrati and Lipani (2020). It estimates the Shapley values in its integral representation by
3
3
  sampling random marginal contributions."""
4
4
 
5
- from typing import Callable, Optional
5
+ from collections.abc import Callable
6
6
 
7
7
  import numpy as np
8
8
 
@@ -34,7 +34,7 @@ class OwenSamplingSV(Approximator):
34
34
  self,
35
35
  n: int,
36
36
  n_anchor_points: int = 10,
37
- random_state: Optional[int] = None,
37
+ random_state: int | None = None,
38
38
  ) -> None:
39
39
  super().__init__(n, max_order=1, index="SV", top_order=False, random_state=random_state)
40
40
  self.iteration_cost: int = 2
@@ -1,6 +1,6 @@
1
1
  """This module contains the Stratified Sampling approximation method for the Shapley values."""
2
2
 
3
- from typing import Callable, Optional
3
+ from collections.abc import Callable
4
4
 
5
5
  import numpy as np
6
6
 
@@ -31,7 +31,7 @@ class StratifiedSamplingSV(Approximator):
31
31
  def __init__(
32
32
  self,
33
33
  n: int,
34
- random_state: Optional[int] = None,
34
+ random_state: int | None = None,
35
35
  ) -> None:
36
36
  super().__init__(n, max_order=1, index="SV", top_order=False, random_state=random_state)
37
37
  self.iteration_cost: int = 2
@@ -1,6 +1,6 @@
1
1
  """This module contains the Base Regression approximator to compute SII and k-SII of arbitrary max_order."""
2
2
 
3
- from typing import Callable, Optional
3
+ from collections.abc import Callable
4
4
 
5
5
  import numpy as np
6
6
  from scipy.special import binom, factorial
@@ -41,7 +41,7 @@ class MonteCarlo(Approximator):
41
41
  stratify_coalition_size: bool = True,
42
42
  stratify_intersection: bool = True,
43
43
  top_order: bool = False,
44
- random_state: Optional[int] = None,
44
+ random_state: int | None = None,
45
45
  pairing_trick: bool = False,
46
46
  sampling_weights: np.ndarray = None,
47
47
  ):
@@ -2,8 +2,6 @@
2
2
  The Unbiased KernelSHAP method is a variant of KernelSHAP. However, it was shown that Unbiased
3
3
  KernelSHAP is a more specific variant of the ShapIQ interaction method."""
4
4
 
5
- from typing import Optional
6
-
7
5
  from ._base import MonteCarlo
8
6
 
9
7
 
@@ -53,9 +51,9 @@ class SHAPIQ(MonteCarlo):
53
51
  max_order: int = 2,
54
52
  index: str = "k-SII",
55
53
  top_order: bool = False,
56
- sampling_weights: Optional[float] = None,
54
+ sampling_weights: float | None = None,
57
55
  pairing_trick: bool = False,
58
- random_state: Optional[int] = None,
56
+ random_state: int | None = None,
59
57
  ):
60
58
  super().__init__(
61
59
  n,
@@ -117,8 +115,9 @@ class UnbiasedKernelSHAP(SHAPIQ):
117
115
  self,
118
116
  n: int,
119
117
  pairing_trick: bool = False,
120
- sampling_weights: Optional[float] = None,
121
- random_state: Optional[int] = None,
118
+ sampling_weights: float | None = None,
119
+ random_state: int | None = None,
120
+ **kwargs,
122
121
  ):
123
122
  super().__init__(
124
123
  n,
@@ -1,7 +1,5 @@
1
1
  """SVARM-IQ approximation."""
2
2
 
3
- from typing import Optional
4
-
5
3
  from ._base import MonteCarlo
6
4
 
7
5
 
@@ -37,8 +35,8 @@ class SVARMIQ(MonteCarlo):
37
35
  index: str = "k-SII",
38
36
  top_order: bool = False,
39
37
  pairing_trick: bool = False,
40
- sampling_weights: Optional[float] = None,
41
- random_state: Optional[int] = None,
38
+ sampling_weights: float | None = None,
39
+ random_state: int | None = None,
42
40
  ):
43
41
  super().__init__(
44
42
  n,
@@ -75,9 +73,10 @@ class SVARM(SVARMIQ):
75
73
  def __init__(
76
74
  self,
77
75
  n: int,
78
- random_state: Optional[int] = None,
76
+ random_state: int | None = None,
79
77
  pairing_trick: bool = False,
80
- sampling_weights: Optional[float] = None,
78
+ sampling_weights: float | None = None,
79
+ **kwargs,
81
80
  ):
82
81
  super().__init__(
83
82
  n,
@@ -1,6 +1,6 @@
1
1
  """This module implements the Permutation Sampling approximator for the SII (and k-SII) index."""
2
2
 
3
- from typing import Callable, Optional
3
+ from collections.abc import Callable
4
4
 
5
5
  import numpy as np
6
6
 
@@ -33,7 +33,7 @@ class PermutationSamplingSII(Approximator):
33
33
  max_order: int = 2,
34
34
  index: str = "SII",
35
35
  top_order: bool = False,
36
- random_state: Optional[int] = None,
36
+ random_state: int | None = None,
37
37
  ) -> None:
38
38
  if index not in ["SII", "k-SII"]:
39
39
  raise ValueError(f"Invalid index {index}. Must be either 'SII' or 'k-SII'.")
@@ -68,7 +68,7 @@ class PermutationSamplingSII(Approximator):
68
68
  self,
69
69
  budget: int,
70
70
  game: Callable[[np.ndarray], np.ndarray],
71
- batch_size: Optional[int] = 5,
71
+ batch_size: int | None = 5,
72
72
  ) -> InteractionValues:
73
73
  """Approximates the interaction values.
74
74
 
@@ -1,7 +1,7 @@
1
1
  """This module contains the permutation sampling algorithms to estimate STII scores."""
2
2
 
3
3
  import warnings
4
- from typing import Callable, Optional
4
+ from collections.abc import Callable
5
5
 
6
6
  import numpy as np
7
7
  import scipy as sp
@@ -54,7 +54,7 @@ class PermutationSamplingSTII(Approximator):
54
54
  )
55
55
  """
56
56
 
57
- def __init__(self, n: int, max_order: int, random_state: Optional[int] = None) -> None:
57
+ def __init__(self, n: int, max_order: int, random_state: int | None = None) -> None:
58
58
  super().__init__(
59
59
  n=n, max_order=max_order, index="STII", top_order=False, random_state=random_state
60
60
  )
@@ -1,6 +1,6 @@
1
1
  """This module contains the permutation sampling approximation method for the Shapley value (SV)."""
2
2
 
3
- from typing import Callable, Optional
3
+ from collections.abc import Callable
4
4
 
5
5
  import numpy as np
6
6
 
@@ -30,16 +30,12 @@ class PermutationSamplingSV(Approximator):
30
30
 
31
31
  """
32
32
 
33
- def __init__(
34
- self,
35
- n: int,
36
- random_state: Optional[int] = None,
37
- ) -> None:
33
+ def __init__(self, n: int, random_state: int | None = None, **kwargs) -> None:
38
34
  super().__init__(n=n, max_order=1, index="SV", top_order=False, random_state=random_state)
39
35
  self.iteration_cost: int = n - 1
40
36
 
41
37
  def approximate(
42
- self, budget: int, game: Callable[[np.ndarray], np.ndarray], batch_size: Optional[int] = 5
38
+ self, budget: int, game: Callable[[np.ndarray], np.ndarray], batch_size: int | None = 5
43
39
  ) -> InteractionValues:
44
40
  """Approximates the Shapley values using ApproShapley.
45
41
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  import copy
4
4
  import warnings
5
- from typing import Callable, Optional
5
+ from collections.abc import Callable
6
6
 
7
7
  import numpy as np
8
8
  from scipy.special import bernoulli, binom
@@ -42,8 +42,8 @@ class Regression(Approximator):
42
42
  index: str,
43
43
  sii_consistent: bool = True,
44
44
  pairing_trick: bool = False,
45
- sampling_weights: Optional[np.ndarray] = None,
46
- random_state: Optional[int] = None,
45
+ sampling_weights: np.ndarray | None = None,
46
+ random_state: int | None = None,
47
47
  ):
48
48
  if index not in AVAILABLE_INDICES_REGRESSION:
49
49
  raise ValueError(
@@ -1,7 +1,5 @@
1
1
  """Regression with Shapley interaction index (SII) approximation."""
2
2
 
3
- from typing import Optional
4
-
5
3
  import numpy as np
6
4
 
7
5
  from ._base import Regression
@@ -40,8 +38,8 @@ class RegressionFSII(Regression):
40
38
  n: int,
41
39
  max_order: int = 2,
42
40
  pairing_trick: bool = False,
43
- sampling_weights: Optional[np.ndarray] = None,
44
- random_state: Optional[int] = None,
41
+ sampling_weights: np.ndarray | None = None,
42
+ random_state: int | None = None,
45
43
  ):
46
44
  super().__init__(
47
45
  n,
@@ -1,7 +1,5 @@
1
1
  """Regression with Shapley interaction index (SII) approximation."""
2
2
 
3
- from typing import Optional
4
-
5
3
  import numpy as np
6
4
 
7
5
  from ._base import Regression
@@ -43,8 +41,8 @@ class kADDSHAP(Regression):
43
41
  n: int,
44
42
  max_order: int = 2,
45
43
  pairing_trick: bool = False,
46
- sampling_weights: Optional[np.ndarray] = None,
47
- random_state: Optional[int] = None,
44
+ sampling_weights: np.ndarray | None = None,
45
+ random_state: int | None = None,
48
46
  ):
49
47
  super().__init__(
50
48
  n,
@@ -1,7 +1,5 @@
1
1
  """This module contains the KernelSHAP regression approximator for estimating the SV."""
2
2
 
3
- from typing import Optional
4
-
5
3
  import numpy as np
6
4
 
7
5
  from ._base import Regression
@@ -55,8 +53,9 @@ class KernelSHAP(Regression):
55
53
  self,
56
54
  n: int,
57
55
  pairing_trick: bool = False,
58
- sampling_weights: Optional[np.ndarray] = None,
59
- random_state: Optional[int] = None,
56
+ sampling_weights: np.ndarray | None = None,
57
+ random_state: int | None = None,
58
+ **kwargs,
60
59
  ):
61
60
  super().__init__(
62
61
  n,
@@ -1,7 +1,5 @@
1
1
  """Regression with Shapley interaction index (SII) approximation."""
2
2
 
3
- from typing import Optional
4
-
5
3
  import numpy as np
6
4
 
7
5
  from ._base import Regression
@@ -55,8 +53,8 @@ class KernelSHAPIQ(Regression):
55
53
  max_order: int = 2,
56
54
  index: str = "k-SII",
57
55
  pairing_trick: bool = False,
58
- sampling_weights: Optional[np.ndarray] = None,
59
- random_state: Optional[int] = None,
56
+ sampling_weights: np.ndarray | None = None,
57
+ random_state: int | None = None,
60
58
  ) -> None:
61
59
  if index not in AVAILABLE_INDICES_KERNELSHAPIQ:
62
60
  raise ValueError(
@@ -115,8 +113,8 @@ class InconsistentKernelSHAPIQ(Regression):
115
113
  max_order: int = 2,
116
114
  index: str = "k-SII",
117
115
  pairing_trick: bool = False,
118
- sampling_weights: Optional[np.ndarray] = None,
119
- random_state: Optional[int] = None,
116
+ sampling_weights: np.ndarray | None = None,
117
+ random_state: int | None = None,
120
118
  ) -> None:
121
119
  if index not in AVAILABLE_INDICES_KERNELSHAPIQ:
122
120
  raise ValueError(
@@ -2,7 +2,6 @@
2
2
 
3
3
  import copy
4
4
  import warnings
5
- from typing import Optional
6
5
 
7
6
  import numpy as np
8
7
  from scipy.special import binom
@@ -76,7 +75,7 @@ class CoalitionSampler:
76
75
  n_players: int,
77
76
  sampling_weights: np.ndarray,
78
77
  pairing_trick: bool = False,
79
- random_state: Optional[int] = None,
78
+ random_state: int | None = None,
80
79
  ) -> None:
81
80
  self.pairing_trick: bool = pairing_trick
82
81
 
@@ -115,28 +114,26 @@ class CoalitionSampler:
115
114
  if weight == 0 and 0 < size < self.n:
116
115
  self.n_max_coalitions -= int(binom(self.n, size))
117
116
  self._coalitions_to_exclude.extend([size])
118
- self.adjusted_sampling_weights: Optional[np.ndarray[float]] = None
117
+ self.adjusted_sampling_weights: np.ndarray[float] | None = None
119
118
 
120
119
  # set sample size variables (for border trick)
121
- self._coalitions_to_compute: Optional[list[int]] = None # coalitions to compute
122
- self._coalitions_to_sample: Optional[list[int]] = None # coalitions to sample
120
+ self._coalitions_to_compute: list[int] | None = None # coalitions to compute
121
+ self._coalitions_to_sample: list[int] | None = None # coalitions to sample
123
122
 
124
123
  # initialize variables to be computed and stored
125
- self.sampled_coalitions_dict: Optional[dict[tuple[int, ...], int]] = None # coal -> count
126
- self.coalitions_per_size: Optional[np.ndarray[int]] = None # number of coalitions per size
124
+ self.sampled_coalitions_dict: dict[tuple[int, ...], int] | None = None # coal -> count
125
+ self.coalitions_per_size: np.ndarray[int] | None = None # number of coalitions per size
127
126
 
128
127
  # variables accessible through properties
129
- self._sampled_coalitions_matrix: Optional[np.ndarray[bool]] = None # coalitions
130
- self._sampled_coalitions_counter: Optional[np.ndarray[int]] = None # coalitions_counter
131
- self._sampled_coalitions_size_prob: Optional[np.ndarray[float]] = (
128
+ self._sampled_coalitions_matrix: np.ndarray[bool] | None = None # coalitions
129
+ self._sampled_coalitions_counter: np.ndarray[int] | None = None # coalitions_counter
130
+ self._sampled_coalitions_size_prob: np.ndarray[float] | None = (
132
131
  None # coalitions_size_probability
133
132
  )
134
- self._sampled_coalitions_in_size_prob: Optional[np.ndarray[float]] = (
133
+ self._sampled_coalitions_in_size_prob: np.ndarray[float] | None = (
135
134
  None # coalitions_in_size_probability
136
135
  )
137
- self._is_coalition_size_sampled: Optional[np.ndarray[bool]] = (
138
- None # is_coalition_size_sampled
139
- )
136
+ self._is_coalition_size_sampled: np.ndarray[bool] | None = None # is_coalition_size_sampled
140
137
 
141
138
  @property
142
139
  def n_coalitions(self) -> int:
@@ -272,7 +269,7 @@ class CoalitionSampler:
272
269
  return np.sum(self.coalitions_matrix, axis=1)
273
270
 
274
271
  @property
275
- def empty_coalition_index(self) -> Optional[int]:
272
+ def empty_coalition_index(self) -> int | None:
276
273
  """Returns the index of the empty coalition.
277
274
 
278
275
  Returns:
@@ -34,7 +34,7 @@ information:
34
34
  """
35
35
 
36
36
  import os
37
- from typing import Any, Optional
37
+ from typing import Any
38
38
 
39
39
  from shapiq.approximator import (
40
40
  FSII_APPROXIMATORS,
@@ -757,7 +757,7 @@ APPROXIMATION_BENCHMARK_PARAMS.update(
757
757
 
758
758
 
759
759
  def get_game_file_name_from_config(
760
- configuration: dict[str, Any], iteration: Optional[int] = None
760
+ configuration: dict[str, Any], iteration: int | None = None
761
761
  ) -> str:
762
762
  """Get the file name for the game data with the given configuration and iteration.
763
763
 
@@ -4,7 +4,7 @@ from the precomputed data (GitHub repository)."""
4
4
  import os
5
5
  import time
6
6
  from collections.abc import Generator
7
- from typing import Any, Optional, Union
7
+ from typing import Any
8
8
 
9
9
  import requests
10
10
 
@@ -26,9 +26,9 @@ __all__ = [
26
26
 
27
27
 
28
28
  def load_games_from_configuration(
29
- game_class: Union[Game.__class__, str],
29
+ game_class: Game.__class__ | str,
30
30
  config_id: int,
31
- n_games: Optional[int] = None,
31
+ n_games: int | None = None,
32
32
  n_player_id: int = 0,
33
33
  check_pre_computed: bool = True,
34
34
  only_pre_computed: bool = True,
@@ -2,7 +2,6 @@
2
2
 
3
3
  import copy
4
4
  import warnings
5
- from typing import Optional
6
5
 
7
6
  import numpy as np
8
7
  from scipy.stats import kendalltau
@@ -145,7 +144,7 @@ def compute_precision_at_k(
145
144
  def get_all_metrics(
146
145
  ground_truth: InteractionValues,
147
146
  estimated: InteractionValues,
148
- order_indicator: Optional[str] = None,
147
+ order_indicator: str | None = None,
149
148
  ) -> dict:
150
149
  """Get all metrics for the interaction values.
151
150