shapiq 1.2.1__tar.gz → 1.2.3__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 (142) hide show
  1. {shapiq-1.2.1 → shapiq-1.2.3}/CHANGELOG.md +16 -1
  2. {shapiq-1.2.1/shapiq.egg-info → shapiq-1.2.3}/PKG-INFO +48 -72
  3. {shapiq-1.2.1 → shapiq-1.2.3}/README.md +3 -1
  4. shapiq-1.2.3/pyproject.toml +121 -0
  5. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/__init__.py +3 -1
  6. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/approximator/__init__.py +15 -1
  7. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/approximator/_base.py +37 -103
  8. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/approximator/marginals/owen.py +35 -11
  9. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/approximator/marginals/stratified.py +17 -6
  10. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/approximator/montecarlo/_base.py +37 -10
  11. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/approximator/montecarlo/shapiq.py +4 -6
  12. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/approximator/montecarlo/svarmiq.py +4 -6
  13. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/approximator/permutation/sii.py +16 -6
  14. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/approximator/permutation/stii.py +51 -14
  15. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/approximator/permutation/sv.py +30 -8
  16. shapiq-1.2.3/shapiq/approximator/regression/__init__.py +17 -0
  17. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/approximator/regression/_base.py +165 -127
  18. shapiq-1.2.3/shapiq/approximator/regression/faithful.py +97 -0
  19. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/approximator/regression/kadd_shap.py +2 -4
  20. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/approximator/regression/kernelshap.py +2 -4
  21. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/approximator/regression/kernelshapiq.py +4 -6
  22. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/approximator/sampling.py +17 -17
  23. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/benchmark/configuration.py +2 -2
  24. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/benchmark/load.py +4 -5
  25. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/benchmark/metrics.py +1 -2
  26. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/benchmark/plot.py +8 -8
  27. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/benchmark/precompute.py +8 -8
  28. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/benchmark/run.py +20 -24
  29. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/datasets/_all.py +12 -11
  30. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/explainer/_base.py +1 -4
  31. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/explainer/tabpfn.py +15 -6
  32. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/explainer/tabular.py +20 -8
  33. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/explainer/tree/base.py +33 -12
  34. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/explainer/tree/conversion/lightgbm.py +25 -35
  35. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/explainer/tree/conversion/sklearn.py +2 -4
  36. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/explainer/tree/conversion/xgboost.py +25 -37
  37. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/explainer/tree/explainer.py +16 -6
  38. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/explainer/tree/treeshapiq.py +49 -23
  39. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/explainer/tree/validation.py +8 -6
  40. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/explainer/utils.py +6 -3
  41. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/game_theory/__init__.py +2 -2
  42. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/game_theory/aggregation.py +14 -12
  43. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/game_theory/core.py +1 -2
  44. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/game_theory/exact.py +24 -20
  45. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/game_theory/indices.py +4 -4
  46. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/game_theory/moebius_converter.py +4 -4
  47. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/base.py +21 -22
  48. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/__init__.py +48 -32
  49. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/data_valuation/base.py +2 -2
  50. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/data_valuation/benchmark.py +3 -5
  51. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/dataset_valuation/base.py +10 -10
  52. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/dataset_valuation/benchmark.py +6 -8
  53. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/ensemble_selection/__init__.py +7 -5
  54. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/ensemble_selection/base.py +6 -6
  55. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/ensemble_selection/benchmark.py +6 -8
  56. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/ensemble_selection/benchmark_random_forest.py +3 -5
  57. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/feature_selection/base.py +5 -4
  58. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/feature_selection/benchmark.py +3 -5
  59. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/global_xai/base.py +2 -2
  60. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/global_xai/benchmark_tabular.py +3 -5
  61. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/local_xai/base.py +4 -5
  62. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/local_xai/benchmark_image.py +1 -2
  63. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/local_xai/benchmark_tabular.py +7 -9
  64. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/setup.py +5 -6
  65. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/synthetic/__init__.py +2 -1
  66. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/synthetic/dummy.py +1 -3
  67. shapiq-1.2.3/shapiq/games/benchmark/synthetic/random.py +33 -0
  68. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/synthetic/soum.py +5 -7
  69. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/treeshapiq_xai/base.py +1 -2
  70. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/treeshapiq_xai/benchmark.py +8 -10
  71. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/uncertainty/base.py +2 -4
  72. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/uncertainty/benchmark.py +2 -4
  73. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/unsupervised_cluster/base.py +4 -6
  74. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/unsupervised_cluster/benchmark.py +3 -5
  75. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/imputer/base.py +4 -5
  76. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/imputer/baseline_imputer.py +2 -3
  77. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/imputer/conditional_imputer.py +7 -5
  78. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/imputer/marginal_imputer.py +4 -15
  79. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/imputer/tabpfn_imputer.py +4 -4
  80. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/interaction_values.py +90 -30
  81. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/plot/bar.py +5 -7
  82. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/plot/force.py +2 -4
  83. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/plot/network.py +13 -13
  84. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/plot/sentence.py +3 -4
  85. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/plot/si_graph.py +12 -15
  86. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/plot/stacked_bar.py +6 -6
  87. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/plot/upset.py +2 -3
  88. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/plot/utils.py +1 -2
  89. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/plot/watefall.py +3 -5
  90. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/utils/datasets.py +1 -3
  91. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/utils/modules.py +11 -15
  92. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/utils/sets.py +6 -6
  93. {shapiq-1.2.1 → shapiq-1.2.3/shapiq.egg-info}/PKG-INFO +48 -72
  94. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq.egg-info/SOURCES.txt +2 -5
  95. shapiq-1.2.3/shapiq.egg-info/requires.txt +23 -0
  96. {shapiq-1.2.1 → shapiq-1.2.3}/tests/test_base_interaction_values.py +16 -5
  97. shapiq-1.2.1/MANIFEST.in +0 -3
  98. shapiq-1.2.1/pyproject.toml +0 -16
  99. shapiq-1.2.1/setup.py +0 -110
  100. shapiq-1.2.1/shapiq/approximator/regression/__init__.py +0 -8
  101. shapiq-1.2.1/shapiq/approximator/regression/fsi.py +0 -53
  102. shapiq-1.2.1/shapiq.egg-info/requires.txt +0 -53
  103. shapiq-1.2.1/shapiq.egg-info/zip-safe +0 -1
  104. shapiq-1.2.1/tests/test_abstract_classes.py +0 -64
  105. {shapiq-1.2.1 → shapiq-1.2.3}/LICENSE +0 -0
  106. {shapiq-1.2.1 → shapiq-1.2.3}/setup.cfg +0 -0
  107. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/approximator/marginals/__init__.py +0 -0
  108. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/approximator/montecarlo/__init__.py +0 -0
  109. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/approximator/permutation/__init__.py +0 -0
  110. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/benchmark/__init__.py +0 -0
  111. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/datasets/__init__.py +0 -0
  112. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/explainer/__init__.py +0 -0
  113. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/explainer/tree/__init__.py +0 -0
  114. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/explainer/tree/conversion/__init__.py +0 -0
  115. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/explainer/tree/conversion/edges.py +0 -0
  116. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/explainer/tree/utils.py +0 -0
  117. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/__init__.py +0 -0
  118. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/_setup/__init__.py +0 -0
  119. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/_setup/_california_torch_setup.py +0 -0
  120. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/_setup/_resnet_setup.py +0 -0
  121. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/_setup/_vit_setup.py +0 -0
  122. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/data_valuation/__init__.py +0 -0
  123. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/dataset_valuation/__init__.py +0 -0
  124. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/feature_selection/__init__.py +0 -0
  125. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/global_xai/__init__.py +0 -0
  126. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/local_xai/__init__.py +0 -0
  127. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/local_xai/benchmark_language.py +0 -0
  128. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/treeshapiq_xai/__init__.py +0 -0
  129. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/uncertainty/__init__.py +0 -0
  130. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/unsupervised_cluster/__init__.py +0 -0
  131. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/unsupervised_data/__init__.py +0 -0
  132. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/unsupervised_data/base.py +0 -0
  133. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/benchmark/unsupervised_data/benchmark.py +0 -0
  134. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/games/imputer/__init__.py +0 -0
  135. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/plot/__init__.py +0 -0
  136. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/plot/_config.py +0 -0
  137. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/utils/__init__.py +0 -0
  138. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq/utils/types.py +0 -0
  139. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq.egg-info/dependency_links.txt +0 -0
  140. {shapiq-1.2.1 → shapiq-1.2.3}/shapiq.egg-info/top_level.txt +0 -0
  141. {shapiq-1.2.1 → shapiq-1.2.3}/tests/test_configuration.py +0 -0
  142. {shapiq-1.2.1 → shapiq-1.2.3}/tests/test_integration_import_all.py +0 -0
@@ -1,7 +1,22 @@
1
1
  ## Changelog
2
2
 
3
3
  ### Development
4
- ...
4
+
5
+ ### v1.2.3 (2025-03-24)
6
+ - substantially improves the runtime of all `Regression` approximators by a) a faster pre-computation of the regression matrices and b) a faster computation of the weighted least squares regression [#340](https://github.com/mmschlk/shapiq/issues/340)
7
+ - removes `sample_replacements` parameter from `MarginalImputer` and removes the DeprecationWarning for it
8
+ - adds a trivial computation to `TreeSHAP-IQ` for trees that use only one feature in the tree (this works for decision stumps or trees splitting on only one feature multiple times). In such trees, the computation is trivial as the whole effect of $\nu(N) - \nu(\emptyset)$ is all on the main effect of the single feature and there is no interaction effect. This expands on the fix in v1.2.1 [#286](https://github.com/mmschlk/shapiq/issues/286).
9
+ - fixes a bug with xgboost where feature names where trees that did not contain all features would lead `TreeExplainer` to fail
10
+ - fixes a bug with `stacked_bar_plot` where the higher order interactions were inflated by the lower order interactions, thus wrongly showing the higher order interactions as higher than they are
11
+ - fixes a bug where `InteractionValues.get_subset()` returns a faulty `coalition_lookup` dictionary pointing to indices outside the subset of players [#336](https://github.com/mmschlk/shapiq/issues/336)
12
+ - updates default value of `TreeExplainer`'s `min_order` parameter from 1 to 0 to include the baseline value in the interaction values as per default
13
+ - adds the `RegressionFBII` approximator to estimate Faithful Banzhaf interactions via least squares regression [#333](https://github.com/mmschlk/shapiq/pull/333). Additionally, FBII support was introduced in TabularExplainer and MonteCarlo-Approximator.
14
+ - adds a `RandomGame` class as part of `shapiq.games.benchmark` which always returns a random vector of integers between 0 and 100.
15
+
16
+ ### v1.2.2 (2025-03-11)
17
+ - changes python support to 3.10-3.13 [#318](https://github.com/mmschlk/shapiq/pull/318)
18
+ - fixes a bug that prohibited importing shapiq in environments without write access [#326](https://github.com/mmschlk/shapiq/issues/326)
19
+ - adds `ExtraTreeRegressors` to supported models [#309](https://github.com/mmschlk/shapiq/pull/309)
5
20
 
6
21
  ### v1.2.1 (2025-02-17)
7
22
  - fixes bugs regarding plotting [#315](https://github.com/mmschlk/shapiq/issues/315) and [#316](https://github.com/mmschlk/shapiq/issues/316)
@@ -1,27 +1,30 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: shapiq
3
- Version: 1.2.1
3
+ Version: 1.2.3
4
4
  Summary: Shapley Interactions for Machine Learning
5
- Home-page: https://github.com/mmschlk/shapiq
6
- Author: Maximilian Muschalik et al.
7
- Author-email: maximilian.muschalik@ifi.lmu.de
8
- License: MIT
9
- Project-URL: Tracker, https://github.com/mmschlk/shapiq/issues
10
- Project-URL: Source, https://github.com/mmschlk/shapiq
11
- Project-URL: Documentation, https://shapiq.readthedocs.io
5
+ Author: Hubert Baniecki, Fabian Fumagalli
6
+ Author-email: Maximilian Muschalik <Maximilian.Muschalik@lmu.de>
7
+ Maintainer-email: Maximilian Muschalik <Maximilian.Muschalik@lmu.de>
8
+ License-Expression: MIT
9
+ Project-URL: documentation, https://shapiq.readthedocs.io
10
+ Project-URL: source, https://github.com/mmschlk/shapiq
11
+ Project-URL: tracker, https://github.com/mmschlk/shapiq/issues
12
+ Project-URL: changelog, https://github.com/mmschlk/shapiq/blob/main/CHANGELOG.md
12
13
  Keywords: python,machine learning,interpretable machine learning,shap,xai,explainable ai,interaction,shapley interactions,shapley values,feature interaction
13
14
  Classifier: Development Status :: 4 - Beta
14
- Classifier: License :: OSI Approved :: MIT License
15
15
  Classifier: Intended Audience :: Developers
16
16
  Classifier: Intended Audience :: Science/Research
17
17
  Classifier: Topic :: Scientific/Engineering
18
18
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
- Classifier: Programming Language :: Python
20
- Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Operating System :: Microsoft :: Windows
20
+ Classifier: Operating System :: Unix
21
+ Classifier: Operating System :: MacOS
22
+ Classifier: Programming Language :: Python :: 3
21
23
  Classifier: Programming Language :: Python :: 3.10
22
24
  Classifier: Programming Language :: Python :: 3.11
23
25
  Classifier: Programming Language :: Python :: 3.12
24
- Requires-Python: >=3.9.0
26
+ Classifier: Programming Language :: Python :: 3.13
27
+ Requires-Python: >=3.10
25
28
  Description-Content-Type: text/markdown
26
29
  License-File: LICENSE
27
30
  Requires-Dist: numpy
@@ -31,63 +34,20 @@ Requires-Dist: scikit-learn
31
34
  Requires-Dist: tqdm
32
35
  Requires-Dist: requests
33
36
  Requires-Dist: matplotlib
34
- Requires-Dist: colour
35
37
  Requires-Dist: networkx
36
- Provides-Extra: docs
37
- Requires-Dist: numpy; extra == "docs"
38
- Requires-Dist: scipy; extra == "docs"
39
- Requires-Dist: pandas; extra == "docs"
40
- Requires-Dist: scikit-learn; extra == "docs"
41
- Requires-Dist: tqdm; extra == "docs"
42
- Requires-Dist: requests; extra == "docs"
43
- Requires-Dist: matplotlib; extra == "docs"
44
- Requires-Dist: colour; extra == "docs"
45
- Requires-Dist: networkx; extra == "docs"
46
- Requires-Dist: sphinx; extra == "docs"
47
- Requires-Dist: sphinx-autodoc-typehints; extra == "docs"
48
- Requires-Dist: sphinx_rtd_theme; extra == "docs"
49
- Requires-Dist: sphinx_toolbox; extra == "docs"
50
- Requires-Dist: nbsphinx; extra == "docs"
51
- Requires-Dist: pandoc; extra == "docs"
52
- Requires-Dist: furo; extra == "docs"
53
- Requires-Dist: sphinx-copybutton; extra == "docs"
54
- Requires-Dist: myst-parser; extra == "docs"
55
- Provides-Extra: dev
56
- Requires-Dist: numpy; extra == "dev"
57
- Requires-Dist: scipy; extra == "dev"
58
- Requires-Dist: pandas; extra == "dev"
59
- Requires-Dist: scikit-learn; extra == "dev"
60
- Requires-Dist: tqdm; extra == "dev"
61
- Requires-Dist: requests; extra == "dev"
62
- Requires-Dist: matplotlib; extra == "dev"
63
- Requires-Dist: colour; extra == "dev"
64
- Requires-Dist: networkx; extra == "dev"
65
- Requires-Dist: sphinx; extra == "dev"
66
- Requires-Dist: sphinx-autodoc-typehints; extra == "dev"
67
- Requires-Dist: sphinx_rtd_theme; extra == "dev"
68
- Requires-Dist: sphinx_toolbox; extra == "dev"
69
- Requires-Dist: nbsphinx; extra == "dev"
70
- Requires-Dist: pandoc; extra == "dev"
71
- Requires-Dist: furo; extra == "dev"
72
- Requires-Dist: sphinx-copybutton; extra == "dev"
73
- Requires-Dist: myst-parser; extra == "dev"
74
- Requires-Dist: build; extra == "dev"
75
- Requires-Dist: black; extra == "dev"
76
- Requires-Dist: pytest; extra == "dev"
77
- Requires-Dist: coverage; extra == "dev"
78
- Dynamic: author
79
- Dynamic: author-email
80
- Dynamic: classifier
81
- Dynamic: description
82
- Dynamic: description-content-type
83
- Dynamic: home-page
84
- Dynamic: keywords
85
- Dynamic: license
86
- Dynamic: project-url
87
- Dynamic: provides-extra
88
- Dynamic: requires-dist
89
- Dynamic: requires-python
90
- Dynamic: summary
38
+ Requires-Dist: colour
39
+ Provides-Extra: ml
40
+ Requires-Dist: tabpfn; extra == "ml"
41
+ Requires-Dist: torchvision; extra == "ml"
42
+ Requires-Dist: torch; extra == "ml"
43
+ Requires-Dist: xgboost; extra == "ml"
44
+ Requires-Dist: lightgbm; extra == "ml"
45
+ Requires-Dist: transformers; extra == "ml"
46
+ Requires-Dist: scikit-image; extra == "ml"
47
+ Requires-Dist: joblib; extra == "ml"
48
+ Requires-Dist: tensorflow; python_version < "3.13" and extra == "ml"
49
+ Requires-Dist: tf-keras; python_version < "3.13" and extra == "ml"
50
+ Dynamic: license-file
91
51
 
92
52
  # 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
53
 
@@ -102,13 +62,15 @@ Dynamic: summary
102
62
  [![PePy](https://static.pepy.tech/badge/shapiq?style=flat-square)](https://pepy.tech/project/shapiq)
103
63
 
104
64
  [![Code Style](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
65
+ ![Contributions Welcome](https://img.shields.io/badge/contributions-welcome-brightgreen)
66
+ ![Last Commit](https://img.shields.io/github/last-commit/mmschlk/shapiq)
105
67
 
106
68
  > An interaction may speak more than a thousand main effects.
107
69
 
108
70
  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.
109
71
 
110
72
  ## 🛠️ Install
111
- `shapiq` is intended to work with **Python 3.9 and above**. Installation can be done via `pip`:
73
+ `shapiq` is intended to work with **Python 3.10 and above**. Installation can be done via `pip`:
112
74
 
113
75
  ```sh
114
76
  pip install shapiq
@@ -279,11 +241,25 @@ Some authors acknowledge the financial support by the German Research Foundation
279
241
  ---
280
242
  Built with ❤️ by the shapiq team.
281
243
 
282
-
283
244
  ## Changelog
284
245
 
285
246
  ### Development
286
- ...
247
+
248
+ ### v1.2.3 (2025-03-24)
249
+ - substantially improves the runtime of all `Regression` approximators by a) a faster pre-computation of the regression matrices and b) a faster computation of the weighted least squares regression [#340](https://github.com/mmschlk/shapiq/issues/340)
250
+ - removes `sample_replacements` parameter from `MarginalImputer` and removes the DeprecationWarning for it
251
+ - adds a trivial computation to `TreeSHAP-IQ` for trees that use only one feature in the tree (this works for decision stumps or trees splitting on only one feature multiple times). In such trees, the computation is trivial as the whole effect of $\nu(N) - \nu(\emptyset)$ is all on the main effect of the single feature and there is no interaction effect. This expands on the fix in v1.2.1 [#286](https://github.com/mmschlk/shapiq/issues/286).
252
+ - fixes a bug with xgboost where feature names where trees that did not contain all features would lead `TreeExplainer` to fail
253
+ - fixes a bug with `stacked_bar_plot` where the higher order interactions were inflated by the lower order interactions, thus wrongly showing the higher order interactions as higher than they are
254
+ - fixes a bug where `InteractionValues.get_subset()` returns a faulty `coalition_lookup` dictionary pointing to indices outside the subset of players [#336](https://github.com/mmschlk/shapiq/issues/336)
255
+ - updates default value of `TreeExplainer`'s `min_order` parameter from 1 to 0 to include the baseline value in the interaction values as per default
256
+ - adds the `RegressionFBII` approximator to estimate Faithful Banzhaf interactions via least squares regression [#333](https://github.com/mmschlk/shapiq/pull/333). Additionally, FBII support was introduced in TabularExplainer and MonteCarlo-Approximator.
257
+ - adds a `RandomGame` class as part of `shapiq.games.benchmark` which always returns a random vector of integers between 0 and 100.
258
+
259
+ ### v1.2.2 (2025-03-11)
260
+ - changes python support to 3.10-3.13 [#318](https://github.com/mmschlk/shapiq/pull/318)
261
+ - fixes a bug that prohibited importing shapiq in environments without write access [#326](https://github.com/mmschlk/shapiq/issues/326)
262
+ - adds `ExtraTreeRegressors` to supported models [#309](https://github.com/mmschlk/shapiq/pull/309)
287
263
 
288
264
  ### v1.2.1 (2025-02-17)
289
265
  - fixes bugs regarding plotting [#315](https://github.com/mmschlk/shapiq/issues/315) and [#316](https://github.com/mmschlk/shapiq/issues/316)
@@ -11,13 +11,15 @@
11
11
  [![PePy](https://static.pepy.tech/badge/shapiq?style=flat-square)](https://pepy.tech/project/shapiq)
12
12
 
13
13
  [![Code Style](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
14
+ ![Contributions Welcome](https://img.shields.io/badge/contributions-welcome-brightgreen)
15
+ ![Last Commit](https://img.shields.io/github/last-commit/mmschlk/shapiq)
14
16
 
15
17
  > An interaction may speak more than a thousand main effects.
16
18
 
17
19
  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.
18
20
 
19
21
  ## 🛠️ Install
20
- `shapiq` is intended to work with **Python 3.9 and above**. Installation can be done via `pip`:
22
+ `shapiq` is intended to work with **Python 3.10 and above**. Installation can be done via `pip`:
21
23
 
22
24
  ```sh
23
25
  pip install shapiq
@@ -0,0 +1,121 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "shapiq"
7
+ dynamic = ["version", "readme"]
8
+ description = "Shapley Interactions for Machine Learning"
9
+ requires-python = ">=3.10"
10
+ dependencies = [
11
+ # core
12
+ "numpy",
13
+ "scipy",
14
+ "pandas",
15
+ "scikit-learn",
16
+ "tqdm",
17
+ "requests",
18
+ # plotting
19
+ "matplotlib",
20
+ "networkx",
21
+ "colour"
22
+ ]
23
+ authors = [
24
+ {name = "Maximilian Muschalik", email = "Maximilian.Muschalik@lmu.de"},
25
+ {name = "Hubert Baniecki"},
26
+ {name = "Fabian Fumagalli"},
27
+ ]
28
+ maintainers = [
29
+ {name = "Maximilian Muschalik", email = "Maximilian.Muschalik@lmu.de"},
30
+ ]
31
+ license = "MIT"
32
+ classifiers = [
33
+ "Development Status :: 4 - Beta",
34
+ "Intended Audience :: Developers",
35
+ "Intended Audience :: Science/Research",
36
+ "Topic :: Scientific/Engineering",
37
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
38
+ 'Operating System :: Microsoft :: Windows',
39
+ 'Operating System :: Unix',
40
+ 'Operating System :: MacOS',
41
+ 'Programming Language :: Python :: 3',
42
+ 'Programming Language :: Python :: 3.10',
43
+ 'Programming Language :: Python :: 3.11',
44
+ 'Programming Language :: Python :: 3.12',
45
+ 'Programming Language :: Python :: 3.13',
46
+ ]
47
+ keywords = [
48
+ "python",
49
+ "machine learning",
50
+ "interpretable machine learning",
51
+ "shap",
52
+ "xai",
53
+ "explainable ai",
54
+ "interaction",
55
+ "shapley interactions",
56
+ "shapley values",
57
+ "feature interaction",
58
+ ]
59
+
60
+ [tool.setuptools.packages.find]
61
+ where = ["."]
62
+ include = ["shapiq*"]
63
+
64
+ [tool.setuptools.dynamic]
65
+ version = {attr = "shapiq.__version__"}
66
+ readme = {file = ["README.md", "CHANGELOG.md"], content-type = "text/markdown"}
67
+
68
+ [project.urls]
69
+ documentation = "https://shapiq.readthedocs.io"
70
+ source = "https://github.com/mmschlk/shapiq"
71
+ tracker = "https://github.com/mmschlk/shapiq/issues"
72
+ changelog = "https://github.com/mmschlk/shapiq/blob/main/CHANGELOG.md"
73
+
74
+ [project.optional-dependencies]
75
+ ml = [
76
+ "tabpfn",
77
+ "torchvision",
78
+ "torch",
79
+ "xgboost",
80
+ "lightgbm",
81
+ "transformers",
82
+ "scikit-image",
83
+ "joblib",
84
+ "tensorflow; python_version < '3.13'",
85
+ "tf-keras; python_version < '3.13'",
86
+ ]
87
+
88
+ [tool.pytest.ini_options]
89
+ testpaths = ["tests"]
90
+ minversion = "8.0"
91
+
92
+ [tool.ruff]
93
+ lint.select = ["E", "F", "I", "UP"] # https://beta.ruff.rs/docs/rules/
94
+ lint.ignore = ["E501"]
95
+ line-length = 100
96
+ target-version = "py310"
97
+
98
+ [tool.ruff.lint.isort]
99
+ known-first-party = ["shapiq"]
100
+ extra-standard-library = ["typing_extensions"]
101
+ combine-as-imports = true
102
+ force-wrap-aliases = true
103
+
104
+ [dependency-groups]
105
+ test = [
106
+ "pytest>=8.3.5",
107
+ "pytest-cov>=6.0.0",
108
+ "pytest-xdist>=3.6.1",
109
+ ]
110
+ lint = [
111
+ "ruff>=0.11.2",
112
+ "pre-commit>=4.2.0",
113
+ ]
114
+ dev = [
115
+ "build>=1.2.2.post1",
116
+ "twine>=6.1.0",
117
+ "notebook>=7.3.3",
118
+ "ipywidgets",
119
+ {include-group = "test"},
120
+ {include-group = "lint"},
121
+ ]
@@ -2,7 +2,7 @@
2
2
  the well established Shapley value and its generalization to interaction.
3
3
  """
4
4
 
5
- __version__ = "1.2.1"
5
+ __version__ = "1.2.3"
6
6
 
7
7
  # approximator classes
8
8
  from .approximator import (
@@ -16,6 +16,7 @@ from .approximator import (
16
16
  PermutationSamplingSII,
17
17
  PermutationSamplingSTII,
18
18
  PermutationSamplingSV,
19
+ RegressionFBII,
19
20
  RegressionFSII,
20
21
  StratifiedSamplingSV,
21
22
  UnbiasedKernelSHAP,
@@ -86,6 +87,7 @@ __all__ = [
86
87
  "OwenSamplingSV",
87
88
  "KernelSHAP",
88
89
  "RegressionFSII",
90
+ "RegressionFBII",
89
91
  "KernelSHAPIQ",
90
92
  "InconsistentKernelSHAPIQ",
91
93
  "SHAPIQ",
@@ -6,7 +6,14 @@ from .montecarlo import SHAPIQ, SVARM, SVARMIQ, UnbiasedKernelSHAP
6
6
  from .permutation.sii import PermutationSamplingSII
7
7
  from .permutation.stii import PermutationSamplingSTII
8
8
  from .permutation.sv import PermutationSamplingSV
9
- from .regression import InconsistentKernelSHAPIQ, KernelSHAP, KernelSHAPIQ, RegressionFSII, kADDSHAP
9
+ from .regression import (
10
+ InconsistentKernelSHAPIQ,
11
+ KernelSHAP,
12
+ KernelSHAPIQ,
13
+ RegressionFBII,
14
+ RegressionFSII,
15
+ kADDSHAP,
16
+ )
10
17
 
11
18
  # contains all SV approximators
12
19
  SV_APPROXIMATORS: list[Approximator.__class__] = [
@@ -57,6 +64,11 @@ FSII_APPROXIMATORS: list[Approximator.__class__] = [
57
64
  SHAPIQ,
58
65
  ]
59
66
 
67
+ # contains all approximators that can be used for FBII
68
+ FBII_APPROXIMATORS: list[Approximator.__class__] = [
69
+ RegressionFBII,
70
+ ]
71
+
60
72
  __all__ = [
61
73
  "PermutationSamplingSII",
62
74
  "PermutationSamplingSTII",
@@ -65,6 +77,7 @@ __all__ = [
65
77
  "OwenSamplingSV",
66
78
  "KernelSHAP",
67
79
  "RegressionFSII",
80
+ "RegressionFBII",
68
81
  "KernelSHAPIQ",
69
82
  "InconsistentKernelSHAPIQ",
70
83
  "SHAPIQ",
@@ -77,6 +90,7 @@ __all__ = [
77
90
  "SII_APPROXIMATORS",
78
91
  "STII_APPROXIMATORS",
79
92
  "FSII_APPROXIMATORS",
93
+ "FBII_APPROXIMATORS",
80
94
  ]
81
95
 
82
96
  # Path: shapiq/approximator/__init__.py
@@ -1,17 +1,16 @@
1
1
  """This module contains the base approximator classes for the shapiq package."""
2
2
 
3
- import copy
3
+ import warnings
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
+ from scipy.special import binom
8
9
 
9
10
  from ..approximator.sampling import CoalitionSampler
10
11
  from ..game_theory.indices import (
11
12
  AVAILABLE_INDICES_FOR_APPROXIMATION,
12
13
  get_computation_index,
13
- is_empty_value_the_baseline,
14
- is_index_aggregated,
15
14
  )
16
15
  from ..interaction_values import InteractionValues
17
16
  from ..utils.sets import generate_interaction_lookup
@@ -66,8 +65,8 @@ class Approximator(ABC):
66
65
  top_order: bool,
67
66
  min_order: int = 0,
68
67
  pairing_trick: bool = False,
69
- sampling_weights: Optional[np.ndarray[float]] = None,
70
- random_state: Optional[int] = None,
68
+ sampling_weights: np.ndarray[float] | None = None,
69
+ random_state: int | None = None,
71
70
  ) -> None:
72
71
  # check if index can be approximated
73
72
  self.index: str = index
@@ -92,8 +91,8 @@ class Approximator(ABC):
92
91
  )
93
92
 
94
93
  # 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)
94
+ self._random_state: int | None = random_state
95
+ self._rng: np.random.Generator | None = np.random.default_rng(seed=self._random_state)
97
96
 
98
97
  # set up a coalition sampler
99
98
  self._big_M: int = 100_000_000 # large number for sampling weights
@@ -110,7 +109,7 @@ class Approximator(ABC):
110
109
  self, budget: int, game: Callable[[np.ndarray], np.ndarray], *args, **kwargs
111
110
  ) -> InteractionValues:
112
111
  """Calls the approximate method."""
113
- return self.approximate(budget, game, *args, **kwargs)
112
+ return self.approximate(budget=budget, game=game, *args, **kwargs)
114
113
 
115
114
  @abstractmethod
116
115
  def approximate(
@@ -129,7 +128,9 @@ class Approximator(ABC):
129
128
  Raises:
130
129
  NotImplementedError: If the method is not implemented.
131
130
  """
132
- raise NotImplementedError("The approximate method needs to be implemented.")
131
+ raise NotImplementedError(
132
+ "The approximate method must be implemented in the subclass."
133
+ ) # pragma: no cover
133
134
 
134
135
  def _init_sampling_weights(self) -> np.ndarray:
135
136
  """Initializes the weights for sampling subsets.
@@ -141,13 +142,29 @@ class Approximator(ABC):
141
142
  The weights for sampling subsets of size ``s`` in shape ``(n + 1,)``.
142
143
  """
143
144
  weight_vector = np.zeros(shape=self.n + 1)
144
- for coalition_size in range(0, self.n + 1):
145
- if (coalition_size < self.max_order) or (coalition_size > self.n - self.max_order):
146
- # prioritize these subsets
147
- weight_vector[coalition_size] = self._big_M
148
- else:
149
- # KernelSHAP sampling weights
150
- weight_vector[coalition_size] = 1 / (coalition_size * (self.n - coalition_size))
145
+ if self.index in ["FBII"]:
146
+
147
+ try:
148
+ for coalition_size in range(0, self.n + 1):
149
+ weight_vector[coalition_size] = binom(self.n, coalition_size) / 2**self.n
150
+ except OverflowError:
151
+ for coalition_size in range(0, self.n + 1):
152
+ weight_vector[coalition_size] = (
153
+ 1
154
+ / np.sqrt(2 * np.pi * 0.5)
155
+ * np.exp(-(coalition_size - self.n / 2) * +2 / (self.n / 2))
156
+ )
157
+ warnings.warn(
158
+ "The weights are approximated for n > 1000. While this is very close to the truth for sets for size in the region n/2, the approximation is not exact for size n or 0."
159
+ )
160
+ else:
161
+ for coalition_size in range(0, self.n + 1):
162
+ if (coalition_size < self.max_order) or (coalition_size > self.n - self.max_order):
163
+ # prioritize these subsets
164
+ weight_vector[coalition_size] = self._big_M
165
+ else:
166
+ # KernelSHAP sampling weights
167
+ weight_vector[coalition_size] = 1 / (coalition_size * (self.n - coalition_size))
151
168
  sampling_weight = weight_vector / np.sum(weight_vector)
152
169
  return sampling_weight
153
170
 
@@ -173,65 +190,6 @@ class Approximator(ABC):
173
190
  """
174
191
  return range(self.min_order, self.max_order + 1)
175
192
 
176
- def _finalize_result(
177
- self,
178
- result,
179
- baseline_value: float,
180
- *,
181
- estimated: Optional[bool] = None,
182
- budget: Optional[int] = None,
183
- ) -> InteractionValues:
184
- """Finalizes the result dictionary.
185
-
186
- Args:
187
- result: Interaction values.
188
- baseline_value: Baseline value.
189
- estimated: Whether interaction values were estimated.
190
- budget: The budget for the approximation.
191
-
192
- Returns:
193
- The interaction values.
194
-
195
- Raises:
196
- ValueError: If the baseline value is not provided for SII and k-SII.
197
- """
198
-
199
- if budget is None: # try to get budget from sampler
200
- budget = self._sampler.n_coalitions
201
- if budget == 0:
202
- raise ValueError("Budget is 0. Cannot finalize interaction values.")
203
- # Note to developer: This should not happen, the finalize method should be called
204
- # with a valid budget.
205
-
206
- if estimated is None:
207
- estimated = False if budget >= 2**self.n else True
208
-
209
- # set empty value as baseline value if necessary
210
- if tuple() in self._interaction_lookup:
211
- idx = self._interaction_lookup[tuple()]
212
- empty_value = result[idx]
213
- # only for SII empty value is not the baseline value
214
- if empty_value != baseline_value and is_empty_value_the_baseline(self.index):
215
- result[idx] = baseline_value
216
-
217
- interactions = InteractionValues(
218
- values=result,
219
- estimated=estimated,
220
- estimation_budget=budget,
221
- index=self.approximation_index, # can be different from self.index
222
- min_order=self.min_order,
223
- max_order=self.max_order,
224
- n_players=self.n,
225
- interaction_lookup=copy.deepcopy(self.interaction_lookup),
226
- baseline_value=baseline_value,
227
- )
228
-
229
- # if index needs to be aggregated
230
- if is_index_aggregated(self.index):
231
- interactions = self.aggregate_interaction_values(interactions)
232
-
233
- return interactions
234
-
235
193
  @staticmethod
236
194
  def _calc_iteration_count(budget: int, batch_size: int, iteration_cost: int) -> tuple[int, int]:
237
195
  """Computes the number of iterations and the size of the last batch given the batch size and
@@ -303,8 +261,7 @@ class Approximator(ABC):
303
261
  @staticmethod
304
262
  def aggregate_interaction_values(
305
263
  base_interactions: InteractionValues,
306
- order: Optional[int] = None,
307
- player_set: Optional[set[int]] = None,
264
+ order: int | None = None,
308
265
  ) -> InteractionValues:
309
266
  """Aggregates the interaction values.
310
267
 
@@ -312,33 +269,10 @@ class Approximator(ABC):
312
269
  base_interactions: The base interaction values to aggregate.
313
270
  order: The order of the aggregation. For example, the order of the k-SII aggregation.
314
271
  If ``None`` (default), the maximum order of the base interactions is used.
315
- player_set: The set of players to consider for the aggregation. If ``None`` (default),
316
- all players are considered.
317
272
 
318
273
  Returns:
319
274
  The aggregated interaction values.
320
275
  """
321
- from shapiq.game_theory.aggregation import aggregate_interaction_values
322
-
323
- if player_set is not None:
324
- raise NotImplementedError(
325
- "Aggregating interaction values for a subset of players is not implemented."
326
- )
327
-
328
- return aggregate_interaction_values(base_interactions, order=order)
329
-
330
- @staticmethod
331
- def aggregate_to_one_dimension(
332
- interaction_values: InteractionValues,
333
- ) -> tuple[np.ndarray, np.ndarray]:
334
- """Aggregates the interaction values to one dimension.
335
-
336
- Args:
337
- interaction_values: The interaction values to aggregate.
338
-
339
- Returns:
340
- tuple[np.ndarray, np.ndarray]: The positive and negative aggregated values.
341
- """
342
- from shapiq.game_theory.aggregation import aggregate_to_one_dimension
276
+ from shapiq.game_theory.aggregation import aggregate_base_interaction
343
277
 
344
- return aggregate_to_one_dimension(interaction_values)
278
+ return aggregate_base_interaction(base_interactions, order=order)