Source code for xaicompare.adapters.explainers.explainer_base
# xaicompare/adapters/explainer_base.py
from abc import ABC, abstractmethod
from typing import Any, Dict, Iterable, List, Sequence, Tuple, Union, Optional
import numpy as np
[docs]
class ExplainerAdapter(ABC):
"""
Base class that standardizes how different explainers are called and what they return.
Concrete implementations (e.g., SHAP Tree for XGBoost/LightGBM,
SHAP Kernel for generic models, LIME-Text, etc.) should subclass this.
Contract:
- global_importance(X, rows_limit) -> (mean_abs, feature_names)
* mean_abs: 1D np.ndarray of length n_features (mean absolute importance)
* feature_names: List[str] of length n_features (ordering aligns with mean_abs)
- local_explanations(X_row) -> 1D np.ndarray of length n_features (signed values)
* X_row represents a single sample (shape (1, ...)); caller may pass a slice X[i:i+1]
"""
def __init__(self, model_adapter: Any, config: Optional[Dict[str, Any]] = None) -> None:
"""
Parameters
----------
model_adapter : Any
A model wrapper exposing at least:
- predict(X), predict_proba(X) (optional)
- feature_names() -> List[str]
- class_names() -> List[str]
- is_sparse_input() -> bool (optional, defaults False)
config : dict, optional
Free-form configuration for the concrete explainer (batch_size, background, etc.).
"""
self.m = model_adapter
self.config = config or {}
# Required methods
[docs]
@abstractmethod
def limitation_text(self) -> str:
raise NotImplementedError
[docs]
@abstractmethod
def global_importance(self, x, rows_limit: int = 200,) -> Tuple[np.ndarray, List[str]]:
"""
Compute a global importance estimate (typically mean ``|contribution|``) in a
memory-safe way across up to `rows_limit` rows of X.
Returns
-------
mean_abs : np.ndarray
1D array of length n_features with mean absolute importance per feature.
feature_names : List[str]
The feature names in the same order as 'mean_abs'.
"""
raise NotImplementedError
[docs]
@abstractmethod
def local_explanations(self, x_row) -> np.ndarray:
"""
Explain a single row. Should return a vector of signed contributions whose length
matches the feature space (n_features).
Notes
-----
- Implementations may aggregate across classes if multi-class (e.g. sum over classes).
- If there is a bias term, do NOT return it here; only per-feature values.
"""
raise NotImplementedError
# ---------- Optional methods ----------
[docs]
def name(self) -> str:
"""Human-readable name of the explainer."""
return self.__class__.__name__