From 9dfe0a025188edfcff3b930bcf31a76fe4e829c2 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 26 Nov 2025 09:05:09 +0000
Subject: [PATCH 1/6] Initial plan
From cc27d4fff9b8df5e1160beb37dd4425fb36b1a94 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 26 Nov 2025 09:19:08 +0000
Subject: [PATCH 2/6] Add comprehensive docstrings to XAI-Lib source code and
create GitHub Pages workflow
Co-authored-by: rinziv <12544167+rinziv@users.noreply.github.com>
---
.github/workflows/docs.yml | 66 +++++++
docs/requirements.txt | 1 +
src/xailib/__init__.py | 121 ++++++++++++
src/xailib/data_loaders/__init__.py | 19 ++
src/xailib/data_loaders/dataframe_loader.py | 48 +++++
src/xailib/explainers/__init__.py | 60 ++++++
src/xailib/metrics/__init__.py | 20 ++
src/xailib/metrics/insertiondeletion.py | 96 +++++++++-
src/xailib/models/__init__.py | 37 ++++
src/xailib/models/bbox.py | 85 +++++++++
src/xailib/models/keras_classifier_wrapper.py | 76 ++++++++
.../models/keras_ts_classifier_wrapper.py | 83 +++++++-
.../models/pytorch_classifier_wrapper.py | 107 ++++++++++-
.../models/sklearn_classifier_wrapper.py | 79 ++++++++
.../models/sklearn_ts_classifier_wrapper.py | 79 +++++++-
src/xailib/xailib_base.py | 178 ++++++++++++++++++
src/xailib/xailib_image.py | 137 ++++++++++++++
src/xailib/xailib_tabular.py | 175 +++++++++++++++++
src/xailib/xailib_text.py | 127 +++++++++++++
src/xailib/xailib_transparent_by_design.py | 149 +++++++++++++++
src/xailib/xailib_ts.py | 140 +++++++++++++-
21 files changed, 1861 insertions(+), 22 deletions(-)
create mode 100644 .github/workflows/docs.yml
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
new file mode 100644
index 0000000..eb5b82f
--- /dev/null
+++ b/.github/workflows/docs.yml
@@ -0,0 +1,66 @@
+name: Deploy Documentation to GitHub Pages
+
+on:
+ push:
+ branches:
+ - main
+ - master
+ pull_request:
+ branches:
+ - main
+ - master
+ workflow_dispatch:
+
+# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+# Allow only one concurrent deployment
+concurrency:
+ group: "pages"
+ cancel-in-progress: false
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ with:
+ submodules: recursive
+
+ - name: Set up Python
+ uses: actions/setup-python@v5
+ with:
+ python-version: '3.10'
+
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install sphinx sphinx-autodoc-typehints
+ pip install -e .
+
+ - name: Build documentation
+ run: |
+ cd docs
+ make html
+
+ - name: Upload artifact
+ uses: actions/upload-pages-artifact@v3
+ with:
+ path: docs/_build/html
+
+ deploy:
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ runs-on: ubuntu-latest
+ needs: build
+ # Only deploy on push to main/master branch
+ if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master')
+ steps:
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/docs/requirements.txt b/docs/requirements.txt
index 2ddf98a..ab7825a 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -2,4 +2,5 @@
# To build the module reference correctly, make sure every external package
# under `install_requires` in `setup.cfg` is also listed here!
sphinx>=3.2.1
+sphinx-autodoc-typehints>=1.12.0
# sphinx_rtd_theme
diff --git a/src/xailib/__init__.py b/src/xailib/__init__.py
index e69de29..33b87dd 100644
--- a/src/xailib/__init__.py
+++ b/src/xailib/__init__.py
@@ -0,0 +1,121 @@
+"""
+XAI-Lib: An Integrated Python Library for Explainable AI.
+
+**XAI-Lib** provides a unified interface for various explanation methods,
+making machine learning models more interpretable and transparent. The library
+simplifies the process of explaining black-box models across different data types.
+
+This project is part of the `XAI Project `_ - a European
+initiative focused on advancing explainable artificial intelligence research
+and applications.
+
+Main Modules
+------------
+
+Core Classes
+~~~~~~~~~~~~
+
+.. autosummary::
+ :toctree: _autosummary
+
+ xailib.xailib_base
+ xailib.xailib_tabular
+ xailib.xailib_image
+ xailib.xailib_text
+ xailib.xailib_ts
+ xailib.xailib_transparent_by_design
+
+Explainers
+~~~~~~~~~~
+
+.. autosummary::
+ :toctree: _autosummary
+
+ xailib.explainers.lime_explainer
+ xailib.explainers.shap_explainer_tab
+ xailib.explainers.lore_explainer
+ xailib.explainers.gradcam_explainer
+ xailib.explainers.rise_explainer
+ xailib.explainers.intgrad_explainer
+ xailib.explainers.abele_explainer
+ xailib.explainers.lasts_explainer
+ xailib.explainers.nam_explainer_tab
+
+Model Wrappers
+~~~~~~~~~~~~~~
+
+.. autosummary::
+ :toctree: _autosummary
+
+ xailib.models.bbox
+ xailib.models.sklearn_classifier_wrapper
+ xailib.models.keras_classifier_wrapper
+ xailib.models.pytorch_classifier_wrapper
+
+Data Loaders
+~~~~~~~~~~~~
+
+.. autosummary::
+ :toctree: _autosummary
+
+ xailib.data_loaders.dataframe_loader
+
+Metrics
+~~~~~~~
+
+.. autosummary::
+ :toctree: _autosummary
+
+ xailib.metrics.insertiondeletion
+
+Quick Start
+-----------
+
+Here's a simple example using LIME for tabular data explanation::
+
+ from xailib.explainers.lime_explainer import LimeXAITabularExplainer
+ from xailib.models.sklearn_classifier_wrapper import sklearn_classifier_wrapper
+
+ # Wrap your scikit-learn model
+ bb = sklearn_classifier_wrapper(your_sklearn_model)
+
+ # Create and fit the explainer
+ explainer = LimeXAITabularExplainer(bb)
+ explainer.fit(df, 'target_column', config={})
+
+ # Generate explanation for an instance
+ explanation = explainer.explain(instance)
+
+ # Visualize feature importance
+ explanation.plot_features_importance()
+
+For more examples, see the `examples/ `_
+directory in the repository.
+
+License
+-------
+
+This project is licensed under the MIT License.
+
+Acknowledgments
+---------------
+
+This library is developed as part of the **XAI Project** (https://xai-project.eu/),
+a European initiative dedicated to advancing explainable artificial intelligence.
+"""
+
+from importlib.metadata import PackageNotFoundError, version
+
+try:
+ __version__ = version("XAI-Library")
+except PackageNotFoundError:
+ __version__ = "unknown"
+
+# Import main classes for convenient access
+from xailib.xailib_base import Explainer, Explanation
+
+__all__ = [
+ "__version__",
+ "Explainer",
+ "Explanation",
+]
diff --git a/src/xailib/data_loaders/__init__.py b/src/xailib/data_loaders/__init__.py
index e69de29..9d98223 100644
--- a/src/xailib/data_loaders/__init__.py
+++ b/src/xailib/data_loaders/__init__.py
@@ -0,0 +1,19 @@
+"""
+Data loading utilities for XAI-Lib.
+
+This subpackage provides utilities for loading and preparing data
+for use with XAI-Lib explainers.
+
+Available Loaders
+-----------------
+
+- :func:`~xailib.data_loaders.dataframe_loader.prepare_dataframe`:
+ Prepare a pandas DataFrame for use with XAI-Lib explainers.
+
+Example
+-------
+>>> from xailib.data_loaders.dataframe_loader import prepare_dataframe
+>>>
+>>> df, feature_names, class_values, numeric_columns, \\
+... rdf, real_feature_names, features_map = prepare_dataframe(df, 'target')
+"""
diff --git a/src/xailib/data_loaders/dataframe_loader.py b/src/xailib/data_loaders/dataframe_loader.py
index 101ae95..46b0229 100644
--- a/src/xailib/data_loaders/dataframe_loader.py
+++ b/src/xailib/data_loaders/dataframe_loader.py
@@ -1,5 +1,53 @@
+"""
+DataFrame loading and preparation utilities for XAI-Lib.
+
+This module provides utilities for loading and preparing pandas DataFrames
+for use with XAI-Lib tabular data explainers.
+
+Functions:
+ prepare_dataframe: Prepare a DataFrame for use with explainers.
+
+Example:
+ >>> from xailib.data_loaders.dataframe_loader import prepare_dataframe
+ >>>
+ >>> df, feature_names, class_values, numeric_columns, \\
+ ... rdf, real_feature_names, features_map = prepare_dataframe(df, 'target')
+"""
+
from lore_explainer.datamanager import prepare_dataset
def prepare_dataframe(df, class_field):
+ """
+ Prepare a pandas DataFrame for use with XAI-Lib explainers.
+
+ This function wraps the LORE library's prepare_dataset function to
+ process a DataFrame for use with various XAI-Lib explainers. It
+ handles feature encoding, categorical variable mapping, and other
+ preprocessing steps.
+
+ Args:
+ df (pd.DataFrame): Input DataFrame containing features and target.
+ class_field (str): Name of the target/class column in the DataFrame.
+
+ Returns:
+ tuple: A tuple containing:
+ - df: Processed DataFrame
+ - feature_names: List of feature column names
+ - class_values: List of unique class values
+ - numeric_columns: List of numeric column names
+ - rdf: Reconstructed DataFrame with original encoding
+ - real_feature_names: Original feature names before encoding
+ - features_map: Mapping of encoded to original features
+
+ Example:
+ >>> import pandas as pd
+ >>> df = pd.DataFrame({
+ ... 'age': [25, 30, 35],
+ ... 'income': [50000, 60000, 70000],
+ ... 'approved': [0, 1, 1]
+ ... })
+ >>> result = prepare_dataframe(df, 'approved')
+ >>> df_processed, feature_names, class_values, *rest = result
+ """
return prepare_dataset(df, class_field)
diff --git a/src/xailib/explainers/__init__.py b/src/xailib/explainers/__init__.py
index e69de29..631eac6 100644
--- a/src/xailib/explainers/__init__.py
+++ b/src/xailib/explainers/__init__.py
@@ -0,0 +1,60 @@
+"""
+Explainer implementations for XAI-Lib.
+
+This subpackage contains implementations of various explanation methods
+for different data types (tabular, image, text, time series).
+
+Tabular Data Explainers
+-----------------------
+
+- :class:`~xailib.explainers.lime_explainer.LimeXAITabularExplainer`:
+ LIME (Local Interpretable Model-agnostic Explanations) for tabular data.
+- :class:`~xailib.explainers.shap_explainer_tab.ShapXAITabularExplainer`:
+ SHAP (SHapley Additive exPlanations) for tabular data.
+- :class:`~xailib.explainers.lore_explainer.LoreTabularExplainer`:
+ LORE (LOcal Rule-based Explanations) for tabular data.
+
+Image Data Explainers
+---------------------
+
+- :class:`~xailib.explainers.lime_explainer.LimeXAIImageExplainer`:
+ LIME for image data.
+- :class:`~xailib.explainers.gradcam_explainer.GradCAMImageExplainer`:
+ GradCAM (Gradient-weighted Class Activation Mapping) for images.
+- :class:`~xailib.explainers.gradcam_explainer.GradCAMPlusPlusImageExplainer`:
+ GradCAM++ for improved image explanations.
+- :class:`~xailib.explainers.rise_explainer.RiseXAIImageExplainer`:
+ RISE (Randomized Input Sampling for Explanation) for images.
+- :class:`~xailib.explainers.intgrad_explainer.IntgradImageExplainer`:
+ Integrated Gradients for image explanations.
+- :class:`~xailib.explainers.abele_explainer`:
+ ABELE (Adversarial Black-box Explainer) for images.
+
+Text Data Explainers
+--------------------
+
+- :class:`~xailib.explainers.lime_explainer.LimeXAITextExplainer`:
+ LIME for text data.
+
+Time Series Explainers
+----------------------
+
+- :class:`~xailib.explainers.lasts_explainer`:
+ LASTS for time series explanations.
+
+Transparent-by-Design Models
+----------------------------
+
+- :class:`~xailib.explainers.nam_explainer_tab`:
+ Neural Additive Models for interpretable predictions.
+
+Example
+-------
+>>> from xailib.explainers.lime_explainer import LimeXAITabularExplainer
+>>> from xailib.models.sklearn_classifier_wrapper import sklearn_classifier_wrapper
+>>>
+>>> bb = sklearn_classifier_wrapper(trained_model)
+>>> explainer = LimeXAITabularExplainer(bb)
+>>> explainer.fit(df, 'target', config={})
+>>> explanation = explainer.explain(instance)
+"""
diff --git a/src/xailib/metrics/__init__.py b/src/xailib/metrics/__init__.py
index e69de29..2456311 100644
--- a/src/xailib/metrics/__init__.py
+++ b/src/xailib/metrics/__init__.py
@@ -0,0 +1,20 @@
+"""
+Evaluation metrics for XAI-Lib explanations.
+
+This subpackage provides metrics for evaluating the quality and
+faithfulness of explanations generated by XAI-Lib explainers.
+
+Available Metrics
+-----------------
+
+- :class:`~xailib.metrics.insertiondeletion`:
+ Insertion and Deletion metrics for evaluating explanation faithfulness.
+
+Example
+-------
+>>> from xailib.metrics.insertiondeletion import InsertionDeletion
+>>>
+>>> metric = InsertionDeletion(model, image, explanation)
+>>> insertion_score = metric.insertion()
+>>> deletion_score = metric.deletion()
+"""
diff --git a/src/xailib/metrics/insertiondeletion.py b/src/xailib/metrics/insertiondeletion.py
index e67f965..7588e31 100644
--- a/src/xailib/metrics/insertiondeletion.py
+++ b/src/xailib/metrics/insertiondeletion.py
@@ -1,3 +1,41 @@
+"""
+Insertion and Deletion metrics for evaluating explanation faithfulness.
+
+This module provides the Insertion and Deletion metrics for evaluating
+how well an explanation captures the important features of a model's
+prediction. These metrics are commonly used for evaluating image
+explanations (saliency maps, heatmaps).
+
+The Insertion metric measures how quickly the model's prediction confidence
+increases as pixels are inserted in order of saliency (most salient first).
+
+The Deletion metric measures how quickly the model's prediction confidence
+decreases as pixels are deleted in order of saliency (most salient first).
+
+Classes:
+ ImageInsDel: Insertion and Deletion metric calculator for images.
+
+References:
+ Petsiuk, V., Das, A., & Saenko, K. (2018). RISE: Randomized Input
+ Sampling for Explanation of Black-box Models. BMVC.
+
+Example:
+ >>> from xailib.metrics.insertiondeletion import ImageInsDel
+ >>> import numpy as np
+ >>>
+ >>> # Define prediction function
+ >>> def predict(img):
+ ... return model.predict(img)
+ >>>
+ >>> # Create metric instance
+ >>> deletion = ImageInsDel(predict, mode='del', step=100, substrate_fn=lambda x: x*0)
+ >>> insertion = ImageInsDel(predict, mode='ins', step=100, substrate_fn=lambda x: x*0)
+ >>>
+ >>> # Compute scores
+ >>> del_scores = deletion(image, 224, saliency_map)
+ >>> ins_scores = insertion(image, 224, saliency_map)
+"""
+
from xailib.models.bbox import AbstractBBox
import numpy as np
import matplotlib.pyplot as plt
@@ -5,15 +43,63 @@
import tensorflow as tf
import torch
+
class ImageInsDel():
+ """
+ Insertion and Deletion metric calculator for image explanations.
+
+ This class computes the Insertion and Deletion metrics for evaluating
+ the faithfulness of image explanations (saliency maps). The metrics
+ measure how the model's confidence changes as pixels are progressively
+ inserted or deleted in order of their saliency.
+
+ A good explanation should:
+ - Have high Insertion score (confidence quickly increases as
+ salient pixels are inserted)
+ - Have low Deletion score (confidence quickly decreases as
+ salient pixels are deleted)
+
+ The Area Under the Curve (AUC) of these scores can be used as a
+ single summary metric.
+
+ Args:
+ predict (callable): Function that takes a numpy array image and
+ returns prediction probabilities.
+ mode (str): Either 'del' for deletion metric or 'ins' for
+ insertion metric.
+ step (int): Number of pixels modified per iteration.
+ substrate_fn (callable): Function mapping original pixels to
+ baseline pixels (e.g., black pixels, blurred pixels).
+
+ Attributes:
+ predict: The prediction function.
+ mode: The metric mode ('del' or 'ins').
+ step: Number of pixels per step.
+ substrate_fn: The substrate/baseline function.
+
+ Example:
+ >>> # Create deletion metric with black baseline
+ >>> deletion = ImageInsDel(
+ ... predict=model.predict,
+ ... mode='del',
+ ... step=224, # pixels per step
+ ... substrate_fn=lambda x: torch.zeros_like(x) # black baseline
+ ... )
+ >>> scores = deletion(image, size=224, explanation=saliency_map)
+ >>> auc = np.trapz(scores) / len(scores)
+ """
+
def __init__(self, predict, mode, step, substrate_fn):
- r"""Create deletion/insertion metric instance.
+ """
+ Create deletion/insertion metric instance.
Args:
- predict (func): function that takes in input a numpy array and return the prediction.
- mode (str): 'del' or 'ins'.
- step (int): number of pixels modified per one iteration.
- substrate_fn (func): a mapping from old pixels to new pixels.
+ predict (callable): Function that takes a numpy array and
+ returns the prediction probabilities.
+ mode (str): 'del' for deletion or 'ins' for insertion.
+ step (int): Number of pixels modified per one iteration.
+ substrate_fn (callable): A mapping from old pixels to new pixels
+ (e.g., blurring function or constant function).
"""
assert mode in ['del', 'ins']
self.predict = predict
diff --git a/src/xailib/models/__init__.py b/src/xailib/models/__init__.py
index e69de29..d9972fd 100644
--- a/src/xailib/models/__init__.py
+++ b/src/xailib/models/__init__.py
@@ -0,0 +1,37 @@
+"""
+Model wrappers for XAI-Lib.
+
+This subpackage provides wrapper classes for machine learning models from
+different frameworks (scikit-learn, Keras, PyTorch). These wrappers provide
+a unified interface for explainers to interact with various model types.
+
+Available Wrappers
+------------------
+
+General Purpose:
+ - :class:`~xailib.models.sklearn_classifier_wrapper.sklearn_classifier_wrapper`:
+ Wrapper for scikit-learn classifiers.
+ - :class:`~xailib.models.keras_classifier_wrapper.keras_classifier_wrapper`:
+ Wrapper for Keras/TensorFlow classifiers.
+ - :class:`~xailib.models.pytorch_classifier_wrapper.pytorch_classifier_wrapper`:
+ Wrapper for PyTorch classifiers.
+
+Time Series:
+ - :class:`~xailib.models.keras_ts_classifier_wrapper.keras_classifier_wrapper`:
+ Wrapper for Keras time series classifiers.
+ - :class:`~xailib.models.sklearn_ts_classifier_wrapper.sklearn_classifier_wrapper`:
+ Wrapper for scikit-learn time series classifiers.
+
+Base Class:
+ - :class:`~xailib.models.bbox.AbstractBBox`:
+ Abstract base class for all model wrappers.
+
+Example
+-------
+>>> from sklearn.ensemble import RandomForestClassifier
+>>> from xailib.models.sklearn_classifier_wrapper import sklearn_classifier_wrapper
+>>>
+>>> rf = RandomForestClassifier().fit(X_train, y_train)
+>>> bb = sklearn_classifier_wrapper(rf)
+>>> predictions = bb.predict(X_test)
+"""
diff --git a/src/xailib/models/bbox.py b/src/xailib/models/bbox.py
index c401d67..73992d2 100644
--- a/src/xailib/models/bbox.py
+++ b/src/xailib/models/bbox.py
@@ -1,13 +1,98 @@
+"""
+Abstract base class for black-box model wrappers.
+
+This module defines the :class:`AbstractBBox` interface that all model
+wrappers must implement. Model wrappers provide a unified API for
+interacting with machine learning models from different frameworks
+(scikit-learn, Keras, PyTorch, etc.).
+
+Classes:
+ AbstractBBox: Abstract base class for black-box model wrappers.
+
+Example:
+ Creating a custom model wrapper::
+
+ from xailib.models.bbox import AbstractBBox
+
+ class MyModelWrapper(AbstractBBox):
+ def __init__(self, model):
+ super().__init__()
+ self.model = model
+
+ def predict(self, X):
+ return self.model.predict(X)
+
+ def predict_proba(self, X):
+ return self.model.predict_proba(X)
+
+See Also:
+ :class:`xailib.models.sklearn_classifier_wrapper.sklearn_classifier_wrapper`
+ :class:`xailib.models.keras_classifier_wrapper.KerasClassifierWrapper`
+ :class:`xailib.models.pytorch_classifier_wrapper.PytorchClassifierWrapper`
+"""
+
from abc import ABC, abstractmethod
+
class AbstractBBox(ABC):
+ """
+ Abstract base class for black-box model wrappers.
+
+ This class defines the interface that all model wrappers must implement.
+ Wrappers provide a consistent API for explainers to interact with
+ different types of machine learning models.
+
+ All explainers in XAI-Lib expect models to be wrapped using a class
+ that inherits from AbstractBBox.
+
+ Attributes:
+ Defined by subclasses. Common attributes include the wrapped model
+ and any preprocessing functions.
+
+ Example:
+ >>> from xailib.models.sklearn_classifier_wrapper import sklearn_classifier_wrapper
+ >>> from sklearn.ensemble import RandomForestClassifier
+ >>> rf = RandomForestClassifier()
+ >>> rf.fit(X_train, y_train)
+ >>> bb = sklearn_classifier_wrapper(rf)
+ >>> predictions = bb.predict(X_test)
+ """
+
def __init__(self):
+ """Initialize the AbstractBBox base class."""
pass
@abstractmethod
def predict(self, X):
+ """
+ Make predictions for input instances.
+
+ Args:
+ X: Input features. The format depends on the model type:
+ - For tabular models: numpy array of shape (n_samples, n_features)
+ - For image models: numpy array of images
+ - For text models: list of strings
+
+ Returns:
+ numpy.ndarray: Predicted class labels for classification,
+ or predicted values for regression.
+ """
pass
@abstractmethod
def predict_proba(self, X):
+ """
+ Get prediction probabilities for input instances.
+
+ Args:
+ X: Input features in the same format as :meth:`predict`.
+
+ Returns:
+ numpy.ndarray: Predicted class probabilities of shape
+ (n_samples, n_classes) for classification models.
+
+ Raises:
+ NotImplementedError: If the underlying model does not
+ support probability predictions.
+ """
pass
\ No newline at end of file
diff --git a/src/xailib/models/keras_classifier_wrapper.py b/src/xailib/models/keras_classifier_wrapper.py
index 56415d0..dfac70b 100644
--- a/src/xailib/models/keras_classifier_wrapper.py
+++ b/src/xailib/models/keras_classifier_wrapper.py
@@ -1,14 +1,90 @@
+"""
+Keras classifier wrapper for XAI-Lib.
+
+This module provides a wrapper class for Keras/TensorFlow classifiers,
+allowing them to be used with XAI-Lib explainers.
+
+Classes:
+ keras_classifier_wrapper: Wrapper for Keras classifiers.
+
+Example:
+ >>> from tensorflow import keras
+ >>> from xailib.models.keras_classifier_wrapper import keras_classifier_wrapper
+ >>>
+ >>> # Build and train your Keras model
+ >>> model = keras.Sequential([...])
+ >>> model.fit(X_train, y_train)
+ >>>
+ >>> # Wrap it for use with XAI-Lib
+ >>> bb = keras_classifier_wrapper(model)
+ >>>
+ >>> # Now use with any explainer
+ >>> from xailib.explainers.gradcam_explainer import GradCAMImageExplainer
+ >>> explainer = GradCAMImageExplainer(bb)
+"""
+
from xailib.models.bbox import AbstractBBox
class keras_classifier_wrapper(AbstractBBox):
+ """
+ Wrapper class for Keras/TensorFlow classifiers.
+
+ This class wraps Keras models to provide the standard interface
+ expected by XAI-Lib explainers.
+
+ Args:
+ classifier: A trained Keras model.
+
+ Attributes:
+ bbox: The wrapped Keras model.
+
+ Example:
+ >>> model = keras.Sequential([...])
+ >>> model.fit(X_train, y_train)
+ >>> wrapper = keras_classifier_wrapper(model)
+ >>> wrapper.predict(X_test[:5])
+ """
+
def __init__(self, classifier):
+ """
+ Initialize the Keras classifier wrapper.
+
+ Args:
+ classifier: A trained Keras model.
+ """
super().__init__()
self.bbox = classifier
+
def model(self):
+ """
+ Get the underlying Keras model.
+
+ Returns:
+ The wrapped Keras model object.
+ """
return self.bbox
+
def predict(self, X):
+ """
+ Make class predictions for input instances.
+
+ Args:
+ X: Input features as a numpy array.
+
+ Returns:
+ numpy.ndarray: Predicted class labels.
+ """
return self.bbox.predict(X)
def predict_proba(self, X):
+ """
+ Get prediction probabilities for input instances.
+
+ Args:
+ X: Input features as a numpy array.
+
+ Returns:
+ numpy.ndarray: Predicted class probabilities.
+ """
return self.bbox.predict_proba(X)
diff --git a/src/xailib/models/keras_ts_classifier_wrapper.py b/src/xailib/models/keras_ts_classifier_wrapper.py
index 74faea9..c64fdeb 100644
--- a/src/xailib/models/keras_ts_classifier_wrapper.py
+++ b/src/xailib/models/keras_ts_classifier_wrapper.py
@@ -1,23 +1,100 @@
+"""
+Keras time series classifier wrapper for XAI-Lib.
+
+This module provides a wrapper class for Keras time series classifiers,
+handling the specific input/output requirements of time series models.
+
+Classes:
+ keras_classifier_wrapper: Wrapper for Keras time series classifiers.
+
+Example:
+ >>> from tensorflow import keras
+ >>> from xailib.models.keras_ts_classifier_wrapper import keras_classifier_wrapper
+ >>>
+ >>> # Build and train your Keras time series model
+ >>> model = keras.Sequential([
+ ... keras.layers.LSTM(64, input_shape=(timesteps, features)),
+ ... keras.layers.Dense(num_classes, activation='softmax')
+ ... ])
+ >>> model.fit(X_train, y_train)
+ >>>
+ >>> # Wrap it for use with XAI-Lib
+ >>> bb = keras_classifier_wrapper(model)
+"""
+
from xailib.models.bbox import AbstractBBox
import numpy as np
class keras_classifier_wrapper(AbstractBBox):
+ """
+ Wrapper class for Keras time series classifiers.
+
+ This class wraps Keras models designed for time series classification.
+ It handles the conversion of model outputs to class predictions and
+ probability estimates.
+
+ Args:
+ classifier: A trained Keras time series model.
+
+ Attributes:
+ bbox: The wrapped Keras model.
+
+ Note:
+ For time series models, inputs typically have shape
+ (n_samples, n_timesteps, n_features).
+ """
+
def __init__(self, classifier):
+ """
+ Initialize the Keras time series classifier wrapper.
+
+ Args:
+ classifier: A trained Keras model for time series classification.
+ """
super().__init__()
self.bbox = classifier
def model(self):
+ """
+ Get the underlying Keras model.
+
+ Returns:
+ The wrapped Keras model object.
+ """
return self.bbox
def predict(self, X):
- #here the input is 3 dimensions
+ """
+ Make class predictions for time series input instances.
+
+ For multi-class classification, returns the argmax of the output.
+
+ Args:
+ X: Input time series as a numpy array with 3 dimensions
+ (n_samples, n_timesteps, n_features).
+
+ Returns:
+ numpy.ndarray: Predicted class labels as a 1D array.
+ """
y = self.bbox.predict(X)
- #not sure about this condition, check it
+ # For multi-class output, get the argmax
if len(y.shape) > 1 and (y.shape[1] != 1):
y = np.argmax(y, axis=1)
return y.ravel()
def predict_proba(self, X):
- #keras does not return predict_proba. the probabilities are in the predict
+ """
+ Get prediction probabilities for time series input instances.
+
+ Args:
+ X: Input time series as a numpy array with 3 dimensions
+ (n_samples, n_timesteps, n_features).
+
+ Returns:
+ numpy.ndarray: Predicted class probabilities.
+
+ Note:
+ Keras predict() already returns probabilities for softmax outputs.
+ """
return self.bbox.predict(X)
diff --git a/src/xailib/models/pytorch_classifier_wrapper.py b/src/xailib/models/pytorch_classifier_wrapper.py
index b4cefde..36d991f 100644
--- a/src/xailib/models/pytorch_classifier_wrapper.py
+++ b/src/xailib/models/pytorch_classifier_wrapper.py
@@ -1,34 +1,99 @@
+"""
+PyTorch classifier wrapper for XAI-Lib.
+
+This module provides a wrapper class for PyTorch classifiers,
+allowing them to be used with XAI-Lib explainers.
+
+Classes:
+ pytorch_classifier_wrapper: Wrapper for PyTorch classifiers.
+
+Example:
+ >>> import torch.nn as nn
+ >>> from xailib.models.pytorch_classifier_wrapper import pytorch_classifier_wrapper
+ >>>
+ >>> # Build and train your PyTorch model
+ >>> model = YourPyTorchModel()
+ >>> # ... training code ...
+ >>>
+ >>> # Wrap it for use with XAI-Lib
+ >>> bb = pytorch_classifier_wrapper(model, device="cuda", n_features=10)
+ >>>
+ >>> # Now use with any explainer
+ >>> from xailib.explainers.intgrad_explainer import IntgradImageExplainer
+ >>> explainer = IntgradImageExplainer(bb)
+"""
+
from xailib.models.bbox import AbstractBBox
import torch
import numpy as np
+
class pytorch_classifier_wrapper(AbstractBBox):
- """ Wrapper for a Pytorch classifier to be used as a BBox.
+ """
+ Wrapper class for PyTorch classifiers.
+
+ This class wraps PyTorch models to provide the standard interface
+ expected by XAI-Lib explainers. It handles device management and
+ input tensor conversion automatically.
Args:
- classifier: Pytorch model.
- device: Optional, string indicating the device to use, either "cpu" or "cuda". Default is "cpu".
- n_features: Optional, integer indicating the number of features for reshaping the input. Default is 1.
+ classifier: A trained PyTorch model (nn.Module).
+ device (str, optional): Device to use for inference, either "cpu"
+ or "cuda". Defaults to "cpu".
+ n_features (int, optional): Number of features for reshaping the
+ input tensor. If set, inputs are reshaped to (-1, n_features).
+ Defaults to 1.
+
+ Attributes:
+ bbox: The wrapped PyTorch model.
+ device (str): The device being used for inference.
+ n_features (int): Number of features for input reshaping.
+
+ Example:
+ >>> model = MyPyTorchClassifier()
+ >>> model.load_state_dict(torch.load('model.pt'))
+ >>> model.eval()
+ >>> wrapper = pytorch_classifier_wrapper(model, device="cuda")
+ >>> predictions = wrapper.predict(X_test)
"""
- def __init__(self, classifier, device = "cpu", n_features = 1):
+ def __init__(self, classifier, device="cpu", n_features=1):
+ """
+ Initialize the PyTorch classifier wrapper.
+
+ Args:
+ classifier: A trained PyTorch model.
+ device (str, optional): Device for inference ("cpu" or "cuda").
+ n_features (int, optional): Number of features for input reshaping.
+ """
super().__init__()
self.bbox = classifier
self.device = device
self.n_features = n_features
def model(self):
+ """
+ Get the underlying PyTorch model.
+
+ Returns:
+ The wrapped PyTorch model (nn.Module).
+ """
return self.bbox
def prepare_input(self, X):
- r""" Converts input data to a PyTorch tensor suitable for model inference.
+ """
+ Convert input data to a PyTorch tensor suitable for model inference.
+
+ This method handles numpy array to tensor conversion, reshaping based
+ on n_features, and moving the tensor to the appropriate device.
Args:
X: Input data, either a numpy array or a PyTorch tensor.
Returns:
- torch.Tensor: The input data as a float tensor, reshaped to (-1, n_features) if n_features is set,
- and moved to the specified device (CPU or CUDA).
+ torch.Tensor: The input data as a float tensor, reshaped to
+ (-1, n_features) if n_features is set, and moved to the
+ specified device (CPU or CUDA).
"""
if isinstance(X, np.ndarray):
X = torch.from_numpy(X)
@@ -42,6 +107,18 @@ def prepare_input(self, X):
return X
def predict(self, X):
+ """
+ Make class predictions for input instances.
+
+ For multi-class classification, returns the argmax of the output.
+ For binary classification (single output), applies a 0.5 threshold.
+
+ Args:
+ X: Input features as a numpy array or PyTorch tensor.
+
+ Returns:
+ numpy.ndarray: Predicted class labels as integers.
+ """
X = self.prepare_input(X)
with torch.no_grad():
@@ -56,6 +133,20 @@ def predict(self, X):
return y
def predict_proba(self, X):
+ """
+ Get prediction probabilities for input instances.
+
+ Args:
+ X: Input features as a numpy array or PyTorch tensor.
+
+ Returns:
+ numpy.ndarray: Raw model output (logits or probabilities,
+ depending on the model architecture).
+
+ Note:
+ If your model outputs logits, you may need to apply softmax
+ to get proper probabilities.
+ """
X = self.prepare_input(X)
with torch.no_grad():
diff --git a/src/xailib/models/sklearn_classifier_wrapper.py b/src/xailib/models/sklearn_classifier_wrapper.py
index cc43a3d..383fde7 100644
--- a/src/xailib/models/sklearn_classifier_wrapper.py
+++ b/src/xailib/models/sklearn_classifier_wrapper.py
@@ -1,14 +1,93 @@
+"""
+Scikit-learn classifier wrapper for XAI-Lib.
+
+This module provides a wrapper class for scikit-learn classifiers,
+allowing them to be used with XAI-Lib explainers.
+
+Classes:
+ sklearn_classifier_wrapper: Wrapper for scikit-learn classifiers.
+
+Example:
+ >>> from sklearn.ensemble import RandomForestClassifier
+ >>> from xailib.models.sklearn_classifier_wrapper import sklearn_classifier_wrapper
+ >>>
+ >>> # Train your model
+ >>> rf = RandomForestClassifier()
+ >>> rf.fit(X_train, y_train)
+ >>>
+ >>> # Wrap it for use with XAI-Lib
+ >>> bb = sklearn_classifier_wrapper(rf)
+ >>>
+ >>> # Now use with any explainer
+ >>> from xailib.explainers.lime_explainer import LimeXAITabularExplainer
+ >>> explainer = LimeXAITabularExplainer(bb)
+"""
+
from xailib.models.bbox import AbstractBBox
class sklearn_classifier_wrapper(AbstractBBox):
+ """
+ Wrapper class for scikit-learn classifiers.
+
+ This class wraps scikit-learn compatible classifiers to provide
+ the standard interface expected by XAI-Lib explainers.
+
+ Args:
+ classifier: A trained scikit-learn classifier with `predict`
+ and `predict_proba` methods.
+
+ Attributes:
+ bbox: The wrapped scikit-learn classifier.
+
+ Example:
+ >>> from sklearn.ensemble import GradientBoostingClassifier
+ >>> clf = GradientBoostingClassifier().fit(X_train, y_train)
+ >>> wrapper = sklearn_classifier_wrapper(clf)
+ >>> wrapper.predict(X_test[:5])
+ array([0, 1, 1, 0, 1])
+ """
+
def __init__(self, classifier):
+ """
+ Initialize the sklearn classifier wrapper.
+
+ Args:
+ classifier: A trained scikit-learn compatible classifier.
+ """
super().__init__()
self.bbox = classifier
+
def model(self):
+ """
+ Get the underlying scikit-learn model.
+
+ Returns:
+ The wrapped scikit-learn classifier object.
+ """
return self.bbox
+
def predict(self, X):
+ """
+ Make class predictions for input instances.
+
+ Args:
+ X: Input features as a numpy array of shape (n_samples, n_features).
+
+ Returns:
+ numpy.ndarray: Predicted class labels of shape (n_samples,).
+ """
return self.bbox.predict(X)
def predict_proba(self, X):
+ """
+ Get prediction probabilities for input instances.
+
+ Args:
+ X: Input features as a numpy array of shape (n_samples, n_features).
+
+ Returns:
+ numpy.ndarray: Predicted class probabilities of shape
+ (n_samples, n_classes).
+ """
return self.bbox.predict_proba(X)
diff --git a/src/xailib/models/sklearn_ts_classifier_wrapper.py b/src/xailib/models/sklearn_ts_classifier_wrapper.py
index 8ae88bb..a822ce7 100644
--- a/src/xailib/models/sklearn_ts_classifier_wrapper.py
+++ b/src/xailib/models/sklearn_ts_classifier_wrapper.py
@@ -1,21 +1,96 @@
+"""
+Scikit-learn time series classifier wrapper for XAI-Lib.
+
+This module provides a wrapper class for scikit-learn classifiers
+designed for time series data, handling the specific input shape
+requirements of time series models.
+
+Classes:
+ sklearn_classifier_wrapper: Wrapper for scikit-learn time series classifiers.
+
+Example:
+ >>> from sklearn.ensemble import RandomForestClassifier
+ >>> from xailib.models.sklearn_ts_classifier_wrapper import sklearn_classifier_wrapper
+ >>>
+ >>> # Train your scikit-learn model on flattened time series
+ >>> rf = RandomForestClassifier()
+ >>> rf.fit(X_train_2d, y_train)
+ >>>
+ >>> # Wrap it for use with XAI-Lib (handles 3D to 2D conversion)
+ >>> bb = sklearn_classifier_wrapper(rf)
+"""
+
from xailib.models.bbox import AbstractBBox
class sklearn_classifier_wrapper(AbstractBBox):
+ """
+ Wrapper class for scikit-learn time series classifiers.
+
+ This class wraps scikit-learn classifiers for time series data,
+ handling the conversion from 3D time series format to the 2D
+ format expected by scikit-learn.
+
+ Args:
+ classifier: A trained scikit-learn classifier.
+
+ Attributes:
+ bbox: The wrapped scikit-learn classifier.
+
+ Note:
+ This wrapper converts 3D time series input (n_samples, n_timesteps, n_features)
+ to 2D format (n_samples, n_timesteps) by taking the first feature dimension.
+ """
def __init__(self, classifier):
+ """
+ Initialize the scikit-learn time series classifier wrapper.
+
+ Args:
+ classifier: A trained scikit-learn classifier.
+ """
super().__init__()
self.bbox = classifier
def model(self):
+ """
+ Get the underlying scikit-learn model.
+
+ Returns:
+ The wrapped scikit-learn classifier object.
+ """
return self.bbox
def predict(self, X):
- #change the input shape of the time series, from 3 dimensions to 2.
+ """
+ Make class predictions for time series input instances.
+
+ Converts 3D time series input to 2D format before prediction.
+
+ Args:
+ X: Input time series as a numpy array with 3 dimensions
+ (n_samples, n_timesteps, n_features).
+
+ Returns:
+ numpy.ndarray: Predicted class labels as a 1D array.
+ """
+ # Convert from 3D to 2D by taking first feature dimension
X = X[:, :, 0]
return self.bbox.predict(X).ravel()
def predict_proba(self, X):
- # change the input shape of the time series, from 3 dimensions to 2.
+ """
+ Get prediction probabilities for time series input instances.
+
+ Converts 3D time series input to 2D format before prediction.
+
+ Args:
+ X: Input time series as a numpy array with 3 dimensions
+ (n_samples, n_timesteps, n_features).
+
+ Returns:
+ numpy.ndarray: Predicted class probabilities.
+ """
+ # Convert from 3D to 2D by taking first feature dimension
X = X[:, :, 0]
return self.bbox.predict_proba(X)
diff --git a/src/xailib/xailib_base.py b/src/xailib/xailib_base.py
index a6b019d..6112ae8 100644
--- a/src/xailib/xailib_base.py
+++ b/src/xailib/xailib_base.py
@@ -1,42 +1,220 @@
+"""
+Base classes for XAI-Lib explainability framework.
+
+This module defines the abstract base classes that serve as the foundation
+for all explainers and explanations in the XAI-Lib library. These classes
+provide a unified interface for implementing various explanation methods
+across different data types (tabular, image, text, time series).
+
+Classes:
+ Explainer: Abstract base class for all explainer implementations.
+ Explanation: Abstract base class for all explanation representations.
+
+Example:
+ Creating a custom explainer::
+
+ from xailib.xailib_base import Explainer, Explanation
+
+ class MyExplanation(Explanation):
+ def getFeaturesImportance(self):
+ return self.feature_weights
+
+ class MyExplainer(Explainer):
+ def fit(self, X, y):
+ # Train the explainer
+ pass
+
+ def explain(self, x):
+ # Generate explanation for instance x
+ return MyExplanation()
+"""
from abc import ABC, abstractmethod
class Explainer(ABC):
+ """
+ Abstract base class for all explainer implementations.
+
+ This class defines the interface that all explainers must implement.
+ An explainer is responsible for generating explanations for predictions
+ made by black-box machine learning models.
+
+ The typical workflow involves:
+ 1. Initialize the explainer with a black-box model
+ 2. Call :meth:`fit` to prepare the explainer with training data
+ 3. Call :meth:`explain` to generate explanations for specific instances
+
+ Attributes:
+ None defined at the base level. Subclasses should define their own.
+
+ See Also:
+ :class:`Explanation`: The corresponding base class for explanations.
+ :class:`xailib.xailib_tabular.TabularExplainer`: Explainer for tabular data.
+ :class:`xailib.xailib_image.ImageExplainer`: Explainer for image data.
+ """
def __init__(self):
+ """Initialize the Explainer base class."""
pass
@abstractmethod
def fit(self, X, y):
+ """
+ Fit the explainer to the training data.
+
+ This method prepares the explainer by learning from the training data.
+ The specific behavior depends on the explanation method being used.
+
+ Args:
+ X: Training features. The format depends on the data type:
+ - For tabular data: pandas DataFrame or numpy array of shape (n_samples, n_features)
+ - For image data: numpy array of images
+ - For text data: list of strings or text documents
+ y: Training labels or target values. numpy array of shape (n_samples,)
+
+ Returns:
+ None. The explainer is fitted in-place.
+
+ Raises:
+ NotImplementedError: If the subclass does not implement this method.
+ """
pass
@abstractmethod
def explain(self, x):
+ """
+ Generate an explanation for a single instance.
+
+ This method creates an explanation for why the black-box model
+ made a specific prediction for the given instance.
+
+ Args:
+ x: The instance to explain. The format depends on the data type:
+ - For tabular data: 1D numpy array or pandas Series
+ - For image data: numpy array representing an image
+ - For text data: string or text document
+
+ Returns:
+ Explanation: An Explanation object containing the explanation details.
+
+ Raises:
+ NotImplementedError: If the subclass does not implement this method.
+ """
pass
class Explanation(ABC):
+ """
+ Abstract base class for all explanation representations.
+
+ This class defines the interface for accessing different aspects of
+ an explanation. Explanations can provide various types of information
+ including feature importance, exemplars, rules, and counterfactuals.
+
+ Different explanation methods may only support a subset of these
+ information types. Methods that are not supported by a particular
+ explanation type should return None.
+
+ Attributes:
+ None defined at the base level. Subclasses should define their own.
+
+ See Also:
+ :class:`Explainer`: The corresponding base class for explainers.
+ :class:`xailib.xailib_tabular.TabularExplanation`: Explanation for tabular data.
+ :class:`xailib.xailib_image.ImageExplanation`: Explanation for image data.
+ """
def __init__(self):
+ """Initialize the Explanation base class."""
pass
@abstractmethod
def getFeaturesImportance(self):
+ """
+ Get the feature importance values from the explanation.
+
+ Feature importance indicates how much each feature contributed
+ to the model's prediction for the explained instance.
+
+ Returns:
+ Feature importance values. The format depends on the explanation method:
+ - List of tuples: [(feature_name, importance_value), ...]
+ - numpy array: Array of importance values
+ - None: If feature importance is not available for this explanation type
+
+ Example:
+ >>> explanation = explainer.explain(instance)
+ >>> importance = explanation.getFeaturesImportance()
+ >>> for feature, value in importance:
+ ... print(f"{feature}: {value:.4f}")
+ """
pass
@abstractmethod
def getExemplars(self):
+ """
+ Get exemplar instances from the explanation.
+
+ Exemplars are instances from the training data that are similar
+ to the explained instance and received the same prediction.
+
+ Returns:
+ Exemplar instances, or None if not available for this explanation type.
+ The format depends on the specific explanation method.
+ """
pass
@abstractmethod
def getCounterExemplars(self):
+ """
+ Get counter-exemplar instances from the explanation.
+
+ Counter-exemplars are instances that are similar to the explained
+ instance but received a different prediction.
+
+ Returns:
+ Counter-exemplar instances, or None if not available for this explanation type.
+ The format depends on the specific explanation method.
+ """
pass
@abstractmethod
def getRules(self):
+ """
+ Get the decision rules from the explanation.
+
+ Rules are logical conditions that describe why the model made
+ its prediction for the explained instance.
+
+ Returns:
+ Decision rules as a list or dictionary, or None if not available.
+ For rule-based explanations like LORE, this returns the rule
+ that led to the prediction.
+
+ Example:
+ >>> rules = explanation.getRules()
+ >>> print(rules)
+ {'premise': [{'att': 'age', 'op': '>', 'thr': 30}], 'cons': 'approved'}
+ """
pass
@abstractmethod
def getCounterfactualRules(self):
+ """
+ Get counterfactual rules from the explanation.
+
+ Counterfactual rules describe what minimal changes to the input
+ would result in a different prediction.
+
+ Returns:
+ Counterfactual rules as a list or dictionary, or None if not available.
+ Each counterfactual rule describes conditions that would lead
+ to a different outcome.
+
+ Example:
+ >>> cf_rules = explanation.getCounterfactualRules()
+ >>> for rule in cf_rules:
+ ... print(f"To get {rule['cons']}: {rule['premise']}")
+ """
pass
diff --git a/src/xailib/xailib_image.py b/src/xailib/xailib_image.py
index f26ce0e..2288a11 100644
--- a/src/xailib/xailib_image.py
+++ b/src/xailib/xailib_image.py
@@ -1,43 +1,180 @@
+"""
+Image data explainability classes for XAI-Lib.
+
+This module provides base classes for explaining predictions on image data.
+It extends the base :class:`~xailib.xailib_base.Explainer` and
+:class:`~xailib.xailib_base.Explanation` classes with image-specific
+functionality.
+
+Image explanations typically highlight which regions of an image
+contributed most to a model's prediction, using techniques such as:
+ - Saliency maps and heatmaps
+ - Superpixel importance
+ - Activation visualizations
+
+Classes:
+ ImageExplainer: Base class for image data explainers.
+ ImageExplanation: Base class for image data explanations.
+
+Example:
+ Using GradCAM for image explanation::
+
+ from xailib.explainers.gradcam_explainer import GradCAMImageExplainer
+ from xailib.models.pytorch_classifier_wrapper import pytorch_classifier_wrapper
+
+ # Wrap your model
+ bb = pytorch_classifier_wrapper(your_pytorch_model)
+
+ # Create and fit explainer
+ explainer = GradCAMImageExplainer(bb)
+ explainer.fit(target_layers=[model.layer4])
+
+ # Generate explanation
+ heatmap = explainer.explain(image, class_index)
+
+See Also:
+ :mod:`xailib.explainers.gradcam_explainer`: GradCAM implementation for image data.
+ :mod:`xailib.explainers.lime_explainer`: LIME implementation for image data.
+ :mod:`xailib.explainers.rise_explainer`: RISE implementation for image data.
+ :mod:`xailib.explainers.intgrad_explainer`: Integrated Gradients for image data.
+"""
from abc import abstractmethod
from xailib.xailib_base import Explainer, Explanation
class ImageExplainer(Explainer):
+ """
+ Abstract base class for image data explainers.
+
+ This class extends the base :class:`~xailib.xailib_base.Explainer` class
+ with functionality specific to image data. Image explainers work with
+ numpy arrays representing images and provide visual explanations
+ (typically heatmaps or saliency maps) for model predictions.
+
+ Subclasses implement specific explanation methods such as GradCAM,
+ LIME, RISE, or Integrated Gradients for image data.
+
+ Attributes:
+ Defined by subclasses. Common attributes include the black-box model
+ wrapper and target layers for gradient-based methods.
+
+ See Also:
+ :class:`xailib.explainers.gradcam_explainer.GradCAMImageExplainer`: GradCAM implementation.
+ :class:`xailib.explainers.lime_explainer.LimeXAIImageExplainer`: LIME implementation.
+ :class:`xailib.explainers.rise_explainer.RiseXAIImageExplainer`: RISE implementation.
+ """
def __init__(self):
+ """Initialize the ImageExplainer base class."""
super().__init__()
@abstractmethod
def fit(self, X, y):
+ """
+ Fit the explainer to the image training data.
+
+ For most image explainers, this method sets up the necessary
+ components for generating explanations (e.g., target layers for
+ GradCAM, mask generation for RISE).
+
+ Args:
+ X: Training images or configuration parameters.
+ The exact format depends on the specific method.
+ y: Training labels or additional configuration.
+
+ Returns:
+ None. The explainer is fitted in-place.
+ """
pass
@abstractmethod
def explain(self, b, x):
+ """
+ Generate an explanation for an image instance.
+
+ Args:
+ b: Black-box model or prediction function.
+ x: Image to explain as a numpy array.
+
+ Returns:
+ Explanation output, typically a heatmap or saliency map
+ as a numpy array with the same spatial dimensions as the input.
+ """
pass
class ImageExplanation(Explanation):
+ """
+ Abstract base class for image data explanations.
+
+ This class extends the base :class:`~xailib.xailib_base.Explanation` class
+ with functionality specific to image data. Image explanations typically
+ contain saliency maps, heatmaps, or segmentation-based importance values.
+
+ Note:
+ Most image explainers return the explanation directly (as a numpy
+ array) rather than wrapping it in an ImageExplanation object.
+ This class is provided for consistency and future extensions.
+
+ Attributes:
+ Defined by subclasses. Common attributes include the saliency map
+ and segment importance values.
+ """
def __init__(self):
+ """Initialize the ImageExplanation base class."""
super().__init__()
@abstractmethod
def getFeaturesImportance(self):
+ """
+ Get feature (region) importance values for the image.
+
+ For image data, "features" typically correspond to image regions
+ or superpixels.
+
+ Returns:
+ Importance values for image regions, or None if not available.
+ """
pass
@abstractmethod
def getExemplars(self):
+ """
+ Get exemplar images similar to the explained image.
+
+ Returns:
+ Exemplar images, or None if not supported.
+ """
pass
@abstractmethod
def getCounterExemplars(self):
+ """
+ Get counter-exemplar images with different predictions.
+
+ Returns:
+ Counter-exemplar images, or None if not supported.
+ """
pass
@abstractmethod
def getRules(self):
+ """
+ Get decision rules for the image prediction.
+
+ Returns:
+ Rules, or None if not supported for image explanations.
+ """
pass
@abstractmethod
def getCounterfactualRules(self):
+ """
+ Get counterfactual rules for the image prediction.
+
+ Returns:
+ Counterfactual rules, or None if not supported.
+ """
pass
diff --git a/src/xailib/xailib_tabular.py b/src/xailib/xailib_tabular.py
index 26fa600..4fd3238 100644
--- a/src/xailib/xailib_tabular.py
+++ b/src/xailib/xailib_tabular.py
@@ -1,3 +1,44 @@
+"""
+Tabular data explainability classes for XAI-Lib.
+
+This module provides base classes for explaining predictions on tabular
+(structured) data. It extends the base :class:`~xailib.xailib_base.Explainer`
+and :class:`~xailib.xailib_base.Explanation` classes with tabular-specific
+functionality, including interactive feature importance visualization.
+
+Tabular data explanations are commonly used for:
+ - Understanding feature contributions to predictions
+ - Generating human-readable decision rules
+ - Identifying similar and contrasting examples
+ - Creating counterfactual explanations
+
+Classes:
+ TabularExplanation: Base class for tabular data explanations.
+ TabularExplainer: Base class for tabular data explainers.
+
+Example:
+ Using LIME for tabular explanation::
+
+ from xailib.explainers.lime_explainer import LimeXAITabularExplainer
+ from xailib.models.sklearn_classifier_wrapper import sklearn_classifier_wrapper
+
+ # Wrap your model
+ bb = sklearn_classifier_wrapper(your_sklearn_model)
+
+ # Create and fit explainer
+ explainer = LimeXAITabularExplainer(bb)
+ explainer.fit(df, 'target_column', config={})
+
+ # Generate explanation
+ explanation = explainer.explain(instance)
+ explanation.plot_features_importance()
+
+See Also:
+ :mod:`xailib.explainers.lime_explainer`: LIME implementation for tabular data.
+ :mod:`xailib.explainers.shap_explainer_tab`: SHAP implementation for tabular data.
+ :mod:`xailib.explainers.lore_explainer`: LORE implementation for tabular data.
+"""
+
from abc import abstractmethod
from xailib.xailib_base import Explainer, Explanation
import pandas as pd
@@ -9,31 +50,117 @@
class TabularExplanation(Explanation):
+ """
+ Abstract base class for tabular data explanations.
+
+ This class extends the base :class:`~xailib.xailib_base.Explanation` class
+ with functionality specific to tabular (structured) data, including
+ interactive visualization of feature importance using Altair charts.
+
+ Subclasses should implement the abstract methods to provide access
+ to different types of explanation information (feature importance,
+ rules, exemplars, etc.).
+
+ Attributes:
+ Defined by subclasses. Common attributes include the raw explanation
+ object from the underlying library.
+
+ See Also:
+ :class:`xailib.explainers.lime_explainer.LimeXAITabularExplanation`: LIME explanation.
+ :class:`xailib.explainers.shap_explainer_tab.ShapXAITabularExplanation`: SHAP explanation.
+ :class:`xailib.explainers.lore_explainer.LoreTabularExplanation`: LORE explanation.
+ """
def __init__(self):
+ """Initialize the TabularExplanation base class."""
super().__init__()
@abstractmethod
def getFeaturesImportance(self):
+ """
+ Get feature importance values for the explained instance.
+
+ Returns:
+ Feature importance as a list of tuples, numpy array, or
+ pandas DataFrame. The exact format depends on the explanation
+ method. Returns None if feature importance is not available.
+ """
pass
@abstractmethod
def getExemplars(self):
+ """
+ Get exemplar instances similar to the explained instance.
+
+ Returns:
+ Exemplar instances with the same prediction, or None if
+ not supported by this explanation method.
+ """
pass
@abstractmethod
def getCounterExemplars(self):
+ """
+ Get counter-exemplar instances with different predictions.
+
+ Returns:
+ Counter-exemplar instances, or None if not supported
+ by this explanation method.
+ """
pass
@abstractmethod
def getRules(self):
+ """
+ Get decision rules explaining the prediction.
+
+ Returns:
+ Decision rules as a dictionary or list, or None if not
+ supported by this explanation method.
+ """
pass
@abstractmethod
def getCounterfactualRules(self):
+ """
+ Get counterfactual rules for alternative outcomes.
+
+ Returns:
+ Counterfactual rules describing how to change the prediction,
+ or None if not supported by this explanation method.
+ """
pass
def plot_features_importance_from(self, dataToPlot: pd.DataFrame, fontDimension=10):
+ """
+ Create an interactive feature importance visualization using Altair.
+
+ This method generates an interactive bar chart showing feature importance
+ values with a slider to filter features by importance threshold. Features
+ are color-coded by their importance value (positive vs negative).
+
+ Args:
+ dataToPlot (pd.DataFrame): DataFrame containing feature importance data
+ with columns:
+ - 'name': Feature names (string)
+ - 'value': Importance values (float)
+ fontDimension (int, optional): Base font size for the chart. Defaults to 10.
+
+ Returns:
+ None. Displays the interactive chart using IPython display.
+
+ Note:
+ This method is intended to be called within a Jupyter notebook
+ environment for proper rendering of the interactive chart.
+
+ Example:
+ >>> import pandas as pd
+ >>> data = pd.DataFrame({
+ ... 'name': ['feature1', 'feature2', 'feature3'],
+ ... 'value': [0.5, -0.3, 0.1]
+ ... })
+ >>> explanation.plot_features_importance_from(data, fontDimension=12)
+ """
fontSize = fontDimension
step = fontSize * 1.5
@@ -149,14 +276,62 @@ def plot_features_importance_from(self, dataToPlot: pd.DataFrame, fontDimension=
class TabularExplainer(Explainer):
+ """
+ Abstract base class for tabular data explainers.
+
+ This class extends the base :class:`~xailib.xailib_base.Explainer` class
+ with functionality specific to tabular (structured) data. Tabular
+ explainers work with pandas DataFrames and provide explanations
+ for predictions on structured data.
+
+ Subclasses implement specific explanation methods such as LIME, SHAP,
+ or LORE for tabular data.
+
+ Attributes:
+ Defined by subclasses. Common attributes include the black-box model
+ wrapper and configuration parameters.
+
+ See Also:
+ :class:`xailib.explainers.lime_explainer.LimeXAITabularExplainer`: LIME implementation.
+ :class:`xailib.explainers.shap_explainer_tab.ShapXAITabularExplainer`: SHAP implementation.
+ :class:`xailib.explainers.lore_explainer.LoreTabularExplainer`: LORE implementation.
+ """
def __init__(self):
+ """Initialize the TabularExplainer base class."""
super().__init__()
@abstractmethod
def fit(self, X, y, config):
+ """
+ Fit the explainer to the tabular training data.
+
+ Args:
+ X (pd.DataFrame): Training data as a pandas DataFrame.
+ y: Target column name (str) or target values.
+ config (dict): Configuration dictionary with method-specific parameters.
+ Common keys include:
+ - 'feature_selection': Feature selection method
+ - 'discretize_continuous': Whether to discretize continuous features
+ - 'sample_around_instance': Sampling strategy
+ - Additional method-specific parameters
+
+ Returns:
+ None. The explainer is fitted in-place.
+ """
pass
@abstractmethod
def explain(self, b, x) -> TabularExplanation:
+ """
+ Generate an explanation for a tabular data instance.
+
+ Args:
+ b: Black-box model or prediction function (depends on implementation).
+ x: Instance to explain as a numpy array or pandas Series.
+
+ Returns:
+ TabularExplanation: An explanation object containing feature importance,
+ rules, or other explanation information.
+ """
pass
diff --git a/src/xailib/xailib_text.py b/src/xailib/xailib_text.py
index a62bf26..d344c6a 100644
--- a/src/xailib/xailib_text.py
+++ b/src/xailib/xailib_text.py
@@ -1,43 +1,170 @@
+"""
+Text data explainability classes for XAI-Lib.
+
+This module provides base classes for explaining predictions on text data.
+It extends the base :class:`~xailib.xailib_base.Explainer` and
+:class:`~xailib.xailib_base.Explanation` classes with text-specific
+functionality.
+
+Text explanations typically highlight which words or phrases contributed
+most to a model's prediction. Common use cases include:
+ - Sentiment analysis explanation
+ - Text classification explanation
+ - Named entity recognition explanation
+
+Classes:
+ TextExplainer: Base class for text data explainers.
+ TextExplanation: Base class for text data explanations.
+
+Example:
+ Using LIME for text explanation::
+
+ from xailib.explainers.lime_explainer import LimeXAITextExplainer
+ from xailib.models.sklearn_classifier_wrapper import sklearn_classifier_wrapper
+
+ # Wrap your model
+ bb = sklearn_classifier_wrapper(your_text_classifier)
+
+ # Create and fit explainer
+ explainer = LimeXAITextExplainer(bb)
+ explainer.fit(class_names=['negative', 'positive'])
+
+ # Generate explanation
+ explanation = explainer.explain("This movie was great!")
+
+See Also:
+ :mod:`xailib.explainers.lime_explainer`: LIME implementation for text data.
+
+Note:
+ Text explanation support is currently being expanded. Additional
+ methods will be added in future releases.
+"""
from abc import abstractmethod
from xailib.xailib_base import Explainer, Explanation
class TextExplainer(Explainer):
+ """
+ Abstract base class for text data explainers.
+
+ This class extends the base :class:`~xailib.xailib_base.Explainer` class
+ with functionality specific to text data. Text explainers work with
+ strings or text documents and provide word/phrase-level importance
+ scores for model predictions.
+
+ Subclasses implement specific explanation methods such as LIME
+ for text classification models.
+
+ Attributes:
+ Defined by subclasses. Common attributes include the black-box model
+ wrapper and text preprocessing parameters.
+
+ See Also:
+ :class:`xailib.explainers.lime_explainer.LimeXAITextExplainer`: LIME implementation.
+ """
def __init__(self):
+ """Initialize the TextExplainer base class."""
super().__init__()
@abstractmethod
def fit(self, X, y):
+ """
+ Fit the explainer for text data.
+
+ For most text explainers, this method sets up the necessary
+ components for generating explanations (e.g., tokenizer,
+ class names).
+
+ Args:
+ X: Training texts or configuration parameters.
+ y: Training labels or class names.
+
+ Returns:
+ None. The explainer is fitted in-place.
+ """
pass
@abstractmethod
def explain(self, b, x):
+ """
+ Generate an explanation for a text instance.
+
+ Args:
+ b: Black-box model or prediction function.
+ x: Text to explain as a string.
+
+ Returns:
+ Explanation with word/phrase importance scores.
+ """
pass
class TextExplanation(Explanation):
+ """
+ Abstract base class for text data explanations.
+
+ This class extends the base :class:`~xailib.xailib_base.Explanation` class
+ with functionality specific to text data. Text explanations typically
+ contain word or phrase importance scores.
+
+ Attributes:
+ Defined by subclasses. Common attributes include word importance
+ scores and highlighted text segments.
+ """
def __init__(self):
+ """Initialize the TextExplanation base class."""
super().__init__()
@abstractmethod
def getFeaturesImportance(self):
+ """
+ Get word/phrase importance values for the text.
+
+ Returns:
+ Word importance scores as a list of tuples (word, importance),
+ or None if not available.
+ """
pass
@abstractmethod
def getExemplars(self):
+ """
+ Get exemplar texts similar to the explained text.
+
+ Returns:
+ Exemplar texts, or None if not supported.
+ """
pass
@abstractmethod
def getCounterExemplars(self):
+ """
+ Get counter-exemplar texts with different predictions.
+
+ Returns:
+ Counter-exemplar texts, or None if not supported.
+ """
pass
@abstractmethod
def getRules(self):
+ """
+ Get decision rules for the text prediction.
+
+ Returns:
+ Rules, or None if not supported for text explanations.
+ """
pass
@abstractmethod
def getCounterfactualRules(self):
+ """
+ Get counterfactual rules for the text prediction.
+
+ Returns:
+ Counterfactual rules, or None if not supported.
+ """
pass
diff --git a/src/xailib/xailib_transparent_by_design.py b/src/xailib/xailib_transparent_by_design.py
index a11dfaa..139d955 100644
--- a/src/xailib/xailib_transparent_by_design.py
+++ b/src/xailib/xailib_transparent_by_design.py
@@ -1,50 +1,199 @@
+"""
+Transparent-by-design model classes for XAI-Lib.
+
+This module provides base classes for inherently interpretable models
+that are transparent by design. Unlike post-hoc explanation methods,
+these models provide built-in interpretability without requiring
+additional explanation techniques.
+
+Examples of transparent-by-design models include:
+ - Neural Additive Models (NAM)
+ - Generalized Additive Models (GAM)
+ - Decision trees and rule-based models
+ - Linear models with interpretable features
+
+Classes:
+ Explainer: Base class for transparent models (extended with predict methods).
+ Explanation: Base class for transparent model explanations.
+
+Example:
+ Using a transparent-by-design model::
+
+ from xailib.explainers.nam_explainer_tab import NAMExplainer
+
+ # Create and fit the transparent model
+ explainer = NAMExplainer()
+ explainer.fit(X_train, y_train)
+
+ # Get predictions with built-in explanations
+ prediction = explainer.predict(X_test)
+ explanation = explainer.explain(X_test[0])
+
+Note:
+ Models in this module can both make predictions AND provide
+ explanations, unlike post-hoc explainers that only explain
+ existing black-box models.
+"""
from abc import ABC, abstractmethod
class Explainer(ABC):
+ """
+ Abstract base class for transparent-by-design models.
+
+ This class extends the standard explainer interface with prediction
+ methods, allowing transparent models to serve as both predictors
+ and explainers. Unlike post-hoc explanation methods, transparent
+ models provide inherent interpretability.
+
+ The workflow for transparent models:
+ 1. Initialize the model
+ 2. Call :meth:`fit` to train the model
+ 3. Call :meth:`predict` or :meth:`predict_proba` for predictions
+ 4. Call :meth:`explain` for interpretable explanations
+
+ Attributes:
+ Defined by subclasses. Common attributes include model parameters
+ and learned feature contributions.
+
+ See Also:
+ :class:`xailib.xailib_base.Explainer`: Base explainer for post-hoc methods.
+ :mod:`xailib.explainers.nam_explainer_tab`: NAM implementation.
+ """
def __init__(self):
+ """Initialize the transparent model base class."""
pass
@abstractmethod
def fit(self, X, y):
+ """
+ Fit the transparent model to training data.
+
+ Args:
+ X: Training features as a numpy array or pandas DataFrame.
+ y: Training labels or target values.
+
+ Returns:
+ None. The model is fitted in-place.
+ """
pass
@abstractmethod
def explain(self, x):
+ """
+ Generate an explanation for an instance.
+
+ For transparent models, explanations are derived directly from
+ the model's internal structure (e.g., feature contributions).
+
+ Args:
+ x: Instance to explain.
+
+ Returns:
+ Explanation: An explanation object with interpretable information.
+ """
pass
@abstractmethod
def predict(self, x):
+ """
+ Make predictions for input instances.
+
+ Args:
+ x: Input features for prediction.
+
+ Returns:
+ Predicted class labels or regression values.
+ """
pass
@abstractmethod
def predict_proba(self, x):
+ """
+ Get prediction probabilities for input instances.
+
+ Args:
+ x: Input features for prediction.
+
+ Returns:
+ Predicted class probabilities as a numpy array
+ of shape (n_samples, n_classes).
+ """
pass
class Explanation(ABC):
+ """
+ Abstract base class for transparent model explanations.
+
+ This class provides the standard interface for accessing explanation
+ information from transparent-by-design models. Explanations from
+ transparent models are typically more detailed and accurate than
+ post-hoc explanations.
+
+ Attributes:
+ Defined by subclasses. Common attributes include feature
+ contributions and model-specific interpretable components.
+ """
def __init__(self):
+ """Initialize the explanation base class."""
pass
@abstractmethod
def getFeaturesImportance(self):
+ """
+ Get feature importance values from the transparent model.
+
+ For transparent models, feature importance is typically
+ derived directly from the model's learned parameters.
+
+ Returns:
+ Feature importance values.
+ """
pass
@abstractmethod
def getExemplars(self):
+ """
+ Get exemplar instances.
+
+ Returns:
+ Exemplar instances, or None if not supported.
+ """
pass
@abstractmethod
def getCounterExemplars(self):
+ """
+ Get counter-exemplar instances.
+
+ Returns:
+ Counter-exemplar instances, or None if not supported.
+ """
pass
@abstractmethod
def getRules(self):
+ """
+ Get decision rules from the transparent model.
+
+ For rule-based transparent models, this returns the
+ learned decision rules.
+
+ Returns:
+ Decision rules, or None if not applicable.
+ """
pass
@abstractmethod
def getCounterfactualRules(self):
+ """
+ Get counterfactual rules.
+
+ Returns:
+ Counterfactual rules, or None if not supported.
+ """
pass
diff --git a/src/xailib/xailib_ts.py b/src/xailib/xailib_ts.py
index 55507cd..5743d98 100644
--- a/src/xailib/xailib_ts.py
+++ b/src/xailib/xailib_ts.py
@@ -1,3 +1,45 @@
+"""
+Time series data explainability classes for XAI-Lib.
+
+This module provides base classes for explaining predictions on time series data.
+It extends the base :class:`~xailib.xailib_base.Explainer` and
+:class:`~xailib.xailib_base.Explanation` classes with time series-specific
+functionality.
+
+Time series explanations typically highlight which time steps or temporal
+patterns contributed most to a model's prediction. Common use cases include:
+ - Anomaly detection explanation
+ - Time series classification explanation
+ - Forecasting explanation
+
+Classes:
+ TSExplainer: Base class for time series data explainers.
+ TSExplanation: Base class for time series data explanations.
+
+Example:
+ Using LASTS for time series explanation::
+
+ from xailib.explainers.lasts_explainer import LastsExplainer
+ from xailib.models.keras_ts_classifier_wrapper import KerasTSClassifierWrapper
+
+ # Wrap your model
+ bb = KerasTSClassifierWrapper(your_ts_model)
+
+ # Create and fit explainer
+ explainer = LastsExplainer(bb)
+ explainer.fit(X_train, y_train, config)
+
+ # Generate explanation
+ explanation = explainer.explain(time_series)
+
+See Also:
+ :mod:`xailib.explainers.lasts_explainer`: LASTS implementation for time series.
+
+Note:
+ Time series explanation support is currently being expanded.
+ Additional methods will be added in future releases.
+"""
+
from abc import abstractmethod
from xailib.xailib_base import Explainer, Explanation
import pandas as pd
@@ -9,43 +51,133 @@
class TSExplanation(Explanation):
+ """
+ Abstract base class for time series data explanations.
+
+ This class extends the base :class:`~xailib.xailib_base.Explanation` class
+ with functionality specific to time series data. Time series explanations
+ typically contain temporal importance scores and pattern-based explanations.
+
+ Attributes:
+ Defined by subclasses. Common attributes include temporal importance
+ scores and identified patterns.
+ """
def __init__(self):
+ """Initialize the TSExplanation base class."""
super().__init__()
@abstractmethod
def getFeaturesImportance(self):
+ """
+ Get temporal feature importance values.
+
+ For time series data, "features" may correspond to time steps,
+ temporal windows, or derived features (e.g., shapelets).
+
+ Returns:
+ Temporal importance values, or None if not available.
+ """
pass
@abstractmethod
def getExemplars(self):
+ """
+ Get exemplar time series similar to the explained series.
+
+ Returns:
+ Exemplar time series, or None if not supported.
+ """
pass
@abstractmethod
def getCounterExemplars(self):
+ """
+ Get counter-exemplar time series with different predictions.
+
+ Returns:
+ Counter-exemplar time series, or None if not supported.
+ """
pass
@abstractmethod
def getRules(self):
+ """
+ Get decision rules for the time series prediction.
+
+ For time series, rules may describe temporal patterns or
+ conditions over time windows.
+
+ Returns:
+ Rules, or None if not supported.
+ """
pass
@abstractmethod
def getCounterfactualRules(self):
+ """
+ Get counterfactual rules for the time series prediction.
+
+ Returns:
+ Counterfactual rules describing temporal changes
+ that would alter the prediction, or None if not supported.
+ """
pass
class TSExplainer(Explainer):
+ """
+ Abstract base class for time series data explainers.
+
+ This class extends the base :class:`~xailib.xailib_base.Explainer` class
+ with functionality specific to time series data. Time series explainers
+ work with sequential data and provide temporal importance explanations
+ for model predictions.
+
+ Subclasses implement specific explanation methods such as LASTS
+ for time series classification models.
+
+ Attributes:
+ Defined by subclasses. Common attributes include the black-box model
+ wrapper and temporal configuration parameters.
+
+ See Also:
+ :class:`xailib.explainers.lasts_explainer.LastsExplainer`: LASTS implementation.
+ """
def __init__(self):
+ """Initialize the TSExplainer base class."""
super().__init__()
@abstractmethod
def fit(self, X, y, config):
+ """
+ Fit the explainer to the time series training data.
+
+ Args:
+ X: Training time series data, typically as a numpy array
+ of shape (n_samples, n_timesteps) or
+ (n_samples, n_timesteps, n_features).
+ y: Training labels or target values.
+ config (dict): Configuration dictionary with method-specific
+ parameters for the time series explainer.
+
+ Returns:
+ None. The explainer is fitted in-place.
+ """
pass
@abstractmethod
def explain(self, b, x) -> TSExplanation:
- pass
-
-
-
+ """
+ Generate an explanation for a time series instance.
+
+ Args:
+ b: Black-box model or prediction function.
+ x: Time series to explain as a numpy array.
+
+ Returns:
+ TSExplanation: An explanation object containing temporal
+ importance scores and pattern information.
+ """
+ pass
\ No newline at end of file
From 7c5f3775f4d2c57336e668f43078a2b2258b261e Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 26 Nov 2025 09:25:17 +0000
Subject: [PATCH 3/6] Add docstrings to explainer modules (LIME, ABELE, LASTS)
Co-authored-by: rinziv <12544167+rinziv@users.noreply.github.com>
---
src/xailib/explainers/abele_explainer.py | 160 ++++++++-
src/xailib/explainers/lasts_explainer.py | 170 +++++++++-
src/xailib/explainers/lime_explainer.py | 401 +++++++++++++++++++----
3 files changed, 651 insertions(+), 80 deletions(-)
diff --git a/src/xailib/explainers/abele_explainer.py b/src/xailib/explainers/abele_explainer.py
index b118f5a..36f8003 100644
--- a/src/xailib/explainers/abele_explainer.py
+++ b/src/xailib/explainers/abele_explainer.py
@@ -1,3 +1,35 @@
+"""
+ABELE (Adversarial Black-box Explainer generating Latent Exemplars) for image data.
+
+This module provides the ABELE explainer for image classification models.
+ABELE generates explanations by learning a latent representation of images
+and using it to find exemplars, counter-exemplars, and generate rules.
+
+ABELE is particularly useful for:
+ - Finding prototypical examples that explain a prediction
+ - Generating counterfactual examples showing what would change the prediction
+ - Extracting human-readable rules from image classifications
+
+Classes:
+ ABELEImageExplanation: Explanation class for ABELE.
+ ABELEImageExplainer: Explainer class implementing ABELE algorithm.
+
+References:
+ Guidotti, R., Monreale, A., Matwin, S., & Pedreschi, D. (2019).
+ Black Box Explanation by Learning Image Exemplars in the Latent Feature Space.
+ ECML PKDD.
+
+Example:
+ >>> from xailib.explainers.abele_explainer import ABELEImageExplainer
+ >>> from xailib.models.keras_classifier_wrapper import keras_classifier_wrapper
+ >>>
+ >>> bb = keras_classifier_wrapper(trained_model)
+ >>> explainer = ABELEImageExplainer(bb)
+ >>> explainer.fit(config={'...': '...'})
+ >>> explanation = explainer.explain(image)
+ >>> prototypes = explanation.getExemplars(num_prototypes=5)
+"""
+
from xailib.xailib_image import ImageExplainer, ImageExplanation
from xailib.models.bbox import AbstractBBox
from externals.ABELE.ilore.ilorem import ILOREM
@@ -5,33 +37,157 @@
class ABELEImageExplanation(ImageExplanation):
+ """
+ Explanation class for ABELE image explanations.
+
+ This class wraps the ABELE explanation result and provides methods
+ to access different aspects of the explanation: rules, exemplars,
+ counter-exemplars, and feature importance.
+
+ Args:
+ abele_exp: The raw ABELE explanation object from ILOREM.
+
+ Attributes:
+ exp: The underlying ABELE explanation object.
+ """
+
def __init__(self, abele_exp):
+ """
+ Initialize the ABELE explanation.
+
+ Args:
+ abele_exp: Raw explanation from ILOREM explain_instance.
+ """
super().__init__()
self.exp = abele_exp
def getFeaturesImportance(self, features=None, samples=400):
+ """
+ Get the image-based rule showing important features.
+
+ Args:
+ features: Optional feature specification for the rule.
+ samples (int): Number of samples to use for rule extraction.
+ Defaults to 400.
+
+ Returns:
+ Image rule highlighting important features for the prediction.
+ """
return self.exp.get_image_rule(features=features, samples=samples)
def getExemplars(self, num_prototypes):
+ """
+ Get prototype images that support the prediction.
+
+ Prototypes are images that satisfy the decision rule and
+ received the same prediction as the query image.
+
+ Args:
+ num_prototypes (int): Number of prototype images to return.
+
+ Returns:
+ List of prototype images respecting the decision rule.
+ """
return self.exp.get_prototypes_respecting_rule(num_prototypes=num_prototypes)
def getCounterExemplars(self):
+ """
+ Get counterfactual prototype images.
+
+ Counterfactual prototypes are images that would receive a
+ different prediction from the query image.
+
+ Returns:
+ List of counterfactual prototype images.
+ """
return self.exp.get_counterfactual_prototypes()
def getRules(self):
+ """
+ Get the decision rule as a human-readable string.
+
+ Returns:
+ str: String representation of the decision rule.
+ """
return self.exp.rstr()
def getCounterfactualRules(self):
+ """
+ Get counterfactual rules as a human-readable string.
+
+ Returns:
+ str: String representation of the counterfactual rules.
+ """
return self.exp.cstr()
+
class ABELEImageExplainer(ImageExplainer):
+ """
+ ABELE (Adversarial Black-box Explainer generating Latent Exemplars) explainer.
+
+ This explainer uses the ABELE algorithm to generate explanations for
+ image classification models by learning a latent representation and
+ extracting decision rules, exemplars, and counterfactuals.
+
+ Args:
+ bb (AbstractBBox): The black-box model wrapper to explain.
+
+ Attributes:
+ bb: The black-box model wrapper.
+ exp: The ILOREM explainer instance (after fitting).
+
+ Example:
+ >>> explainer = ABELEImageExplainer(model_wrapper)
+ >>> explainer.fit(config={
+ ... 'autoencoder': autoencoder,
+ ... 'latent_dim': 128,
+ ... # ... other ILOREM parameters
+ ... })
+ >>> explanation = explainer.explain(query_image)
+ """
+
def __init__(self, bb: AbstractBBox):
+ """
+ Initialize the ABELE explainer.
+
+ Args:
+ bb (AbstractBBox): Black-box model wrapper to explain.
+ """
super().__init__()
self.bb = bb
def fit(self, config):
+ """
+ Configure the ABELE explainer with the given parameters.
+
+ Args:
+ config (dict): Configuration dictionary with ILOREM parameters.
+ See ILOREM documentation for available options.
+
+ Returns:
+ None. The explainer is configured in-place.
+ """
self.exp = ILOREM(**config)
-
+
def explain(self, img, num_samples=300, use_weights=True, metric=neuclidean):
- return ABELEImageExplanation(self.exp.explain_instance(img, num_samples=num_samples, use_weights=use_weights, metric=metric))
+ """
+ Generate an ABELE explanation for an image.
+
+ Args:
+ img: Query image to explain.
+ num_samples (int): Number of samples for neighborhood generation.
+ Defaults to 300.
+ use_weights (bool): Whether to use weighted sampling.
+ Defaults to True.
+ metric: Distance metric for similarity computation.
+ Defaults to neuclidean (normalized Euclidean).
+ Returns:
+ ABELEImageExplanation: Explanation object with access to rules,
+ exemplars, and counterfactuals.
+ """
+ return ABELEImageExplanation(
+ self.exp.explain_instance(
+ img, num_samples=num_samples, use_weights=use_weights, metric=metric
+ )
+ )
\ No newline at end of file
diff --git a/src/xailib/explainers/lasts_explainer.py b/src/xailib/explainers/lasts_explainer.py
index bdb5e51..308d83f 100644
--- a/src/xailib/explainers/lasts_explainer.py
+++ b/src/xailib/explainers/lasts_explainer.py
@@ -1,3 +1,34 @@
+"""
+LASTS (Local Agnostic Subsequence-based Time Series) explainer for time series data.
+
+This module provides the LASTS explainer for time series classification models.
+LASTS generates explanations by identifying subsequences (shapelets) that are
+important for the prediction, along with exemplar and counter-exemplar time series.
+
+LASTS is particularly useful for:
+ - Understanding which parts of a time series led to a prediction
+ - Finding similar time series (exemplars) with the same prediction
+ - Finding contrasting time series (counter-exemplars) with different predictions
+
+Classes:
+ LastsTSExplanation: Explanation class for LASTS.
+ LastsExplainer: Explainer class implementing LASTS algorithm.
+
+Example:
+ >>> from xailib.explainers.lasts_explainer import LastsExplainer
+ >>> from xailib.models.keras_ts_classifier_wrapper import keras_classifier_wrapper
+ >>>
+ >>> bb = keras_classifier_wrapper(trained_ts_model)
+ >>> explainer = LastsExplainer(bb)
+ >>> explainer.fit(config={
+ ... 'encoder': encoder,
+ ... 'decoder': decoder,
+ ... 'labels': ['class_0', 'class_1']
+ ... })
+ >>> explanation = explainer.explain(time_series)
+ >>> exemplars = explanation.getExemplars()
+"""
+
from xailib.xailib_ts import TSExplainer, TSExplanation
from xailib.models.bbox import AbstractBBox
from externals.late.late.explainers import lasts
@@ -8,43 +39,168 @@
class LastsTSExplanation(TSExplanation):
+ """
+ Explanation class for LASTS time series explanations.
+
+ This class wraps the LASTS explanation result and provides methods
+ to access exemplar and counter-exemplar time series.
+
+ Args:
+ lasts_exp (dict): The raw LASTS explanation dictionary containing
+ 'Zplus' (exemplars) and 'Zminus' (counter-exemplars).
+
+ Attributes:
+ exp (dict): The underlying LASTS explanation dictionary.
+ """
+
def __init__(self, lasts_exp):
+ """
+ Initialize the LASTS explanation.
+
+ Args:
+ lasts_exp (dict): Raw explanation from LASTS explainer.
+ """
super().__init__()
self.exp = lasts_exp
def getFeaturesImportance(self):
+ """
+ Get temporal feature importance values.
+
+ Note:
+ LASTS does not provide direct feature importance.
+ Use getExemplars() and getCounterExemplars() for explanation.
+
+ Returns:
+ None: Feature importance is not available for LASTS.
+ """
return None
def getExemplars(self):
+ """
+ Get exemplar time series with the same prediction.
+
+ Exemplars (Z+) are time series from the neighborhood that
+ received the same prediction as the query time series.
+
+ Returns:
+ numpy.ndarray: Array of exemplar time series.
+ """
return self.exp['Zplus']
def getCounterExemplars(self):
+ """
+ Get counter-exemplar time series with different predictions.
+
+ Counter-exemplars (Z-) are time series that would receive
+ a different prediction from the query time series.
+
+ Returns:
+ numpy.ndarray: Array of counter-exemplar time series.
+ """
return self.exp['Zminus']
def getRules(self):
+ """
+ Get decision rules for the prediction.
+
+ Note:
+ LASTS does not provide explicit decision rules.
+
+ Returns:
+ None: Rules are not available for LASTS.
+ """
return None
def getCounterfactualRules(self):
+ """
+ Get counterfactual rules.
+
+ Note:
+ LASTS does not provide explicit counterfactual rules.
+
+ Returns:
+ None: Counterfactual rules are not available for LASTS.
+ """
return None
+
class LastsExplainer(TSExplainer):
+ """
+ LASTS (Local Agnostic Subsequence-based Time Series) explainer.
+
+ This explainer uses the LASTS algorithm to generate explanations for
+ time series classification models. It works by generating a neighborhood
+ in latent space using an encoder-decoder architecture.
+
+ Args:
+ bb (AbstractBBox): The black-box model wrapper to explain.
+ Attributes:
+ bb: The black-box model wrapper.
+ neighborhood_generator: Generator for the latent neighborhood.
+ expl: The LASTS explainer instance (after fitting).
+ config (dict): Configuration parameters.
+
+ Example:
+ >>> explainer = LastsExplainer(model_wrapper)
+ >>> explainer.fit(config={
+ ... 'encoder': trained_encoder,
+ ... 'decoder': trained_decoder,
+ ... 'labels': ['normal', 'anomaly'],
+ ... 'n_neighbors': 100
+ ... })
+ >>> explanation = explainer.explain(query_ts)
+ """
def __init__(self, bb: AbstractBBox):
+ """
+ Initialize the LASTS explainer.
+
+ Args:
+ bb (AbstractBBox): Black-box model wrapper to explain.
+ """
super().__init__()
self.bb = bb
def fit(self, config):
- #qui passiamo i parametri da inizializzare, tra cui encoder, decoder, vicinato etc
- #passiamo anche i parametri per generare il vicinato
- self.neighborhood_generator = neighborhood_generators.NeighborhoodGenerator(self.bb, config.get('decoder'))
- self.expl = lasts.Lasts(self.bb, encoder = config.get('encoder'), decoder = config.get('decoder'), neighborhood_generator= self.neighborhood_generator, labels=config.get('labels',None))
- self.config = config
-
+ """
+ Configure the LASTS explainer with encoder, decoder, and parameters.
+ Args:
+ config (dict): Configuration dictionary containing:
+ - 'encoder': Trained encoder model for latent space projection
+ - 'decoder': Trained decoder model for reconstruction
+ - 'labels' (optional): List of class label names
+ - Additional neighborhood generation parameters
+ Returns:
+ None. The explainer is configured in-place.
+ """
+ self.neighborhood_generator = neighborhood_generators.NeighborhoodGenerator(
+ self.bb, config.get('decoder')
+ )
+ self.expl = lasts.Lasts(
+ self.bb,
+ encoder=config.get('encoder'),
+ decoder=config.get('decoder'),
+ neighborhood_generator=self.neighborhood_generator,
+ labels=config.get('labels', None)
+ )
+ self.config = config
def explain(self, x, z_fixed=None):
- #qui passiamo la x e la z_fixed che serve per l'encoder
+ """
+ Generate a LASTS explanation for a time series.
+
+ Args:
+ x: Query time series to explain.
+ z_fixed: Optional fixed latent representation for the encoder.
+ If None, the encoder will compute it from x.
+
+ Returns:
+ LastsTSExplanation: Explanation object with access to exemplars
+ and counter-exemplars.
+ """
explanation = self.expl.generate_neighborhood(x, z_fixed, **self.config)
return LastsTSExplanation(explanation)
diff --git a/src/xailib/explainers/lime_explainer.py b/src/xailib/explainers/lime_explainer.py
index 68fa11b..dcdb677 100644
--- a/src/xailib/explainers/lime_explainer.py
+++ b/src/xailib/explainers/lime_explainer.py
@@ -1,3 +1,44 @@
+"""
+LIME (Local Interpretable Model-agnostic Explanations) implementation for XAI-Lib.
+
+This module provides LIME explainers for tabular, image, and text data.
+LIME is a popular explanation method that approximates the behavior of
+a black-box model locally using an interpretable surrogate model.
+
+LIME works by:
+ 1. Generating a neighborhood of perturbed samples around the instance to explain
+ 2. Getting predictions for these samples from the black-box model
+ 3. Training an interpretable model (e.g., linear model) on the neighborhood
+ 4. Using the interpretable model to explain the prediction
+
+Classes:
+ LimeXAITabularExplanation: Explanation class for LIME tabular explanations.
+ LimeXAITabularExplainer: LIME explainer for tabular data.
+ LimeXAIImageExplainer: LIME explainer for image data.
+ LimeXAITextExplainer: LIME explainer for text data.
+
+References:
+ Ribeiro, M. T., Singh, S., & Guestrin, C. (2016).
+ "Why Should I Trust You?": Explaining the Predictions of Any Classifier.
+ KDD 2016.
+
+Example:
+ Using LIME for tabular data::
+
+ from xailib.explainers.lime_explainer import LimeXAITabularExplainer
+ from xailib.models.sklearn_classifier_wrapper import sklearn_classifier_wrapper
+
+ bb = sklearn_classifier_wrapper(trained_model)
+ explainer = LimeXAITabularExplainer(bb)
+ explainer.fit(df, 'target', config={'discretize_continuous': True})
+ explanation = explainer.explain(instance)
+ explanation.plot_features_importance()
+
+See Also:
+ :mod:`lime`: The underlying LIME library.
+ :class:`xailib.explainers.shap_explainer_tab.ShapXAITabularExplainer`: Alternative explanation method.
+"""
+
import pandas as pd
from skimage.segmentation import mark_boundaries
import matplotlib.pyplot as plt
@@ -14,183 +55,401 @@
class LimeXAITabularExplanation(TabularExplanation):
+ """
+ Explanation class for LIME tabular explanations.
+
+ This class wraps the LIME explanation result and provides methods
+ to access feature importance and visualize the explanation.
+
+ Args:
+ lime_exp: The raw LIME explanation object.
+
+ Attributes:
+ exp: The underlying LIME explanation object.
+
+ Example:
+ >>> explanation = explainer.explain(instance)
+ >>> importance = explanation.getFeaturesImportance()
+ >>> explanation.plot_features_importance()
+ """
+
def __init__(self, lime_exp):
+ """
+ Initialize the LIME explanation.
+
+ Args:
+ lime_exp: Raw explanation from LimeTabularExplainer.
+ """
super().__init__()
self.exp = lime_exp
def getFeaturesImportance(self):
+ """
+ Get feature importance as a list of (feature, weight) tuples.
+
+ Returns:
+ list: List of tuples (feature_description, weight) showing
+ how each feature contributed to the prediction.
+ """
return self.exp.as_list()
def getExemplars(self):
+ """
+ Get exemplar instances.
+
+ Note:
+ LIME does not provide exemplars.
+
+ Returns:
+ None: Not available for LIME.
+ """
return None
def getCounterExemplars(self):
+ """
+ Get counter-exemplar instances.
+
+ Note:
+ LIME does not provide counter-exemplars.
+
+ Returns:
+ None: Not available for LIME.
+ """
return None
def getRules(self):
+ """
+ Get decision rules.
+
+ Note:
+ LIME provides feature weights, not explicit rules.
+ Use getFeaturesImportance() instead.
+
+ Returns:
+ None: Not available for LIME.
+ """
return None
def getCounterfactualRules(self):
+ """
+ Get counterfactual rules.
+
+ Note:
+ LIME does not provide counterfactual rules.
+
+ Returns:
+ None: Not available for LIME.
+ """
return None
def plot_features_importance(self, fontDimension=10):
- #data prepraration
-
- dataToPlot=pd.DataFrame(self.exp.as_list(),columns=['name','value'])
+ """
+ Plot an interactive visualization of feature importance.
+
+ Creates an Altair chart showing feature weights with an
+ interactive slider to filter by importance threshold.
+
+ Args:
+ fontDimension (int, optional): Base font size for the chart.
+ Defaults to 10.
+
+ Returns:
+ None. Displays the chart using IPython display.
+ """
+ dataToPlot = pd.DataFrame(self.exp.as_list(), columns=['name', 'value'])
dataToPlot['value'] = dataToPlot['value'].astype('float64')
super().plot_features_importance_from(dataToPlot, fontDimension)
+
class LimeXAITabularExplainer(TabularExplainer):
+ """
+ LIME explainer for tabular data.
+
+ This explainer uses LIME (Local Interpretable Model-agnostic Explanations)
+ to explain predictions on tabular data by training a local linear model.
+
+ Args:
+ bb (AbstractBBox): The black-box model wrapper to explain.
+
+ Attributes:
+ bb: The black-box model wrapper.
+ lime_explainer: The underlying LimeTabularExplainer (after fitting).
+
+ Example:
+ >>> explainer = LimeXAITabularExplainer(model_wrapper)
+ >>> explainer.fit(df, 'target', config={
+ ... 'discretize_continuous': True,
+ ... 'feature_selection': 'auto'
+ ... })
+ >>> explanation = explainer.explain(instance, num_samples=1000)
+ """
+
lime_explainer = None
def __init__(self, bb: AbstractBBox):
+ """
+ Initialize the LIME tabular explainer.
+
+ Args:
+ bb (AbstractBBox): Black-box model wrapper to explain.
+ """
super().__init__()
self.bb = bb
def fit(self, _df: pd.DataFrame, class_name, config):
+ """
+ Fit the LIME explainer to the training data.
+
+ Args:
+ _df (pd.DataFrame): Training DataFrame with features and target.
+ class_name (str): Name of the target column.
+ config (dict): Configuration dictionary with optional parameters:
+ - 'feature_selection': Feature selection method ('auto', 'forward', etc.)
+ - 'discretize_continuous' (bool): Whether to discretize continuous features
+ - 'discretizer': Discretizer type ('quartile' or 'decile')
+ - 'sample_around_instance' (bool): Sampling strategy
+ - 'kernel_width': Width of the kernel for weighting
+ - 'kernel': Custom kernel function
+
+ Returns:
+ None. The explainer is fitted in-place.
+ """
df, feature_names, class_values, numeric_columns, \
_, _, _ = prepare_dataset(_df, class_name)
- feature_selection=config['feature_selection'] if 'feature_selection' in config else None
+ feature_selection = config['feature_selection'] if 'feature_selection' in config else None
discretize_continuous = config['discretize_continuous'] if 'discretize_continuous' in config else False
discretizer = config['discretizer'] if 'discretizer' in config else 'quartile'
sample_around_instance = config['sample_around_instance'] if 'sample_around_instance' in config else False
kernel_width = config['kernel_width'] if 'kernel_width' in config else None
kernel = config['kernel'] if 'kernel' in config else None
- self.lime_explainer = LimeTabularExplainer(df[feature_names].values, feature_names=feature_names,
- class_names=class_values, feature_selection=feature_selection,
- discretize_continuous=discretize_continuous, discretizer=discretizer,
- sample_around_instance=sample_around_instance, kernel_width=kernel_width,
- kernel=kernel)
+ self.lime_explainer = LimeTabularExplainer(
+ df[feature_names].values, feature_names=feature_names,
+ class_names=class_values, feature_selection=feature_selection,
+ discretize_continuous=discretize_continuous, discretizer=discretizer,
+ sample_around_instance=sample_around_instance, kernel_width=kernel_width,
+ kernel=kernel
+ )
+ def explain(self, x, classifier_fn=None, num_samples=1000, top_labels=5):
+ """
+ Generate a LIME explanation for a tabular instance.
+ Args:
+ x: Instance to explain as a numpy array.
+ classifier_fn (callable, optional): Custom prediction function.
+ If None, uses the black-box model's predict_proba.
+ num_samples (int): Number of samples in the neighborhood.
+ Defaults to 1000.
+ top_labels (int): Number of top labels to explain.
+ Defaults to 5.
- def explain(self, x, classifier_fn=None, num_samples=1000, top_labels=5):
+ Returns:
+ LimeXAITabularExplanation: Explanation object with feature weights.
+ """
if classifier_fn:
self.classifier_fn = classifier_fn
else:
self.classifier_fn = self.bb.predict_proba
- exp = self.lime_explainer.explain_instance(x,
- self.classifier_fn,
- num_samples=num_samples,
- top_labels=top_labels)
+ exp = self.lime_explainer.explain_instance(
+ x,
+ self.classifier_fn,
+ num_samples=num_samples,
+ top_labels=top_labels
+ )
return LimeXAITabularExplanation(exp)
def plot_lime_values(self, exp, range_start, range_end):
+ """
+ Plot LIME feature importance values as a bar chart.
+
+ Args:
+ exp: LIME explanation (list of (feature, weight) tuples).
+ range_start (int): Start index for features to display.
+ range_end (int): End index for features to display.
+
+ Returns:
+ None. Displays the matplotlib figure.
+ """
feature_names = [a_tuple[0] for a_tuple in exp]
exp = [a_tuple[1] for a_tuple in exp]
plt.rcParams.update({'font.size': 20})
plt.figure(figsize=(10, 8))
plt.bar(feature_names[range_start:range_end], exp[range_start:range_end], facecolor='lightblue', width=0.5)
- # You can specify a rotation for the tick labels in degrees or with keywords.
plt.xticks(feature_names[range_start:range_end], rotation='vertical')
- # Pad margins so that markers don't get clipped by the axes
plt.margins(0.1)
- # Tweak spacing to prevent clipping of tick-labels
plt.subplots_adjust(bottom=0.25)
plt.show()
-
class LimeXAIImageExplainer(ImageExplainer):
+ """
+ LIME explainer for image data.
+
+ This explainer uses LIME to explain image classification predictions
+ by segmenting the image and determining which segments are most
+ important for the prediction.
+
+ Args:
+ bb (AbstractBBox): The black-box model wrapper to explain.
+
+ Attributes:
+ bb: The black-box model wrapper.
+ lime_explainer: The underlying LimeImageExplainer (after fitting).
+ """
+
lime_explainer = None
def __init__(self, bb: AbstractBBox):
"""
- Arguments:
- bb: black box model
+ Initialize the LIME image explainer.
+
+ Args:
+ bb (AbstractBBox): Black-box model wrapper to explain.
"""
super().__init__()
self.bb = bb
def fit(self, verbose=False):
"""
- Create the explainer, extra parameters will be set in the explain function
+ Initialize the LIME image explainer.
+
+ Args:
+ verbose (bool): Whether to print verbose output.
+ Defaults to False.
+
+ Returns:
+ None. The explainer is initialized in-place.
"""
- self.lime_explainer = LimeImageExplainer(verbose = False)
+ self.lime_explainer = LimeImageExplainer(verbose=False)
def explain(self, image, classifier_fn=None, segmentation_fn=None, top_labels=5, num_samples=1000):
"""
- Return LIME explanation
- Arguments:
- image: query image to explain
- classifier_fn: [None] function that takes as input an array of images (the LIME neighbourhood) and return an array of (num_images,num_classes)
- If None will use black_box.predict function
- top_labels: For multiclass problems select the best top_labels from the results to produce the explanation
- num_samples: number of points in the generated neighbourhood
+ Generate a LIME explanation for an image.
+
+ Args:
+ image: Query image to explain as a numpy array.
+ classifier_fn (callable, optional): Function that takes images and
+ returns predictions. If None, uses black_box.predict.
+ segmentation_fn (callable, optional): Function to segment the image.
+ If None, uses quickshift segmentation.
+ top_labels (int): Number of top labels to explain. Defaults to 5.
+ num_samples (int): Number of perturbed images to generate.
+ Defaults to 1000.
+
+ Returns:
+ LIME ImageExplanation object with superpixel importance values.
"""
if classifier_fn:
self.classifier_fn = classifier_fn
else:
self.classifier_fn = self.bb.predict
-
- exp = self.lime_explainer.explain_instance(image,
- self.classifier_fn,
- segmentation_fn=segmentation_fn,
- top_labels=top_labels,
- hide_color=0,
- num_samples=num_samples)
+
+ exp = self.lime_explainer.explain_instance(
+ image,
+ self.classifier_fn,
+ segmentation_fn=segmentation_fn,
+ top_labels=top_labels,
+ hide_color=0,
+ num_samples=num_samples
+ )
return exp
-
- def plot_lime_values(self, image, explanation, figsize=(15,5)):
+
+ def plot_lime_values(self, image, explanation, figsize=(15, 5)):
"""
- Plot a three figure plot: [query image, heatmap of superpixels, overlap of the twos]
- Arguments:
- image: image to explain used in the explain function
- explanation: explanation returned by the explain function
- figsize: tuple of figure dimension
+ Plot a visualization of the LIME image explanation.
+
+ Creates a three-panel figure showing:
+ 1. The original query image
+ 2. A heatmap of superpixel importance
+ 3. An overlay of the heatmap on the original image
+
+ Args:
+ image: The original image used in the explain function.
+ explanation: LIME explanation object returned by explain().
+ figsize (tuple): Figure size as (width, height). Defaults to (15, 5).
+
+ Returns:
+ None. Displays the matplotlib figure.
"""
-
- F, ax = plt.subplots(1,3,figsize=figsize)
+ F, ax = plt.subplots(1, 3, figsize=figsize)
ax[0].imshow(image)
ax[0].axis('off')
ax[0].set_title('Query Image')
-
- #plot heatmap
- ind = explanation.top_labels[0]
+
+ # plot heatmap
+ ind = explanation.top_labels[0]
dict_heatmap = dict(explanation.local_exp[ind])
- heatmap = np.vectorize(dict_heatmap.get)(explanation.segments)
- ax[1].imshow(heatmap, cmap = 'coolwarm', vmin = -heatmap.max(), vmax = heatmap.max())
+ heatmap = np.vectorize(dict_heatmap.get)(explanation.segments)
+ ax[1].imshow(heatmap, cmap='coolwarm', vmin=-heatmap.max(), vmax=heatmap.max())
ax[1].axis('off')
ax[1].set_title('Super Pixel Heatmap Explanation')
-
- #plot overlap
+
+ # plot overlap
ax[2].imshow(image)
- ax[2].imshow(heatmap,alpha=0.5,cmap='coolwarm')
+ ax[2].imshow(heatmap, alpha=0.5, cmap='coolwarm')
ax[2].axis('off')
- ax[2].set_title('Overlap of Query Image and Heatmap');
-
-
+ ax[2].set_title('Overlap of Query Image and Heatmap')
+
+
class LimeXAITextExplainer(TextExplainer):
+ """
+ LIME explainer for text data.
+
+ This explainer uses LIME to explain text classification predictions
+ by perturbing words in the text and measuring their impact on predictions.
+
+ Args:
+ bb (AbstractBBox): The black-box model wrapper to explain.
+
+ Attributes:
+ bb: The black-box model wrapper.
+ lime_explainer: The underlying LimeTextExplainer (after fitting).
+ """
+
lime_explainer = None
def __init__(self, bb: AbstractBBox):
"""
- Arguments:
- bb: black box model
+ Initialize the LIME text explainer.
+
+ Args:
+ bb (AbstractBBox): Black-box model wrapper to explain.
"""
super().__init__()
self.bb = bb
def fit(self, class_names=None, verbose=False):
"""
- Create the explainer,
- Arguments:
- class_names: [None] list of class names, ordered according to whatever the
- classifier is using. If not present, class names will be '0',
- '1', ...
- verbose: [False] if true, print local prediction values from linear model
+ Initialize the LIME text explainer.
+
+ Args:
+ class_names (list, optional): List of class names ordered
+ according to the classifier output. If None, class names
+ will be '0', '1', etc.
+ verbose (bool): Whether to print verbose output.
+ Defaults to False.
+
+ Returns:
+ None. The explainer is initialized in-place.
"""
- self.lime_explainer = LimeTextExplainer(class_names = class_names, verbose = False)
+ self.lime_explainer = LimeTextExplainer(class_names=class_names, verbose=False)
def explain(self, sentence, classifier_fn=None, num_samples=1000, plot=False):
"""
- Return LIME explanation
- Arguments:
- sentence: query text to explain
- classifier_fn: [None] function that takes as input an array of images (the LIME neighbourhood) and return an array of (num_images,num_classes)
- If None will use black_box.predict function
- num_samples: [1000] number of points in the generated neighbourhood
+ Generate a LIME explanation for a text sentence.
+
+ Args:
+ sentence (str): Query text to explain.
+ classifier_fn (callable, optional): Function that takes text
+ and returns predictions. If None, uses black_box.predict.
+ num_samples (int): Number of perturbed texts to generate.
+ Defaults to 1000.
+ plot (bool): Whether to display a matplotlib plot of the
+ explanation. Defaults to False.
+
+ Returns:
+ LIME TextExplanation object with word importance values.
"""
if classifier_fn:
self.classifier_fn = classifier_fn
From 673027a21c5ea540b86cf539462a42887b23edf7 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 26 Nov 2025 09:27:14 +0000
Subject: [PATCH 4/6] Fix documentation comments for clarity per code review
feedback
Co-authored-by: rinziv <12544167+rinziv@users.noreply.github.com>
---
src/xailib/models/keras_ts_classifier_wrapper.py | 4 ++--
src/xailib/models/sklearn_ts_classifier_wrapper.py | 10 ++++++----
2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/src/xailib/models/keras_ts_classifier_wrapper.py b/src/xailib/models/keras_ts_classifier_wrapper.py
index c64fdeb..459aba7 100644
--- a/src/xailib/models/keras_ts_classifier_wrapper.py
+++ b/src/xailib/models/keras_ts_classifier_wrapper.py
@@ -68,7 +68,7 @@ def predict(self, X):
"""
Make class predictions for time series input instances.
- For multi-class classification, returns the argmax of the output.
+ For outputs with multiple classes, returns the argmax of the output.
Args:
X: Input time series as a numpy array with 3 dimensions
@@ -78,7 +78,7 @@ def predict(self, X):
numpy.ndarray: Predicted class labels as a 1D array.
"""
y = self.bbox.predict(X)
- # For multi-class output, get the argmax
+ # For outputs with multiple classes, get the argmax
if len(y.shape) > 1 and (y.shape[1] != 1):
y = np.argmax(y, axis=1)
return y.ravel()
diff --git a/src/xailib/models/sklearn_ts_classifier_wrapper.py b/src/xailib/models/sklearn_ts_classifier_wrapper.py
index a822ce7..bef5d37 100644
--- a/src/xailib/models/sklearn_ts_classifier_wrapper.py
+++ b/src/xailib/models/sklearn_ts_classifier_wrapper.py
@@ -65,7 +65,8 @@ def predict(self, X):
"""
Make class predictions for time series input instances.
- Converts 3D time series input to 2D format before prediction.
+ Converts 3D time series input to 2D format before prediction
+ by selecting only the first feature column (index 0).
Args:
X: Input time series as a numpy array with 3 dimensions
@@ -74,7 +75,7 @@ def predict(self, X):
Returns:
numpy.ndarray: Predicted class labels as a 1D array.
"""
- # Convert from 3D to 2D by taking first feature dimension
+ # Select first feature column from 3D array: (samples, timesteps, features) -> (samples, timesteps)
X = X[:, :, 0]
return self.bbox.predict(X).ravel()
@@ -82,7 +83,8 @@ def predict_proba(self, X):
"""
Get prediction probabilities for time series input instances.
- Converts 3D time series input to 2D format before prediction.
+ Converts 3D time series input to 2D format before prediction
+ by selecting only the first feature column (index 0).
Args:
X: Input time series as a numpy array with 3 dimensions
@@ -91,6 +93,6 @@ def predict_proba(self, X):
Returns:
numpy.ndarray: Predicted class probabilities.
"""
- # Convert from 3D to 2D by taking first feature dimension
+ # Select first feature column from 3D array: (samples, timesteps, features) -> (samples, timesteps)
X = X[:, :, 0]
return self.bbox.predict_proba(X)
From 06b68e2db505960bb89d1f5b5ff601607681dd92 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 26 Nov 2025 09:53:03 +0000
Subject: [PATCH 5/6] Update README.rst with accurate API examples and GitHub
Pages documentation link
Co-authored-by: rinziv <12544167+rinziv@users.noreply.github.com>
---
README.rst | 37 +++++++++++++++++++++++++------------
1 file changed, 25 insertions(+), 12 deletions(-)
diff --git a/README.rst b/README.rst
index 97a8f8f..996c80b 100644
--- a/README.rst
+++ b/README.rst
@@ -58,12 +58,12 @@ Image Data
Text Data
---------
-* 🚧 **Work in Progress** - Coming soon!
+* **LIME** - Local Interpretable Model-agnostic Explanations for text classification
Time Series Data
----------------
-* 🚧 **Work in Progress** - Coming soon!
+* **LASTS** - Local Agnostic Subsequence-based Time Series explanations
|
@@ -110,19 +110,24 @@ Here's a simple example of using LIME for tabular data explanation:
.. code-block:: python
- from xailib import Explainer
+ from xailib.explainers.lime_explainer import LimeXAITabularExplainer
+ from xailib.models.sklearn_classifier_wrapper import sklearn_classifier_wrapper
- # Initialize your black-box model
- # model = YourModel()
+ # Wrap your scikit-learn model
+ bb = sklearn_classifier_wrapper(your_trained_model)
- # Create an explainer
- explainer = Explainer(model, method='lime')
+ # Create and fit the LIME explainer
+ explainer = LimeXAITabularExplainer(bb)
+ explainer.fit(df, 'target_column', config={
+ 'discretize_continuous': True,
+ 'feature_selection': 'auto'
+ })
- # Generate explanation for a sample
- explanation = explainer.explain(sample_data)
+ # Generate explanation for an instance
+ explanation = explainer.explain(instance, num_samples=1000)
- # Visualize the explanation
- explainer.visualize(explanation)
+ # Visualize feature importance
+ explanation.plot_features_importance()
For more examples and detailed usage, please check the `examples/ `_ directory.
@@ -133,10 +138,18 @@ For more examples and detailed usage, please check the `examples/ `_
+* **GitHub Pages Documentation**: `https://kdd-lab.github.io/XAI-Lib/ `_
+* **Read the Docs**: `https://xai-lib.readthedocs.io/ `_
* **GitHub Repository**: `https://github.com/kdd-lab/XAI-Lib `_
* **Issue Tracker**: `https://github.com/kdd-lab/XAI-Lib/issues `_
+The documentation includes:
+
+* **Getting Started Guide**: Installation and quick start tutorials
+* **API Reference**: Complete documentation of all classes and methods
+* **Examples**: Practical examples for tabular, image, and text data
+* **Contributing Guide**: How to contribute to the project
+
|
🤝 Contributing
From 574d15a13394a15b86a7c0fc2cbffb0c18e31ebd Mon Sep 17 00:00:00 2001
From: Salvo Rinzivillo
Date: Wed, 26 Nov 2025 10:57:03 +0100
Subject: [PATCH 6/6] Revise acknowledgments for XAI Project clarity
Updated acknowledgments section to clarify the focus of the XAI Project.
---
README.rst | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/README.rst b/README.rst
index 996c80b..ae21239 100644
--- a/README.rst
+++ b/README.rst
@@ -178,17 +178,13 @@ This project is licensed under the MIT License - see the `LICENSE `
|
-🙏 Acknowledgments
+Acknowledgments
==================
This library is developed as part of the **XAI Project** (`https://xai-project.eu/ `_), a European initiative dedicated to advancing explainable artificial intelligence.
-The XAI Project aims to:
+The Xai project focuses on the urgent open challenge of how to construct meaningful explanations of opaque AI/ML systems in the context of ai based decision making, aiming at empowering individual against undesired effects of automated decision making, implementing the right of explanation, helping people make better decisions preserving (and expand) human autonomy.
-* Develop new methods for explainable AI
-* Create practical tools for AI transparency
-* Foster collaboration between research and industry
-* Promote responsible AI development
For more information about the XAI Project, visit `https://xai-project.eu/ `_.