explainiverse 0.8.5__py3-none-any.whl → 0.8.6__py3-none-any.whl

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.
explainiverse/__init__.py CHANGED
@@ -34,7 +34,7 @@ from explainiverse.adapters.sklearn_adapter import SklearnAdapter
34
34
  from explainiverse.adapters import TORCH_AVAILABLE
35
35
  from explainiverse.engine.suite import ExplanationSuite
36
36
 
37
- __version__ = "0.8.5"
37
+ __version__ = "0.8.6"
38
38
 
39
39
  __all__ = [
40
40
  # Core
@@ -47,6 +47,8 @@ from explainiverse.evaluation.faithfulness_extended import (
47
47
  compute_batch_pixel_flipping,
48
48
  compute_region_perturbation,
49
49
  compute_batch_region_perturbation,
50
+ compute_selectivity,
51
+ compute_batch_selectivity,
50
52
  )
51
53
 
52
54
  __all__ = [
@@ -82,4 +84,6 @@ __all__ = [
82
84
  "compute_batch_pixel_flipping",
83
85
  "compute_region_perturbation",
84
86
  "compute_batch_region_perturbation",
87
+ "compute_selectivity",
88
+ "compute_batch_selectivity",
85
89
  ]
@@ -256,6 +256,204 @@ def compute_batch_faithfulness_estimate(
256
256
  }
257
257
 
258
258
 
259
+ # =============================================================================
260
+ # Metric 6: Selectivity (Montavon et al., 2018)
261
+ # =============================================================================
262
+
263
+ def compute_selectivity(
264
+ model,
265
+ instance: np.ndarray,
266
+ explanation: Explanation,
267
+ baseline: Union[str, float, np.ndarray, Callable] = "mean",
268
+ background_data: np.ndarray = None,
269
+ target_class: int = None,
270
+ n_steps: int = None,
271
+ use_absolute: bool = True,
272
+ return_details: bool = False,
273
+ ) -> Union[float, Dict[str, Union[float, np.ndarray]]]:
274
+ """
275
+ Compute Selectivity score using AOPC (Montavon et al., 2018).
276
+
277
+ Measures how quickly the prediction function drops when removing features
278
+ with the highest attributed values. Computed as the Area Over the
279
+ Perturbation Curve (AOPC), which is the average prediction drop across
280
+ all perturbation steps.
281
+
282
+ AOPC = (1/(K+1)) * Σₖ₌₀ᴷ [f(x) - f(x_{1..k})]
283
+
284
+ where:
285
+ - f(x) is the original prediction for the target class
286
+ - f(x_{1..k}) is the prediction after removing the top-k most important features
287
+ - K is the total number of perturbation steps (default: n_features)
288
+
289
+ Higher AOPC indicates better selectivity - the explanation correctly
290
+ identifies features whose removal causes the largest prediction drop.
291
+
292
+ Args:
293
+ model: Model adapter with predict/predict_proba method
294
+ instance: Input instance (1D array)
295
+ explanation: Explanation object with feature_attributions
296
+ baseline: Baseline for feature removal ("mean", "median", scalar, array, callable)
297
+ background_data: Reference data for computing baseline (required for "mean"/"median")
298
+ target_class: Target class index for probability (default: predicted class)
299
+ n_steps: Number of perturbation steps (default: n_features, max features to remove)
300
+ use_absolute: If True, sort features by absolute attribution value (default: True)
301
+ return_details: If True, return detailed results including prediction drops per step
302
+
303
+ Returns:
304
+ If return_details=False: AOPC score (float, higher is better)
305
+ If return_details=True: Dictionary with:
306
+ - 'aopc': float - Area Over the Perturbation Curve (average drop)
307
+ - 'prediction_drops': np.ndarray - Drop at each step [f(x) - f(x_{1..k})]
308
+ - 'predictions': np.ndarray - Predictions at each step
309
+ - 'feature_order': np.ndarray - Order in which features were removed
310
+ - 'n_steps': int - Number of perturbation steps
311
+
312
+ References:
313
+ Montavon, G., Samek, W., & Müller, K. R. (2018). Methods for Interpreting
314
+ and Understanding Deep Neural Networks. Digital Signal Processing, 73, 1-15.
315
+
316
+ Samek, W., Binder, A., Montavon, G., Lapuschkin, S., & Müller, K. R. (2016).
317
+ Evaluating the Visualization of What a Deep Neural Network has Learned.
318
+ IEEE Transactions on Neural Networks and Learning Systems, 28(11), 2660-2673.
319
+ """
320
+ instance = np.asarray(instance).flatten()
321
+ n_features = len(instance)
322
+
323
+ # Get baseline values
324
+ baseline_values = compute_baseline_values(
325
+ baseline, background_data, n_features
326
+ )
327
+
328
+ # Extract attributions as array
329
+ attr_array = _extract_attribution_array(explanation, n_features)
330
+
331
+ # Determine number of steps (default: all features)
332
+ if n_steps is None:
333
+ n_steps = n_features
334
+ n_steps = min(n_steps, n_features)
335
+
336
+ # Sort features by attribution (descending - most important first)
337
+ if use_absolute:
338
+ sorted_indices = np.argsort(-np.abs(attr_array))
339
+ else:
340
+ sorted_indices = np.argsort(-attr_array)
341
+
342
+ # Determine target class
343
+ if target_class is None:
344
+ pred = get_prediction_value(model, instance.reshape(1, -1))
345
+ if isinstance(pred, np.ndarray) and pred.ndim > 0:
346
+ target_class = int(np.argmax(pred))
347
+ else:
348
+ target_class = 0
349
+
350
+ # Get original prediction for the target class
351
+ original_pred = get_prediction_value(model, instance.reshape(1, -1))
352
+ if isinstance(original_pred, np.ndarray) and original_pred.ndim > 0 and len(original_pred) > target_class:
353
+ original_value = original_pred[target_class]
354
+ else:
355
+ original_value = float(original_pred)
356
+
357
+ # Start with original instance
358
+ current = instance.copy()
359
+
360
+ # Track predictions and drops at each step
361
+ # Step 0: no features removed (drop = 0)
362
+ predictions = [original_value]
363
+ prediction_drops = [0.0] # f(x) - f(x) = 0
364
+
365
+ # Remove features one by one (most important first)
366
+ for k in range(n_steps):
367
+ idx = sorted_indices[k]
368
+ # Remove this feature (replace with baseline)
369
+ current[idx] = baseline_values[idx]
370
+
371
+ # Get prediction
372
+ pred = get_prediction_value(model, current.reshape(1, -1))
373
+ if isinstance(pred, np.ndarray) and pred.ndim > 0 and len(pred) > target_class:
374
+ current_pred = pred[target_class]
375
+ else:
376
+ current_pred = float(pred)
377
+
378
+ predictions.append(current_pred)
379
+ # Prediction drop: f(x) - f(x_{1..k})
380
+ prediction_drops.append(original_value - current_pred)
381
+
382
+ predictions = np.array(predictions)
383
+ prediction_drops = np.array(prediction_drops)
384
+
385
+ # Compute AOPC: average of prediction drops across all steps
386
+ # AOPC = (1/(K+1)) * Σₖ₌₀ᴷ [f(x) - f(x_{1..k})]
387
+ aopc = np.mean(prediction_drops)
388
+
389
+ if return_details:
390
+ return {
391
+ "aopc": float(aopc),
392
+ "prediction_drops": prediction_drops,
393
+ "predictions": predictions,
394
+ "feature_order": sorted_indices[:n_steps],
395
+ "n_steps": n_steps,
396
+ "original_prediction": original_value,
397
+ }
398
+
399
+ return float(aopc)
400
+
401
+
402
+ def compute_batch_selectivity(
403
+ model,
404
+ X: np.ndarray,
405
+ explanations: List[Explanation],
406
+ baseline: Union[str, float, np.ndarray, Callable] = "mean",
407
+ max_samples: int = None,
408
+ n_steps: int = None,
409
+ use_absolute: bool = True,
410
+ ) -> Dict[str, float]:
411
+ """
412
+ Compute average Selectivity (AOPC) over a batch of instances.
413
+
414
+ Args:
415
+ model: Model adapter
416
+ X: Input data (2D array)
417
+ explanations: List of Explanation objects (one per instance)
418
+ baseline: Baseline for feature removal
419
+ max_samples: Maximum number of samples to evaluate
420
+ n_steps: Number of perturbation steps per instance
421
+ use_absolute: If True, sort features by absolute attribution value
422
+
423
+ Returns:
424
+ Dictionary with mean, std, min, max, and count of valid scores
425
+ """
426
+ n_samples = len(explanations)
427
+ if max_samples:
428
+ n_samples = min(n_samples, max_samples)
429
+
430
+ scores = []
431
+
432
+ for i in range(n_samples):
433
+ try:
434
+ score = compute_selectivity(
435
+ model, X[i], explanations[i],
436
+ baseline=baseline, background_data=X,
437
+ n_steps=n_steps,
438
+ use_absolute=use_absolute
439
+ )
440
+ if not np.isnan(score):
441
+ scores.append(score)
442
+ except Exception:
443
+ continue
444
+
445
+ if not scores:
446
+ return {"mean": 0.0, "std": 0.0, "min": 0.0, "max": 0.0, "n_samples": 0}
447
+
448
+ return {
449
+ "mean": float(np.mean(scores)),
450
+ "std": float(np.std(scores)),
451
+ "min": float(np.min(scores)),
452
+ "max": float(np.max(scores)),
453
+ "n_samples": len(scores),
454
+ }
455
+
456
+
259
457
  # =============================================================================
260
458
  # Metric 5: Region Perturbation (Samek et al., 2015)
261
459
  # =============================================================================
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: explainiverse
3
- Version: 0.8.5
3
+ Version: 0.8.6
4
4
  Summary: Unified, extensible explainability framework supporting 18 XAI methods including LIME, SHAP, LRP, TCAV, GradCAM, and more
5
5
  Home-page: https://github.com/jemsbhai/explainiverse
6
6
  License: MIT
@@ -44,7 +44,7 @@ Description-Content-Type: text/markdown
44
44
  | Feature | Description |
45
45
  |---------|-------------|
46
46
  | **18 Explainers** | LIME, KernelSHAP, TreeSHAP, Integrated Gradients, DeepLIFT, DeepSHAP, SmoothGrad, Saliency Maps, GradCAM/GradCAM++, LRP, TCAV, Anchors, Counterfactual, Permutation Importance, PDP, ALE, SAGE, ProtoDash |
47
- | **14 Evaluation Metrics** | Faithfulness (PGI, PGU, Comprehensiveness, Sufficiency, Correlation, Faithfulness Estimate, Monotonicity, Monotonicity-Nguyen, Pixel Flipping, Region Perturbation) and Stability (RIS, ROS, Lipschitz) |
47
+ | **15 Evaluation Metrics** | Faithfulness (PGI, PGU, Comprehensiveness, Sufficiency, Correlation, Faithfulness Estimate, Monotonicity, Monotonicity-Nguyen, Pixel Flipping, Region Perturbation, Selectivity) and Stability (RIS, ROS, Lipschitz) |
48
48
  | **Unified API** | Consistent `BaseExplainer` interface with standardized `Explanation` output |
49
49
  | **Plugin Registry** | Filter explainers by scope, model type, data type; automatic recommendations |
50
50
  | **Framework Support** | Adapters for scikit-learn and PyTorch (with gradient computation) |
@@ -101,6 +101,7 @@ Explainiverse includes a comprehensive suite of evaluation metrics based on the
101
101
  | **Monotonicity-Nguyen** | Spearman correlation between attributions and feature removal impact | [Nguyen & Martinez, 2020](https://arxiv.org/abs/2010.07455) |
102
102
  | **Pixel Flipping** | AUC of prediction degradation when removing features by importance | [Bach et al., 2015](https://doi.org/10.1371/journal.pone.0130140) |
103
103
  | **Region Perturbation** | AUC of prediction degradation when perturbing feature regions by importance | [Samek et al., 2015](https://arxiv.org/abs/1509.06321) |
104
+ | **Selectivity (AOPC)** | Average prediction drop when sequentially removing features by importance | [Montavon et al., 2018](https://doi.org/10.1016/j.dsp.2017.10.011) |
104
105
 
105
106
  ### Stability Metrics
106
107
 
@@ -1,4 +1,4 @@
1
- explainiverse/__init__.py,sha256=aI5BiLl4bBBvP5icTtOou1_gsdNE6gnl_yeJoGFldFo,1694
1
+ explainiverse/__init__.py,sha256=KFPDVxlFzpILL_9pdWSDKFtrnVo086_K1KeYcJIT6cc,1694
2
2
  explainiverse/adapters/__init__.py,sha256=HcQGISyp-YQ4jEj2IYveX_c9X5otLcTNWRnVRRhzRik,781
3
3
  explainiverse/adapters/base_adapter.py,sha256=Nqt0GeDn_-PjTyJcZsE8dRTulavqFQsv8sMYWS_ps-M,603
4
4
  explainiverse/adapters/pytorch_adapter.py,sha256=DLQKJ7gB0foPwAmcrru7QdZnPRnhqDKpFCT-EaD3420,15612
@@ -9,10 +9,10 @@ explainiverse/core/explanation.py,sha256=498BbRYrNR-BOql78sENOsyWxgqLsBVZXn14lh-
9
9
  explainiverse/core/registry.py,sha256=6HttL27Ty4jYtugRf-EDIKPy80M8BfvUppAKwwGDyQ8,27207
10
10
  explainiverse/engine/__init__.py,sha256=1sZO8nH1mmwK2e-KUavBQm7zYDWUe27nyWoFy9tgsiA,197
11
11
  explainiverse/engine/suite.py,sha256=G-7OjESisSTaQ1FQrlPl4YydX13uz8Bb70hJZNlcl2M,8918
12
- explainiverse/evaluation/__init__.py,sha256=k45VxDn04v0Quy9WqmNuwFfLebMtFHUSgMAvAaiaMkQ,2381
12
+ explainiverse/evaluation/__init__.py,sha256=bde3iDHvCKlYJ1TgJMhkY1ldCHBZ26eQxQX7u6iCDkY,2497
13
13
  explainiverse/evaluation/_utils.py,sha256=ej7YOPZ90gVHuuIMj45EXHq9Jx3QG7lhaj5sk26hRpg,10519
14
14
  explainiverse/evaluation/faithfulness.py,sha256=_40afOW6vJ3dQguHlJySlgWqiJF_xIvN-uVA3nPKRvI,14841
15
- explainiverse/evaluation/faithfulness_extended.py,sha256=OA6KjhT5fORuOjRFStIXVtWan_nxM4WUChEEKEjW44s,35523
15
+ explainiverse/evaluation/faithfulness_extended.py,sha256=c1tQazZBR9sdH3Y431VCL00nE8w9p1vMOYsx2mOBzJg,43101
16
16
  explainiverse/evaluation/metrics.py,sha256=snNK9Ua1VzHDT6DlrhYL4m2MmRF3X15vuuVXiHbeicU,9944
17
17
  explainiverse/evaluation/stability.py,sha256=q2d3rpxpp0X1s6ADST1iZA4tzksLJpR0mYBnA_U5FIs,12090
18
18
  explainiverse/explainers/__init__.py,sha256=-ncRXbFKahH3bR0oXM2UQM4LtTdTlvdeprL6cHeqNBs,2549
@@ -39,7 +39,7 @@ explainiverse/explainers/gradient/smoothgrad.py,sha256=COIKZSFcApmMkA62M0AForHiY
39
39
  explainiverse/explainers/gradient/tcav.py,sha256=zc-8wMsc2ZOhUeSZNBJ6H6BPXlVMJ9DRcAMiL25wU9I,32242
40
40
  explainiverse/explainers/rule_based/__init__.py,sha256=gKzlFCAzwurAMLJcuYgal4XhDj1thteBGcaHWmN7iWk,243
41
41
  explainiverse/explainers/rule_based/anchors_wrapper.py,sha256=ML7W6aam-eMGZHy5ilol8qupZvNBJpYAFatEEPnuMyo,13254
42
- explainiverse-0.8.5.dist-info/LICENSE,sha256=28rbHe8rJgmUlRdxJACfq1Sj-MtCEhyHxkJedQd1ZYA,1070
43
- explainiverse-0.8.5.dist-info/METADATA,sha256=pPkloUD3bjPOpmbrCqJktcNRAmG9izq42ApYiopiA74,25078
44
- explainiverse-0.8.5.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
45
- explainiverse-0.8.5.dist-info/RECORD,,
42
+ explainiverse-0.8.6.dist-info/LICENSE,sha256=28rbHe8rJgmUlRdxJACfq1Sj-MtCEhyHxkJedQd1ZYA,1070
43
+ explainiverse-0.8.6.dist-info/METADATA,sha256=7KtAAsGj0I3PpqYofYwk-OfSaCEs2HyQo9rW3YCxLks,25263
44
+ explainiverse-0.8.6.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
45
+ explainiverse-0.8.6.dist-info/RECORD,,