Skip to content

HyperSHAP

HyperSHAP main interface to work on explanation for a given task.

This module provides the main interface for working with HyperSHAP to access explanations regarding ablation, tunability, sensitivity, and optimizer bias.

HyperSHAP

A class for computing and visualizing HyperSHAP Shapley values and interactions.

Attributes:

Name Type Description
explanation_task ExplanationTask

The task responsible for generating explanations.

last_interaction_values InteractionValues | None

The cached interaction values for plotting shortcuts.

Methods:

Name Description
__init__

ExplanationTask): Initializes the HyperSHAP instance with an explanation task.

ablation

Configuration, baseline_config: Configuration, index: str = "FSII", order: int = 2) -> InteractionValues: Computes and returns the interaction values for ablation analysis.

tunability

Configuration | None, index: str = "FSII", order: int = 2) -> InteractionValues: Computes and returns the interaction values for tunability analysis.

optimizer_bias

ConfigSpaceSearcher, optimizer_ensemble: list[ConfigSpaceSearcher], index: str = "FSII", order: int = 2) -> InteractionValues: Computes and returns the interaction values for optimizer bias analysis.

plot_si_graph

InteractionValues | None = None, save_path: str | None = None): Plots the SHAP interaction values as a graph.

Source code in src/hypershap/hypershap.py
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
class HyperSHAP:
    """A class for computing and visualizing HyperSHAP Shapley values and interactions.

    Attributes:
        explanation_task (ExplanationTask): The task responsible for generating explanations.
        last_interaction_values (InteractionValues | None): The cached interaction values for plotting shortcuts.

    Methods:
        __init__(explanation_task: ExplanationTask):
            Initializes the HyperSHAP instance with an explanation task.

        ablation(config_of_interest: Configuration, baseline_config: Configuration, index: str = "FSII", order: int = 2) -> InteractionValues:
            Computes and returns the interaction values for ablation analysis.

        tunability(baseline_config: Configuration | None, index: str = "FSII", order: int = 2) -> InteractionValues:
            Computes and returns the interaction values for tunability analysis.

        optimizer_bias(optimizer_of_interest: ConfigSpaceSearcher, optimizer_ensemble: list[ConfigSpaceSearcher], index: str = "FSII", order: int = 2) -> InteractionValues:
            Computes and returns the interaction values for optimizer bias analysis.

        plot_si_graph(interaction_values: InteractionValues | None = None, save_path: str | None = None):
            Plots the SHAP interaction values as a graph.

    """

    def __init__(
        self,
        explanation_task: ExplanationTask,
        n_workers: int | None = None,
        max_hyperparameters_exact: int | None = None,
        approximation_budget: int | None = None,
        verbose: bool | None = None,
    ) -> None:
        """Initialize the HyperSHAP instance with an explanation task.

        Args:
            explanation_task (ExplanationTask): The task responsible for generating explanations.
            n_workers: The number of worker threads to use for parallel evaluation
                of coalitions. Defaults to None meaning no parallelization.  Using more workers can significantly
                speed up the computation of Shapley values.  The maximum number of workers is capped by the number of coalitions.
            max_hyperparameters_exact: The maximum number of hyperparameters to compute exactly. Defaults to 14. If this number of
                hyperparameters is exceeded, the Shapley values and interactions will be approximated by a sampling method with a
                budget set via `approximation_budget`.
            approximation_budget: The budget to be used for approximating Shapley values when the number of hyperparameters exceeds
                the maximum number of hyperparameters for computing exact values. Defaults to 2**14.
            verbose:  A boolean indicating whether to print verbose messages during
                computation. Defaults to None.  When set to True, the method prints
                debugging information and progress updates.

        """
        self.explanation_task = explanation_task
        self.last_interaction_values = None
        self.n_workers = n_workers
        self.max_hyperparameters_exact = (
            max_hyperparameters_exact if max_hyperparameters_exact is not None else EXACT_MAX_HYPERPARAMETERS
        )
        self.approximation_budget = (
            approximation_budget if approximation_budget is not None else 2**EXACT_MAX_HYPERPARAMETERS
        )
        self.verbose = verbose

    def __get_interaction_values(self, game: AbstractHPIGame, index: str = "FSII", order: int = 2) -> InteractionValues:
        if game.n_players <= EXACT_MAX_HYPERPARAMETERS:
            # instantiate exact computer if number of hyperparameters is small enough
            ec = ExactComputer(n_players=game.get_num_hyperparameters(), game=game)  # pyright: ignore

            # compute interaction values with the given index and order
            interaction_values = ec(index=index, order=order)
        else:
            # instantiate kernel
            if index == "FSII":
                approx = SHAPIQ(n=game.n_players, max_order=2, index=index)
            else:
                approx = KernelSHAPIQ(n=game.n_players, max_order=2, index=index)

            # approximate interaction values with the given index and order
            interaction_values = approx(budget=self.approximation_budget, game=game)

        # cache current interaction values for plotting shortcuts
        self.last_interaction_values = interaction_values

        return interaction_values

    def ablation(
        self,
        config_of_interest: Configuration,
        baseline_config: Configuration,
        index: str = "FSII",
        order: int = 2,
    ) -> InteractionValues:
        """Compute and return the interaction values for ablation analysis.

        Args:
            config_of_interest (Configuration): The configuration of interest.
            baseline_config (Configuration): The baseline configuration.
            index (str, optional): The index to use for computing interaction values. Defaults to "FSII".
            order (int, optional): The order of the interaction values. Defaults to 2.

        Returns:
            InteractionValues: The computed interaction values.

        """
        # setup explanation task
        if isinstance(self.explanation_task.surrogate_model, list):
            surrogate_model = self.explanation_task.surrogate_model[0]
        else:
            surrogate_model = self.explanation_task.surrogate_model

        ablation_task: AblationExplanationTask = AblationExplanationTask(
            config_space=self.explanation_task.config_space,
            surrogate_model=surrogate_model,
            baseline_config=baseline_config,
            config_of_interest=config_of_interest,
        )

        # setup ablation game and get interaction values
        ag = AblationGame(
            explanation_task=ablation_task,
            n_workers=self.n_workers,
            verbose=self.verbose,
        )

        if self.explanation_task.is_multi_data():
            ag = MultiDataHPIGame(
                explanation_task=self.explanation_task,
                base_game=ag,
                aggregation=Aggregation.AVG,
            )

        return self.__get_interaction_values(game=ag, index=index, order=order)

    def ablation_multibaseline(
        self,
        config_of_interest: Configuration,
        baseline_configs: list[Configuration],
        aggregation: Aggregation = Aggregation.AVG,
        index: str = "FSII",
        order: int = 2,
    ) -> InteractionValues:
        """Compute and return the interaction values for multi-baseline ablation analysis.

        Args:
            config_of_interest (Configuration): The configuration of interest.
            baseline_configs (list[Configuration]): The list of baseline configurations.
            aggregation (Aggregation): The aggregation method to use for computing interaction values.
            index (str, optional): The index to use for computing interaction values. Defaults to "FSII".
            order (int, optional): The order of the interaction values. Defaults to 2.

        Returns:
            InteractionValues: The computed interaction values.

        """
        if isinstance(self.explanation_task.surrogate_model, list):
            surrogate_model = self.explanation_task.surrogate_model[0]
        else:
            surrogate_model = self.explanation_task.surrogate_model

        # setup explanation task
        multibaseline_ablation_task = MultiBaselineAblationExplanationTask(
            config_space=self.explanation_task.config_space,
            surrogate_model=surrogate_model,
            baseline_configs=baseline_configs,
            config_of_interest=config_of_interest,
        )

        # setup ablation game and get interaction values
        ag = MultiBaselineAblationGame(
            explanation_task=multibaseline_ablation_task,
            aggregation=aggregation,
            n_workers=self.n_workers,
            verbose=self.verbose,
        )

        if self.explanation_task.is_multi_data():
            ag = MultiDataHPIGame(
                explanation_task=self.explanation_task,
                base_game=ag,
                aggregation=Aggregation.AVG,
            )

        return self.__get_interaction_values(game=ag, index=index, order=order)

    def tunability(
        self,
        baseline_config: Configuration | None = None,
        index: str = "FSII",
        order: int = 2,
        n_samples: int = 10_000,
    ) -> InteractionValues:
        """Compute and return the interaction values for tunability analysis.

        Args:
            baseline_config (Configuration | None, optional): The baseline configuration. Defaults to None.
            index (str, optional): The index to use for computing interaction values. Defaults to "FSII".
            order (int, optional): The order of the interaction values. Defaults to 2.
            n_samples (int, optional): The number of samples to use for simulating HPO. Defaults to 10_000.

        Returns:
            InteractionValues: The computed interaction values.

        """
        if baseline_config is None:
            baseline_config = self.explanation_task.config_space.get_default_configuration()

        if isinstance(self.explanation_task.surrogate_model, list):
            surrogate_model = self.explanation_task.surrogate_model[0]
        else:
            surrogate_model = self.explanation_task.surrogate_model

        # setup explanation task
        tunability_task: TunabilityExplanationTask = TunabilityExplanationTask(
            config_space=self.explanation_task.config_space,
            surrogate_model=surrogate_model,
            baseline_config=baseline_config,
        )

        # setup tunability game and get interaction values
        tg = TunabilityGame(
            explanation_task=tunability_task,
            cs_searcher=RandomConfigSpaceSearcher(
                explanation_task=tunability_task,
                n_samples=n_samples,
                mode=Aggregation.MAX,
            ),
            n_workers=self.n_workers,
            verbose=self.verbose,
        )

        if self.explanation_task.is_multi_data():
            tg = MultiDataHPIGame(
                explanation_task=self.explanation_task,
                base_game=tg,
                aggregation=Aggregation.AVG,
            )

        return self.__get_interaction_values(game=tg, index=index, order=order)

    def sensitivity(
        self,
        baseline_config: Configuration | None = None,
        index: str = "FSII",
        order: int = 2,
        n_samples: int = 10_000,
    ) -> InteractionValues:
        """Compute and return the interaction values for sensitivity analysis.

        Args:
            baseline_config (Configuration | None, optional): The baseline configuration. Defaults to None.
            index (str, optional): The index to use for computing interaction values. Defaults to "FSII".
            order (int, optional): The order of the interaction values. Defaults to 2.
            n_samples (int, optional): The number of samples to use for simulating HPO. Defaults to 10_000.

        Returns:
            InteractionValues: The computed interaction values.

        """
        if baseline_config is None:
            baseline_config = self.explanation_task.config_space.get_default_configuration()

        if isinstance(self.explanation_task.surrogate_model, list):
            surrogate_model = self.explanation_task.surrogate_model[0]
        else:
            surrogate_model = self.explanation_task.surrogate_model

        # setup explanation task
        sensitivity_task: SensitivityExplanationTask = SensitivityExplanationTask(
            config_space=self.explanation_task.config_space,
            surrogate_model=surrogate_model,
            baseline_config=baseline_config,
        )

        # setup tunability game and get interaction values
        tg = SensitivityGame(
            explanation_task=sensitivity_task,
            cs_searcher=RandomConfigSpaceSearcher(
                explanation_task=sensitivity_task,
                n_samples=n_samples,
                mode=Aggregation.VAR,
            ),
            n_workers=self.n_workers,
            verbose=self.verbose,
        )

        if self.explanation_task.is_multi_data():
            tg = MultiDataHPIGame(
                explanation_task=self.explanation_task,
                base_game=tg,
                aggregation=Aggregation.AVG,
            )

        return self.__get_interaction_values(game=tg, index=index, order=order)

    def mistunability(
        self,
        baseline_config: Configuration | None = None,
        index: str = "FSII",
        order: int = 2,
        n_samples: int = 10_000,
    ) -> InteractionValues:
        """Compute and return the interaction values for mistunability analysis.

        Args:
            baseline_config (Configuration | None, optional): The baseline configuration. Defaults to None.
            index (str, optional): The index to use for computing interaction values. Defaults to "FSII".
            order (int, optional): The order of the interaction values. Defaults to 2.
            n_samples (int, optional): The number of samples to use for simulating HPO. Defaults to 10_000.

        Returns:
            InteractionValues: The computed interaction values.

        """
        if baseline_config is None:
            baseline_config = self.explanation_task.config_space.get_default_configuration()

        if isinstance(self.explanation_task.surrogate_model, list):
            surrogate_model = self.explanation_task.surrogate_model[0]
        else:
            surrogate_model = self.explanation_task.surrogate_model

        # setup explanation task
        mistunability_task: MistunabilityExplanationTask = MistunabilityExplanationTask(
            config_space=self.explanation_task.config_space,
            surrogate_model=surrogate_model,
            baseline_config=baseline_config,
        )

        # setup tunability game and get interaction values
        tg = MistunabilityGame(
            explanation_task=mistunability_task,
            cs_searcher=RandomConfigSpaceSearcher(
                explanation_task=mistunability_task,
                n_samples=n_samples,
                mode=Aggregation.MIN,
            ),
            n_workers=self.n_workers,
            verbose=self.verbose,
        )

        if self.explanation_task.is_multi_data():
            tg = MultiDataHPIGame(
                explanation_task=self.explanation_task,
                base_game=tg,
                aggregation=Aggregation.AVG,
            )
        return self.__get_interaction_values(game=tg, index=index, order=order)

    def optimizer_bias(
        self,
        optimizer_of_interest: ConfigSpaceSearcher,
        optimizer_ensemble: list[ConfigSpaceSearcher],
        index: str = "FSII",
        order: int = 2,
    ) -> InteractionValues:
        """Compute and return the interaction values for optimizer bias analysis.

        Args:
            optimizer_of_interest (ConfigSpaceSearcher): The optimizer of interest.
            optimizer_ensemble (list[ConfigSpaceSearcher]): The ensemble of optimizers.
            index (str, optional): The index to use for computing interaction values. Defaults to "FSII".
            order (int, optional): The order of the interaction values. Defaults to 2.

        Returns:
            InteractionValues: The computed interaction values.

        """
        # setup explanation task
        optimizer_bias_task: OptimizerBiasExplanationTask = OptimizerBiasExplanationTask(
            config_space=self.explanation_task.config_space,
            surrogate_model=self.explanation_task.surrogate_model,
            optimizer_of_interest=optimizer_of_interest,
            optimizer_ensemble=optimizer_ensemble,
        )

        # setup optimizer bias game and get interaction values
        og = OptimizerBiasGame(explanation_task=optimizer_bias_task, n_workers=self.n_workers, verbose=self.verbose)
        return self.__get_interaction_values(game=og, index=index, order=order)

    def get_interaction_values_with_names(self, iv: InteractionValues | None = None) -> dict[tuple, float]:
        """Get the interaction values provided as argument or the last interaction values as a dict of hyperparameter names and their interaction values.

        Args:
            iv (InteractionValues | None): The interaction values to compute with.

        Returns:
            dict[Tuple, float]: A dictionary with a tuples of hyperparameter names as keys mapping to their interaction values.

        """
        # prioritize given iv's over last interaction values stored in the object
        iv = iv if iv is not None else self.last_interaction_values

        # check whether we now have actually interaction values if not: nothing to get here
        if not isinstance(iv, InteractionValues):  # pragma: no cover
            raise TypeError  # pragma: no cover

        iv_mapped = {}
        for key, value in iv.dict_values.items():
            names = []
            if len(key) == 0:
                iv_mapped[()] = value
                continue
            names = [self.explanation_task.get_hyperparameter_names()[k] for k in key]
            iv_mapped[tuple(names)] = value
        return iv_mapped

    def plot_si_graph(
        self,
        interaction_values: InteractionValues | None = None,
        save_path: str | None = None,
        no_show: bool | None = None,
    ) -> None:
        """Plot the SHAP interaction values as a graph.

        Args:
            interaction_values (InteractionValues | None, optional): The interaction values to plot. Defaults to None.
            save_path (str | None, optional): The path to save the plot. Defaults to None.
            no_show (bool | None, optional): Do not show the plot if set to true. Defaults to None.

        """
        if interaction_values is None and self.last_interaction_values is None:
            raise NoInteractionValuesError

        # if given interaction values use those, else use cached interaction values
        iv = interaction_values if interaction_values is not None else self.last_interaction_values

        if not isinstance(iv, InteractionValues):  # pragma: no cover
            raise TypeError  # pragma: no cover

        hyperparameter_names = self.explanation_task.get_hyperparameter_names()

        def get_circular_layout(n_players: int) -> dict:
            original_graph, graph_nodes = nx.Graph(), []
            for i in range(n_players):
                original_graph.add_node(i, label=i)
                graph_nodes.append(i)
            return nx.circular_layout(original_graph)

        pos = get_circular_layout(n_players=self.explanation_task.get_num_hyperparameters())
        iv.plot_si_graph(
            show=False,
            size_factor=3.0,
            feature_names=hyperparameter_names,
            pos=pos,
            n_interactions=1_000,
            compactness=1e50,
        )
        plt.tight_layout()

        if save_path is not None:
            plt.savefig(save_path)
            logger.info("Saved SI graph to %s", save_path)

        if no_show is None or not no_show:  # pragma: no cover
            plt.show()  # pragma: no cover

    def plot_upset(
        self,
        interaction_values: InteractionValues | None = None,
        save_path: str | None = None,
        no_show: bool | None = None,
    ) -> None:
        """Plot the SHAP interaction values as an upset plot graph.

        Args:
            interaction_values (InteractionValues | None, optional): The interaction values to plot. Defaults to None.
            save_path (str | None, optional): The path to save the plot. Defaults to None.
            no_show (bool | None, optional): Do not show the plot if set to true. Defaults to None.

        """
        if interaction_values is None and self.last_interaction_values is None:
            raise NoInteractionValuesError

        # if given interaction values use those, else use cached interaction values
        iv = interaction_values if interaction_values is not None else self.last_interaction_values

        if not isinstance(iv, InteractionValues):  # pragma: no cover
            raise TypeError  # pragma: no cover

        hyperparameter_names = self.explanation_task.get_hyperparameter_names()

        fig = iv.plot_upset(feature_names=hyperparameter_names, show=False)

        if fig is None:  # pragma: no cover
            raise TypeError  # pragma: no cover

        ax = fig.get_axes()[0]
        ax.set_ylabel("Performance Gain")
        # also add "parameter" to the y-axis label
        ax = fig.get_axes()[1]
        ax.set_ylabel("Hyperparameter")

        plt.tight_layout()

        if save_path is not None:
            plt.savefig(save_path)

        if no_show is None or not no_show:  # pragma: no cover
            plt.show()  # pragma: no cover

    def plot_force(
        self,
        interaction_values: InteractionValues | None = None,
        save_path: str | None = None,
        no_show: bool | None = None,
    ) -> None:
        """Plot the SHAP interaction values as a forceplot graph.

        Args:
            interaction_values: Interaction values to plot. Defaults to None.
            save_path: The path to save the plot. Defaults to None.
            no_show (bool | None, optional): Do not show the plot if set to true. Defaults to None.

        """
        if interaction_values is None and self.last_interaction_values is None:
            raise NoInteractionValuesError

        # if given interaction values use those, else use cached interaction values
        iv = interaction_values if interaction_values is not None else self.last_interaction_values

        if not isinstance(iv, InteractionValues):  # pragma: no cover
            raise TypeError  # pragma: no cover

        hyperparameter_names = self.explanation_task.get_hyperparameter_names()

        iv.plot_force(feature_names=np.array(hyperparameter_names), show=False)
        plt.tight_layout()

        if save_path is not None:
            plt.savefig(save_path)

        if no_show is None or not no_show:  # pragma: no cover
            plt.show()  # pragma: no cover

    def plot_waterfall(
        self,
        interaction_values: InteractionValues | None = None,
        save_path: str | None = None,
        no_show: bool | None = None,
    ) -> None:
        """Plot the SHAP interaction values as a waterfall graph.

        Args:
            interaction_values: Interaction values to plot. Defaults to None.
            save_path: The path to save the plot. Defaults to None.
            no_show (bool | None, optional): Do not show the plot if set to true. Defaults to None.

        """
        if interaction_values is None and self.last_interaction_values is None:
            raise NoInteractionValuesError

        # if given interaction values use those, else use cached interaction values
        iv = interaction_values if interaction_values is not None else self.last_interaction_values

        if not isinstance(iv, InteractionValues):  # pragma: no cover
            raise TypeError  # pragma: no cover

        hyperparameter_names = self.explanation_task.get_hyperparameter_names()

        iv.plot_waterfall(feature_names=np.array(hyperparameter_names), show=False)
        plt.tight_layout()

        if save_path is not None:
            plt.savefig(save_path)

        if no_show is None or not no_show:  # pragma: no cover
            plt.show()  # pragma: no cover

    def plot_stacked_bar(
        self,
        interaction_values: InteractionValues | None = None,
        save_path: str | None = None,
        no_show: bool | None = None,
    ) -> None:
        """Plot the SHAP interaction values as a stacked bar chart.

        Args:
            interaction_values: Interaction values to plot. Defaults to None.
            save_path: The path to save the plot. Defaults to None.
            no_show (bool | None, optional): Do not show the plot if set to true. Defaults to None.

        """
        if interaction_values is None and self.last_interaction_values is None:
            raise NoInteractionValuesError

        # if given interaction values use those, else use cached interaction values
        iv = interaction_values if interaction_values is not None else self.last_interaction_values

        if not isinstance(iv, InteractionValues):  # pragma: no cover
            raise TypeError  # pragma: no cover

        hyperparameter_names = self.explanation_task.get_hyperparameter_names()

        iv.plot_stacked_bar(feature_names=np.array(hyperparameter_names), show=False)
        plt.tight_layout()

        if save_path is not None:
            plt.savefig(save_path)

        if no_show is None or not no_show:  # pragma: no cover
            plt.show()  # pragma: no cover

__init__(explanation_task, n_workers=None, max_hyperparameters_exact=None, approximation_budget=None, verbose=None)

Initialize the HyperSHAP instance with an explanation task.

Parameters:

Name Type Description Default
explanation_task ExplanationTask

The task responsible for generating explanations.

required
n_workers int | None

The number of worker threads to use for parallel evaluation of coalitions. Defaults to None meaning no parallelization. Using more workers can significantly speed up the computation of Shapley values. The maximum number of workers is capped by the number of coalitions.

None
max_hyperparameters_exact int | None

The maximum number of hyperparameters to compute exactly. Defaults to 14. If this number of hyperparameters is exceeded, the Shapley values and interactions will be approximated by a sampling method with a budget set via approximation_budget.

None
approximation_budget int | None

The budget to be used for approximating Shapley values when the number of hyperparameters exceeds the maximum number of hyperparameters for computing exact values. Defaults to 2**14.

None
verbose bool | None

A boolean indicating whether to print verbose messages during computation. Defaults to None. When set to True, the method prints debugging information and progress updates.

None
Source code in src/hypershap/hypershap.py
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
def __init__(
    self,
    explanation_task: ExplanationTask,
    n_workers: int | None = None,
    max_hyperparameters_exact: int | None = None,
    approximation_budget: int | None = None,
    verbose: bool | None = None,
) -> None:
    """Initialize the HyperSHAP instance with an explanation task.

    Args:
        explanation_task (ExplanationTask): The task responsible for generating explanations.
        n_workers: The number of worker threads to use for parallel evaluation
            of coalitions. Defaults to None meaning no parallelization.  Using more workers can significantly
            speed up the computation of Shapley values.  The maximum number of workers is capped by the number of coalitions.
        max_hyperparameters_exact: The maximum number of hyperparameters to compute exactly. Defaults to 14. If this number of
            hyperparameters is exceeded, the Shapley values and interactions will be approximated by a sampling method with a
            budget set via `approximation_budget`.
        approximation_budget: The budget to be used for approximating Shapley values when the number of hyperparameters exceeds
            the maximum number of hyperparameters for computing exact values. Defaults to 2**14.
        verbose:  A boolean indicating whether to print verbose messages during
            computation. Defaults to None.  When set to True, the method prints
            debugging information and progress updates.

    """
    self.explanation_task = explanation_task
    self.last_interaction_values = None
    self.n_workers = n_workers
    self.max_hyperparameters_exact = (
        max_hyperparameters_exact if max_hyperparameters_exact is not None else EXACT_MAX_HYPERPARAMETERS
    )
    self.approximation_budget = (
        approximation_budget if approximation_budget is not None else 2**EXACT_MAX_HYPERPARAMETERS
    )
    self.verbose = verbose

ablation(config_of_interest, baseline_config, index='FSII', order=2)

Compute and return the interaction values for ablation analysis.

Parameters:

Name Type Description Default
config_of_interest Configuration

The configuration of interest.

required
baseline_config Configuration

The baseline configuration.

required
index str

The index to use for computing interaction values. Defaults to "FSII".

'FSII'
order int

The order of the interaction values. Defaults to 2.

2

Returns:

Name Type Description
InteractionValues InteractionValues

The computed interaction values.

Source code in src/hypershap/hypershap.py
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
def ablation(
    self,
    config_of_interest: Configuration,
    baseline_config: Configuration,
    index: str = "FSII",
    order: int = 2,
) -> InteractionValues:
    """Compute and return the interaction values for ablation analysis.

    Args:
        config_of_interest (Configuration): The configuration of interest.
        baseline_config (Configuration): The baseline configuration.
        index (str, optional): The index to use for computing interaction values. Defaults to "FSII".
        order (int, optional): The order of the interaction values. Defaults to 2.

    Returns:
        InteractionValues: The computed interaction values.

    """
    # setup explanation task
    if isinstance(self.explanation_task.surrogate_model, list):
        surrogate_model = self.explanation_task.surrogate_model[0]
    else:
        surrogate_model = self.explanation_task.surrogate_model

    ablation_task: AblationExplanationTask = AblationExplanationTask(
        config_space=self.explanation_task.config_space,
        surrogate_model=surrogate_model,
        baseline_config=baseline_config,
        config_of_interest=config_of_interest,
    )

    # setup ablation game and get interaction values
    ag = AblationGame(
        explanation_task=ablation_task,
        n_workers=self.n_workers,
        verbose=self.verbose,
    )

    if self.explanation_task.is_multi_data():
        ag = MultiDataHPIGame(
            explanation_task=self.explanation_task,
            base_game=ag,
            aggregation=Aggregation.AVG,
        )

    return self.__get_interaction_values(game=ag, index=index, order=order)

ablation_multibaseline(config_of_interest, baseline_configs, aggregation=Aggregation.AVG, index='FSII', order=2)

Compute and return the interaction values for multi-baseline ablation analysis.

Parameters:

Name Type Description Default
config_of_interest Configuration

The configuration of interest.

required
baseline_configs list[Configuration]

The list of baseline configurations.

required
aggregation Aggregation

The aggregation method to use for computing interaction values.

AVG
index str

The index to use for computing interaction values. Defaults to "FSII".

'FSII'
order int

The order of the interaction values. Defaults to 2.

2

Returns:

Name Type Description
InteractionValues InteractionValues

The computed interaction values.

Source code in src/hypershap/hypershap.py
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
def ablation_multibaseline(
    self,
    config_of_interest: Configuration,
    baseline_configs: list[Configuration],
    aggregation: Aggregation = Aggregation.AVG,
    index: str = "FSII",
    order: int = 2,
) -> InteractionValues:
    """Compute and return the interaction values for multi-baseline ablation analysis.

    Args:
        config_of_interest (Configuration): The configuration of interest.
        baseline_configs (list[Configuration]): The list of baseline configurations.
        aggregation (Aggregation): The aggregation method to use for computing interaction values.
        index (str, optional): The index to use for computing interaction values. Defaults to "FSII".
        order (int, optional): The order of the interaction values. Defaults to 2.

    Returns:
        InteractionValues: The computed interaction values.

    """
    if isinstance(self.explanation_task.surrogate_model, list):
        surrogate_model = self.explanation_task.surrogate_model[0]
    else:
        surrogate_model = self.explanation_task.surrogate_model

    # setup explanation task
    multibaseline_ablation_task = MultiBaselineAblationExplanationTask(
        config_space=self.explanation_task.config_space,
        surrogate_model=surrogate_model,
        baseline_configs=baseline_configs,
        config_of_interest=config_of_interest,
    )

    # setup ablation game and get interaction values
    ag = MultiBaselineAblationGame(
        explanation_task=multibaseline_ablation_task,
        aggregation=aggregation,
        n_workers=self.n_workers,
        verbose=self.verbose,
    )

    if self.explanation_task.is_multi_data():
        ag = MultiDataHPIGame(
            explanation_task=self.explanation_task,
            base_game=ag,
            aggregation=Aggregation.AVG,
        )

    return self.__get_interaction_values(game=ag, index=index, order=order)

get_interaction_values_with_names(iv=None)

Get the interaction values provided as argument or the last interaction values as a dict of hyperparameter names and their interaction values.

Parameters:

Name Type Description Default
iv InteractionValues | None

The interaction values to compute with.

None

Returns:

Type Description
dict[tuple, float]

dict[Tuple, float]: A dictionary with a tuples of hyperparameter names as keys mapping to their interaction values.

Source code in src/hypershap/hypershap.py
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
def get_interaction_values_with_names(self, iv: InteractionValues | None = None) -> dict[tuple, float]:
    """Get the interaction values provided as argument or the last interaction values as a dict of hyperparameter names and their interaction values.

    Args:
        iv (InteractionValues | None): The interaction values to compute with.

    Returns:
        dict[Tuple, float]: A dictionary with a tuples of hyperparameter names as keys mapping to their interaction values.

    """
    # prioritize given iv's over last interaction values stored in the object
    iv = iv if iv is not None else self.last_interaction_values

    # check whether we now have actually interaction values if not: nothing to get here
    if not isinstance(iv, InteractionValues):  # pragma: no cover
        raise TypeError  # pragma: no cover

    iv_mapped = {}
    for key, value in iv.dict_values.items():
        names = []
        if len(key) == 0:
            iv_mapped[()] = value
            continue
        names = [self.explanation_task.get_hyperparameter_names()[k] for k in key]
        iv_mapped[tuple(names)] = value
    return iv_mapped

mistunability(baseline_config=None, index='FSII', order=2, n_samples=10000)

Compute and return the interaction values for mistunability analysis.

Parameters:

Name Type Description Default
baseline_config Configuration | None

The baseline configuration. Defaults to None.

None
index str

The index to use for computing interaction values. Defaults to "FSII".

'FSII'
order int

The order of the interaction values. Defaults to 2.

2
n_samples int

The number of samples to use for simulating HPO. Defaults to 10_000.

10000

Returns:

Name Type Description
InteractionValues InteractionValues

The computed interaction values.

Source code in src/hypershap/hypershap.py
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
def mistunability(
    self,
    baseline_config: Configuration | None = None,
    index: str = "FSII",
    order: int = 2,
    n_samples: int = 10_000,
) -> InteractionValues:
    """Compute and return the interaction values for mistunability analysis.

    Args:
        baseline_config (Configuration | None, optional): The baseline configuration. Defaults to None.
        index (str, optional): The index to use for computing interaction values. Defaults to "FSII".
        order (int, optional): The order of the interaction values. Defaults to 2.
        n_samples (int, optional): The number of samples to use for simulating HPO. Defaults to 10_000.

    Returns:
        InteractionValues: The computed interaction values.

    """
    if baseline_config is None:
        baseline_config = self.explanation_task.config_space.get_default_configuration()

    if isinstance(self.explanation_task.surrogate_model, list):
        surrogate_model = self.explanation_task.surrogate_model[0]
    else:
        surrogate_model = self.explanation_task.surrogate_model

    # setup explanation task
    mistunability_task: MistunabilityExplanationTask = MistunabilityExplanationTask(
        config_space=self.explanation_task.config_space,
        surrogate_model=surrogate_model,
        baseline_config=baseline_config,
    )

    # setup tunability game and get interaction values
    tg = MistunabilityGame(
        explanation_task=mistunability_task,
        cs_searcher=RandomConfigSpaceSearcher(
            explanation_task=mistunability_task,
            n_samples=n_samples,
            mode=Aggregation.MIN,
        ),
        n_workers=self.n_workers,
        verbose=self.verbose,
    )

    if self.explanation_task.is_multi_data():
        tg = MultiDataHPIGame(
            explanation_task=self.explanation_task,
            base_game=tg,
            aggregation=Aggregation.AVG,
        )
    return self.__get_interaction_values(game=tg, index=index, order=order)

optimizer_bias(optimizer_of_interest, optimizer_ensemble, index='FSII', order=2)

Compute and return the interaction values for optimizer bias analysis.

Parameters:

Name Type Description Default
optimizer_of_interest ConfigSpaceSearcher

The optimizer of interest.

required
optimizer_ensemble list[ConfigSpaceSearcher]

The ensemble of optimizers.

required
index str

The index to use for computing interaction values. Defaults to "FSII".

'FSII'
order int

The order of the interaction values. Defaults to 2.

2

Returns:

Name Type Description
InteractionValues InteractionValues

The computed interaction values.

Source code in src/hypershap/hypershap.py
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
def optimizer_bias(
    self,
    optimizer_of_interest: ConfigSpaceSearcher,
    optimizer_ensemble: list[ConfigSpaceSearcher],
    index: str = "FSII",
    order: int = 2,
) -> InteractionValues:
    """Compute and return the interaction values for optimizer bias analysis.

    Args:
        optimizer_of_interest (ConfigSpaceSearcher): The optimizer of interest.
        optimizer_ensemble (list[ConfigSpaceSearcher]): The ensemble of optimizers.
        index (str, optional): The index to use for computing interaction values. Defaults to "FSII".
        order (int, optional): The order of the interaction values. Defaults to 2.

    Returns:
        InteractionValues: The computed interaction values.

    """
    # setup explanation task
    optimizer_bias_task: OptimizerBiasExplanationTask = OptimizerBiasExplanationTask(
        config_space=self.explanation_task.config_space,
        surrogate_model=self.explanation_task.surrogate_model,
        optimizer_of_interest=optimizer_of_interest,
        optimizer_ensemble=optimizer_ensemble,
    )

    # setup optimizer bias game and get interaction values
    og = OptimizerBiasGame(explanation_task=optimizer_bias_task, n_workers=self.n_workers, verbose=self.verbose)
    return self.__get_interaction_values(game=og, index=index, order=order)

plot_force(interaction_values=None, save_path=None, no_show=None)

Plot the SHAP interaction values as a forceplot graph.

Parameters:

Name Type Description Default
interaction_values InteractionValues | None

Interaction values to plot. Defaults to None.

None
save_path str | None

The path to save the plot. Defaults to None.

None
no_show bool | None

Do not show the plot if set to true. Defaults to None.

None
Source code in src/hypershap/hypershap.py
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
def plot_force(
    self,
    interaction_values: InteractionValues | None = None,
    save_path: str | None = None,
    no_show: bool | None = None,
) -> None:
    """Plot the SHAP interaction values as a forceplot graph.

    Args:
        interaction_values: Interaction values to plot. Defaults to None.
        save_path: The path to save the plot. Defaults to None.
        no_show (bool | None, optional): Do not show the plot if set to true. Defaults to None.

    """
    if interaction_values is None and self.last_interaction_values is None:
        raise NoInteractionValuesError

    # if given interaction values use those, else use cached interaction values
    iv = interaction_values if interaction_values is not None else self.last_interaction_values

    if not isinstance(iv, InteractionValues):  # pragma: no cover
        raise TypeError  # pragma: no cover

    hyperparameter_names = self.explanation_task.get_hyperparameter_names()

    iv.plot_force(feature_names=np.array(hyperparameter_names), show=False)
    plt.tight_layout()

    if save_path is not None:
        plt.savefig(save_path)

    if no_show is None or not no_show:  # pragma: no cover
        plt.show()  # pragma: no cover

plot_si_graph(interaction_values=None, save_path=None, no_show=None)

Plot the SHAP interaction values as a graph.

Parameters:

Name Type Description Default
interaction_values InteractionValues | None

The interaction values to plot. Defaults to None.

None
save_path str | None

The path to save the plot. Defaults to None.

None
no_show bool | None

Do not show the plot if set to true. Defaults to None.

None
Source code in src/hypershap/hypershap.py
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
def plot_si_graph(
    self,
    interaction_values: InteractionValues | None = None,
    save_path: str | None = None,
    no_show: bool | None = None,
) -> None:
    """Plot the SHAP interaction values as a graph.

    Args:
        interaction_values (InteractionValues | None, optional): The interaction values to plot. Defaults to None.
        save_path (str | None, optional): The path to save the plot. Defaults to None.
        no_show (bool | None, optional): Do not show the plot if set to true. Defaults to None.

    """
    if interaction_values is None and self.last_interaction_values is None:
        raise NoInteractionValuesError

    # if given interaction values use those, else use cached interaction values
    iv = interaction_values if interaction_values is not None else self.last_interaction_values

    if not isinstance(iv, InteractionValues):  # pragma: no cover
        raise TypeError  # pragma: no cover

    hyperparameter_names = self.explanation_task.get_hyperparameter_names()

    def get_circular_layout(n_players: int) -> dict:
        original_graph, graph_nodes = nx.Graph(), []
        for i in range(n_players):
            original_graph.add_node(i, label=i)
            graph_nodes.append(i)
        return nx.circular_layout(original_graph)

    pos = get_circular_layout(n_players=self.explanation_task.get_num_hyperparameters())
    iv.plot_si_graph(
        show=False,
        size_factor=3.0,
        feature_names=hyperparameter_names,
        pos=pos,
        n_interactions=1_000,
        compactness=1e50,
    )
    plt.tight_layout()

    if save_path is not None:
        plt.savefig(save_path)
        logger.info("Saved SI graph to %s", save_path)

    if no_show is None or not no_show:  # pragma: no cover
        plt.show()  # pragma: no cover

plot_stacked_bar(interaction_values=None, save_path=None, no_show=None)

Plot the SHAP interaction values as a stacked bar chart.

Parameters:

Name Type Description Default
interaction_values InteractionValues | None

Interaction values to plot. Defaults to None.

None
save_path str | None

The path to save the plot. Defaults to None.

None
no_show bool | None

Do not show the plot if set to true. Defaults to None.

None
Source code in src/hypershap/hypershap.py
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
def plot_stacked_bar(
    self,
    interaction_values: InteractionValues | None = None,
    save_path: str | None = None,
    no_show: bool | None = None,
) -> None:
    """Plot the SHAP interaction values as a stacked bar chart.

    Args:
        interaction_values: Interaction values to plot. Defaults to None.
        save_path: The path to save the plot. Defaults to None.
        no_show (bool | None, optional): Do not show the plot if set to true. Defaults to None.

    """
    if interaction_values is None and self.last_interaction_values is None:
        raise NoInteractionValuesError

    # if given interaction values use those, else use cached interaction values
    iv = interaction_values if interaction_values is not None else self.last_interaction_values

    if not isinstance(iv, InteractionValues):  # pragma: no cover
        raise TypeError  # pragma: no cover

    hyperparameter_names = self.explanation_task.get_hyperparameter_names()

    iv.plot_stacked_bar(feature_names=np.array(hyperparameter_names), show=False)
    plt.tight_layout()

    if save_path is not None:
        plt.savefig(save_path)

    if no_show is None or not no_show:  # pragma: no cover
        plt.show()  # pragma: no cover

plot_upset(interaction_values=None, save_path=None, no_show=None)

Plot the SHAP interaction values as an upset plot graph.

Parameters:

Name Type Description Default
interaction_values InteractionValues | None

The interaction values to plot. Defaults to None.

None
save_path str | None

The path to save the plot. Defaults to None.

None
no_show bool | None

Do not show the plot if set to true. Defaults to None.

None
Source code in src/hypershap/hypershap.py
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
def plot_upset(
    self,
    interaction_values: InteractionValues | None = None,
    save_path: str | None = None,
    no_show: bool | None = None,
) -> None:
    """Plot the SHAP interaction values as an upset plot graph.

    Args:
        interaction_values (InteractionValues | None, optional): The interaction values to plot. Defaults to None.
        save_path (str | None, optional): The path to save the plot. Defaults to None.
        no_show (bool | None, optional): Do not show the plot if set to true. Defaults to None.

    """
    if interaction_values is None and self.last_interaction_values is None:
        raise NoInteractionValuesError

    # if given interaction values use those, else use cached interaction values
    iv = interaction_values if interaction_values is not None else self.last_interaction_values

    if not isinstance(iv, InteractionValues):  # pragma: no cover
        raise TypeError  # pragma: no cover

    hyperparameter_names = self.explanation_task.get_hyperparameter_names()

    fig = iv.plot_upset(feature_names=hyperparameter_names, show=False)

    if fig is None:  # pragma: no cover
        raise TypeError  # pragma: no cover

    ax = fig.get_axes()[0]
    ax.set_ylabel("Performance Gain")
    # also add "parameter" to the y-axis label
    ax = fig.get_axes()[1]
    ax.set_ylabel("Hyperparameter")

    plt.tight_layout()

    if save_path is not None:
        plt.savefig(save_path)

    if no_show is None or not no_show:  # pragma: no cover
        plt.show()  # pragma: no cover

plot_waterfall(interaction_values=None, save_path=None, no_show=None)

Plot the SHAP interaction values as a waterfall graph.

Parameters:

Name Type Description Default
interaction_values InteractionValues | None

Interaction values to plot. Defaults to None.

None
save_path str | None

The path to save the plot. Defaults to None.

None
no_show bool | None

Do not show the plot if set to true. Defaults to None.

None
Source code in src/hypershap/hypershap.py
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
def plot_waterfall(
    self,
    interaction_values: InteractionValues | None = None,
    save_path: str | None = None,
    no_show: bool | None = None,
) -> None:
    """Plot the SHAP interaction values as a waterfall graph.

    Args:
        interaction_values: Interaction values to plot. Defaults to None.
        save_path: The path to save the plot. Defaults to None.
        no_show (bool | None, optional): Do not show the plot if set to true. Defaults to None.

    """
    if interaction_values is None and self.last_interaction_values is None:
        raise NoInteractionValuesError

    # if given interaction values use those, else use cached interaction values
    iv = interaction_values if interaction_values is not None else self.last_interaction_values

    if not isinstance(iv, InteractionValues):  # pragma: no cover
        raise TypeError  # pragma: no cover

    hyperparameter_names = self.explanation_task.get_hyperparameter_names()

    iv.plot_waterfall(feature_names=np.array(hyperparameter_names), show=False)
    plt.tight_layout()

    if save_path is not None:
        plt.savefig(save_path)

    if no_show is None or not no_show:  # pragma: no cover
        plt.show()  # pragma: no cover

sensitivity(baseline_config=None, index='FSII', order=2, n_samples=10000)

Compute and return the interaction values for sensitivity analysis.

Parameters:

Name Type Description Default
baseline_config Configuration | None

The baseline configuration. Defaults to None.

None
index str

The index to use for computing interaction values. Defaults to "FSII".

'FSII'
order int

The order of the interaction values. Defaults to 2.

2
n_samples int

The number of samples to use for simulating HPO. Defaults to 10_000.

10000

Returns:

Name Type Description
InteractionValues InteractionValues

The computed interaction values.

Source code in src/hypershap/hypershap.py
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
def sensitivity(
    self,
    baseline_config: Configuration | None = None,
    index: str = "FSII",
    order: int = 2,
    n_samples: int = 10_000,
) -> InteractionValues:
    """Compute and return the interaction values for sensitivity analysis.

    Args:
        baseline_config (Configuration | None, optional): The baseline configuration. Defaults to None.
        index (str, optional): The index to use for computing interaction values. Defaults to "FSII".
        order (int, optional): The order of the interaction values. Defaults to 2.
        n_samples (int, optional): The number of samples to use for simulating HPO. Defaults to 10_000.

    Returns:
        InteractionValues: The computed interaction values.

    """
    if baseline_config is None:
        baseline_config = self.explanation_task.config_space.get_default_configuration()

    if isinstance(self.explanation_task.surrogate_model, list):
        surrogate_model = self.explanation_task.surrogate_model[0]
    else:
        surrogate_model = self.explanation_task.surrogate_model

    # setup explanation task
    sensitivity_task: SensitivityExplanationTask = SensitivityExplanationTask(
        config_space=self.explanation_task.config_space,
        surrogate_model=surrogate_model,
        baseline_config=baseline_config,
    )

    # setup tunability game and get interaction values
    tg = SensitivityGame(
        explanation_task=sensitivity_task,
        cs_searcher=RandomConfigSpaceSearcher(
            explanation_task=sensitivity_task,
            n_samples=n_samples,
            mode=Aggregation.VAR,
        ),
        n_workers=self.n_workers,
        verbose=self.verbose,
    )

    if self.explanation_task.is_multi_data():
        tg = MultiDataHPIGame(
            explanation_task=self.explanation_task,
            base_game=tg,
            aggregation=Aggregation.AVG,
        )

    return self.__get_interaction_values(game=tg, index=index, order=order)

tunability(baseline_config=None, index='FSII', order=2, n_samples=10000)

Compute and return the interaction values for tunability analysis.

Parameters:

Name Type Description Default
baseline_config Configuration | None

The baseline configuration. Defaults to None.

None
index str

The index to use for computing interaction values. Defaults to "FSII".

'FSII'
order int

The order of the interaction values. Defaults to 2.

2
n_samples int

The number of samples to use for simulating HPO. Defaults to 10_000.

10000

Returns:

Name Type Description
InteractionValues InteractionValues

The computed interaction values.

Source code in src/hypershap/hypershap.py
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
def tunability(
    self,
    baseline_config: Configuration | None = None,
    index: str = "FSII",
    order: int = 2,
    n_samples: int = 10_000,
) -> InteractionValues:
    """Compute and return the interaction values for tunability analysis.

    Args:
        baseline_config (Configuration | None, optional): The baseline configuration. Defaults to None.
        index (str, optional): The index to use for computing interaction values. Defaults to "FSII".
        order (int, optional): The order of the interaction values. Defaults to 2.
        n_samples (int, optional): The number of samples to use for simulating HPO. Defaults to 10_000.

    Returns:
        InteractionValues: The computed interaction values.

    """
    if baseline_config is None:
        baseline_config = self.explanation_task.config_space.get_default_configuration()

    if isinstance(self.explanation_task.surrogate_model, list):
        surrogate_model = self.explanation_task.surrogate_model[0]
    else:
        surrogate_model = self.explanation_task.surrogate_model

    # setup explanation task
    tunability_task: TunabilityExplanationTask = TunabilityExplanationTask(
        config_space=self.explanation_task.config_space,
        surrogate_model=surrogate_model,
        baseline_config=baseline_config,
    )

    # setup tunability game and get interaction values
    tg = TunabilityGame(
        explanation_task=tunability_task,
        cs_searcher=RandomConfigSpaceSearcher(
            explanation_task=tunability_task,
            n_samples=n_samples,
            mode=Aggregation.MAX,
        ),
        n_workers=self.n_workers,
        verbose=self.verbose,
    )

    if self.explanation_task.is_multi_data():
        tg = MultiDataHPIGame(
            explanation_task=self.explanation_task,
            base_game=tg,
            aggregation=Aggregation.AVG,
        )

    return self.__get_interaction_values(game=tg, index=index, order=order)

NoInteractionValuesError

Bases: ValueError

Exception raised when no interaction values are present for plotting.

Source code in src/hypershap/hypershap.py
50
51
52
53
54
55
class NoInteractionValuesError(ValueError):
    """Exception raised when no interaction values are present for plotting."""

    def __init__(self) -> None:
        """Initialize the no interaction values error."""
        super().__init__("No interaction values present for plotting.")

__init__()

Initialize the no interaction values error.

Source code in src/hypershap/hypershap.py
53
54
55
def __init__(self) -> None:
    """Initialize the no interaction values error."""
    super().__init__("No interaction values present for plotting.")