Skip to content

Commit 2f26df6

Browse files
authored
Merge pull request #138 from mmschlk/111-add-kernel-based-sii-approximator
111 add kernel based SII approximator (closes #111, closes #32)
2 parents 629fc1a + 5912cd4 commit 2f26df6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+2532
-975
lines changed

long_runs/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
"""This module contains longer test cases that can be run if wanted. Will be removed in the future.
2+
or refactored into integration tests."""
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import numpy as np
2+
3+
from shapiq.approximator.moebius_converter import MoebiusConverter
4+
from shapiq.approximator.regression.kernelshapiq import InconsistentKernelSHAPIQ
5+
from shapiq.exact import ExactComputer
6+
from shapiq.games.benchmark import SOUM
7+
8+
9+
def test_approximator_inconsistent_kernelshapiq_sii():
10+
N_RUNS = 10
11+
LOWEST_BUDGET_PERC = 10
12+
PREV_BUDGET_PERC = 0
13+
N_BUDGET_STEPS = 5
14+
N_ITERATIONS = 5
15+
approximation_improvement_counter = 0
16+
17+
for RANDOM_STATE in range(N_RUNS):
18+
n = np.random.randint(low=6, high=8)
19+
total_budget = 2**n
20+
max_order = np.random.randint(low=1, high=n)
21+
n_basis_games = np.random.randint(low=10, high=200)
22+
soum = SOUM(n, n_basis_games=n_basis_games)
23+
index = "SII"
24+
25+
predicted_value = soum(np.ones(n))[0]
26+
27+
# For ground truth comparison - kADD-SHAP
28+
exact_computer = ExactComputer(n_players=n, game_fun=soum)
29+
kadd_shap = exact_computer.shapley_interaction(index="kADD-SHAP", order=max_order)
30+
kadd_shap.index = index
31+
kernelshapiq = InconsistentKernelSHAPIQ(n=n, max_order=max_order, index=index)
32+
33+
squared_errors = {}
34+
35+
for budget_perc in np.linspace(LOWEST_BUDGET_PERC, 100, N_BUDGET_STEPS):
36+
budget = int(budget_perc / 100 * total_budget)
37+
38+
sii_approximated = kernelshapiq.approximate(budget=budget, game=soum)
39+
for iteration in range(N_ITERATIONS - 1):
40+
sii_approximated += kernelshapiq.approximate(budget=budget, game=soum)
41+
sii_approximated *= 1 / N_ITERATIONS
42+
43+
# Assert efficiency
44+
assert (
45+
np.sum(
46+
sii_approximated.values[
47+
np.array(
48+
[
49+
pos
50+
for key, pos in sii_approximated.interaction_lookup.items()
51+
if len(key) == 1
52+
]
53+
)
54+
]
55+
)
56+
+ sii_approximated.baseline_value
57+
) - predicted_value < 10e-5
58+
59+
# Compute squared errors
60+
squared_errors[budget_perc] = np.mean(((sii_approximated - kadd_shap).values) ** 2)
61+
if PREV_BUDGET_PERC in squared_errors:
62+
approximation_improvement_counter += (
63+
squared_errors[budget_perc] < squared_errors[PREV_BUDGET_PERC]
64+
)
65+
PREV_BUDGET_PERC = budget_perc
66+
67+
# Assert 60%-ratio of improvements over previous calculation
68+
assert approximation_improvement_counter / ((N_BUDGET_STEPS - 1) * N_RUNS) >= 0.6
69+
70+
71+
def test_approximator_inconsistent_kernelshapiq_kaddshap():
72+
N_RUNS = 10
73+
74+
for RANDOM_STATE in range(N_RUNS):
75+
n = np.random.randint(low=6, high=8)
76+
budget = 2**n
77+
N = set(range(n))
78+
max_order = np.random.randint(low=1, high=n)
79+
n_basis_games = np.random.randint(low=10, high=200)
80+
soum = SOUM(n, n_basis_games=n_basis_games)
81+
index = "SII"
82+
83+
# Compute via sparse Möbius representation
84+
moebius_converter = MoebiusConverter(N, soum.moebius_coefficients)
85+
86+
sii = moebius_converter(index=index, order=max_order)
87+
sii.values[sii.interaction_lookup[tuple()]] = 0
88+
89+
# For ground truth comparison
90+
exact_computer = ExactComputer(n_players=n, game_fun=soum)
91+
kadd_shap = exact_computer.shapley_interaction(index="kADD-SHAP", order=max_order)
92+
93+
kernelshapiq = InconsistentKernelSHAPIQ(n=n, max_order=max_order, index=index)
94+
sii_approximated = kernelshapiq.approximate(budget=budget, game=soum)
95+
96+
kadd_shap.index = index
97+
squared_error = np.sum((sii_approximated - kadd_shap).values ** 2)
98+
assert squared_error < 10e-7
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import numpy as np
2+
3+
from shapiq.exact import ExactComputer
4+
from shapiq.approximator.regression.kadd_shap import kADDSHAP
5+
from shapiq.games.benchmark import SOUM
6+
7+
8+
def test_approximator_kaddshap():
9+
N_RUNS = 10
10+
LOWEST_BUDGET_PERC = 10
11+
PREV_BUDGET_PERC = 0
12+
N_BUDGET_STEPS = 5
13+
N_ITERATIONS = 5
14+
approximation_improvement_counter = 0
15+
16+
for RANDOM_STATE in range(N_RUNS):
17+
n = np.random.randint(low=6, high=8)
18+
total_budget = 2**n
19+
N = set(range(n))
20+
max_order = np.random.randint(low=1, high=n)
21+
n_basis_games = np.random.randint(low=10, high=200)
22+
soum = SOUM(n, n_basis_games=n_basis_games)
23+
index = "kADD-SHAP"
24+
25+
predicted_value = soum(np.ones(n))[0]
26+
27+
# For ground truth comparison - kADD-SHAP
28+
exact_computer = ExactComputer(n_players=n, game_fun=soum)
29+
kadd_shap = exact_computer.shapley_interaction(index="kADD-SHAP", order=max_order)
30+
31+
kadd_shap_approximator = kADDSHAP(n=n, max_order=max_order)
32+
33+
squared_errors = {}
34+
35+
for budget_perc in np.linspace(LOWEST_BUDGET_PERC, 100, N_BUDGET_STEPS):
36+
budget = int(budget_perc / 100 * total_budget)
37+
38+
sii_approximated = kadd_shap_approximator.approximate(budget=budget, game=soum)
39+
for iteration in range(N_ITERATIONS - 1):
40+
sii_approximated += kadd_shap_approximator.approximate(budget=budget, game=soum)
41+
sii_approximated *= 1 / N_ITERATIONS
42+
43+
# Assert efficiency
44+
assert (
45+
np.sum(
46+
sii_approximated.values[
47+
np.array(
48+
[
49+
pos
50+
for key, pos in sii_approximated.interaction_lookup.items()
51+
if len(key) == 1
52+
]
53+
)
54+
]
55+
)
56+
+ sii_approximated.baseline_value
57+
) - predicted_value < 10e-5
58+
59+
# Compute squared errors
60+
squared_errors[budget_perc] = np.mean(((sii_approximated - kadd_shap).values) ** 2)
61+
if PREV_BUDGET_PERC in squared_errors:
62+
approximation_improvement_counter += (
63+
squared_errors[budget_perc] < squared_errors[PREV_BUDGET_PERC]
64+
)
65+
PREV_BUDGET_PERC = budget_perc
66+
67+
# Assert exact values for 100% budget
68+
assert squared_errors[100] < 10e-7
69+
70+
# Assert 80%-ratio of improvements over previous calculation
71+
assert approximation_improvement_counter / ((N_BUDGET_STEPS - 1) * N_RUNS) >= 0.8
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import numpy as np
2+
3+
from shapiq.approximator.moebius_converter import MoebiusConverter
4+
from shapiq.approximator.regression.kernelshapiq import KernelSHAPIQ
5+
from shapiq.games.benchmark import SOUM
6+
7+
8+
def test_approximator_kernelshapiq_sii():
9+
N_RUNS = 10
10+
LOWEST_BUDGET_PERC = 10
11+
PREV_BUDGET_PERC = 0
12+
N_BUDGET_STEPS = 5
13+
N_ITERATIONS = 5
14+
approximation_improvement_counter = 0
15+
16+
for RANDOM_STATE in range(N_RUNS):
17+
n = np.random.randint(low=6, high=8)
18+
total_budget = 2**n
19+
N = set(range(n))
20+
max_order = np.random.randint(low=1, high=n)
21+
n_basis_games = np.random.randint(low=10, high=200)
22+
soum = SOUM(n, n_basis_games=n_basis_games)
23+
index = "SII"
24+
25+
predicted_value = soum(np.ones(n))[0]
26+
27+
# Compute via sparse Möbius representation
28+
moebius_converter = MoebiusConverter(N, soum.moebius_coefficients)
29+
30+
sii = moebius_converter(index=index, order=max_order)
31+
# set emptyset value to baseline
32+
sii.values[sii.interaction_lookup[tuple()]] = sii.baseline_value
33+
34+
kernelshapiq = KernelSHAPIQ(n=n, max_order=max_order, index=index)
35+
36+
squared_errors = {}
37+
38+
for budget_perc in np.linspace(LOWEST_BUDGET_PERC, 100, N_BUDGET_STEPS):
39+
budget = int(budget_perc / 100 * total_budget)
40+
41+
sii_approximated = kernelshapiq.approximate(budget=budget, game=soum)
42+
for iteration in range(N_ITERATIONS - 1):
43+
sii_approximated += kernelshapiq.approximate(budget=budget, game=soum)
44+
sii_approximated *= 1 / N_ITERATIONS
45+
46+
# test efficiency
47+
sum_of_values = (
48+
np.sum(
49+
sii_approximated.values[
50+
np.array(
51+
[
52+
pos
53+
for key, pos in sii_approximated.interaction_lookup.items()
54+
if len(key) == 1
55+
]
56+
)
57+
]
58+
)
59+
+ sii_approximated.baseline_value
60+
)
61+
assert sum_of_values - predicted_value < 10e-5
62+
63+
# Compute squared errors
64+
squared_errors[budget_perc] = np.mean((sii_approximated - sii).values ** 2)
65+
if PREV_BUDGET_PERC in squared_errors:
66+
approximation_improvement_counter += (
67+
squared_errors[budget_perc] < squared_errors[PREV_BUDGET_PERC]
68+
)
69+
PREV_BUDGET_PERC = budget_perc
70+
71+
# Assert exact values for 100% budget
72+
assert squared_errors[100] < 10e-7
73+
74+
# Assert 70%-ratio of improvements over previous calculation
75+
assert approximation_improvement_counter / ((N_BUDGET_STEPS - 1) * N_RUNS) >= 0.7
76+
77+
78+
def test_approximator_kernelshapiq_ksii():
79+
N_RUNS = 10
80+
LOWEST_BUDGET_PERC = 10
81+
PREV_BUDGET_PERC = 0
82+
N_BUDGET_STEPS = 5
83+
N_ITERATIONS = 5
84+
approximation_improvement_counter = 0
85+
86+
for RANDOM_STATE in range(N_RUNS):
87+
n = np.random.randint(low=6, high=8)
88+
total_budget = 2**n
89+
N = set(range(n))
90+
max_order = np.random.randint(low=1, high=n)
91+
n_basis_games = np.random.randint(low=10, high=200)
92+
soum = SOUM(n, n_basis_games=n_basis_games)
93+
index = "k-SII"
94+
95+
predicted_value = soum(np.ones(n))[0]
96+
97+
# Compute via sparse Möbius representation
98+
moebius_converter = MoebiusConverter(N, soum.moebius_coefficients)
99+
100+
k_sii = moebius_converter(index=index, order=max_order)
101+
102+
kernelshapiq = KernelSHAPIQ(n=n, max_order=max_order, index=index)
103+
104+
squared_errors = {}
105+
106+
for budget_perc in np.linspace(LOWEST_BUDGET_PERC, 100, N_BUDGET_STEPS):
107+
budget = int(budget_perc / 100 * total_budget)
108+
109+
sii_approximated = kernelshapiq.approximate(budget=budget, game=soum)
110+
for iteration in range(N_ITERATIONS - 1):
111+
sii_approximated += kernelshapiq.approximate(budget=budget, game=soum)
112+
sii_approximated *= 1 / N_ITERATIONS
113+
114+
# Assert efficiency
115+
assert (np.sum(sii_approximated.values)) - predicted_value < 10e-5
116+
117+
# Compute squared errors
118+
squared_errors[budget_perc] = np.mean(((sii_approximated - k_sii).values) ** 2)
119+
if PREV_BUDGET_PERC in squared_errors:
120+
approximation_improvement_counter += (
121+
squared_errors[budget_perc] < squared_errors[PREV_BUDGET_PERC]
122+
)
123+
PREV_BUDGET_PERC = budget_perc
124+
125+
# Assert exact values for 100% budget
126+
assert squared_errors[100] < 10e-7
127+
128+
# Assert 70%-ratio of improvements over previous calculation
129+
assert approximation_improvement_counter / ((N_BUDGET_STEPS - 1) * N_RUNS) >= 0.7

0 commit comments

Comments
 (0)