Source code for xailens.adapters.explainers.xaimethod_base

import pandas as pd
from abc import ABC, abstractmethod
from typing import Any, Optional

from xailens.entities.context import ModelContext
from xailens.entities.model import Model
from xailens.exceptions import MissingDataError
from xailens import config


[docs] class XAIMethodAdapter(ABC): """ Abstract class for XAI method adapter. """ display_name: str | None = None display_notes: str | None = None default_visualisation: Optional[str] compatible_visualisations: Optional[dict] # type of explanation storage - df or json, default to df explanation_file_type: str = "df"
[docs] @classmethod def load_global_explanation(cls, model: Model) -> pd.DataFrame: """ Loads the global explanation for the instantiated class Args: model: Model object Returns: pd.DataFrame: dataframe containing global explanation """ df = model.store.load_dataframe(f"exp_global_{cls.key}") explanation = df.groupby("feature")["importance"].mean() explanation_abs = explanation.abs() abs_sum = explanation.abs().sum() abs_max = explanation.abs().max() return pd.DataFrame({ "feature_name": explanation.index, "score": explanation.values, "score_normalised_sum": explanation_abs.values / abs_sum if abs_sum != 0 else explanation_abs.values, "score_normalised_max": explanation_abs.values / abs_max if abs_max != 0 else explanation_abs.values, })
[docs] @classmethod def load_local_explanation(cls, model: Model, instance_id: str) -> pd.DataFrame: df = model.store.load_dataframe(f"exp_local_{cls.key}") row = df[df[model.get(config.DATA_SCHEMA_ID_COLUMN)] == instance_id] if row.empty: raise MissingDataError(f"Instance '{instance_id}' not found in explanations for {cls.key}") explanation = row.iloc[0].drop(model.get(config.DATA_SCHEMA_ID_COLUMN), errors='coerce') abs_sum = explanation.abs().sum() abs_max = explanation.abs().max() return pd.DataFrame({ "feature_name": explanation.index, "score": explanation.values, "score_normalised_sum": explanation.values / abs_sum if abs_sum != 0 else explanation.values, "score_normalised_max": explanation.values / abs_max if abs_max != 0 else explanation.values, "reasoning": None })
[docs] def get_compatible_visualisations(self): """Gets the compatible visualisations for the instantiated class""" return self.compatible_visualisations
[docs] def get_default_visualisation(self): """Gets the default visualisation for the instantiated class""" return self.default_visualisation
[docs] @abstractmethod def explain_global_df(self, ctx: ModelContext, model=None) -> pd.DataFrame: """Computes the global explanation for the model Args: ctx: ModelContext object model: Trained model object Returns: pd.DataFrame: dataframe containing global explanation Raises: MissingDataError: if required data is not provided """ pass
[docs] @abstractmethod def explain_local_df(self, ctx: ModelContext, model=None) -> pd.DataFrame: """Computes the local explanation for the model Args: ctx: ModelContext object model: Trained model object Returns: pd.DataFrame: dataframe containing local explanations Raises: MissingDataError: if required data is not provided """ pass
[docs] @abstractmethod def explain_local_json(self, ctx: ModelContext) -> list[dict[str, Any]]: """Computes the local explanation for the model Args: ctx: ModelContext object Returns: list of dicts - JSON containing local explanations Raises: MissingDataError: if required data is not provided """ pass