Metadata-Version: 2.4
Name: acfx
Version: 0.3.8
Summary: Actionable Counterfactual eXplanations
Author-email: Szymon Bobek <szymon.bobek@gmail.com>, Piotr Kubacki <piotr.kubacki00@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/sbobek/acfx
Project-URL: Documentation, https://acfx.readthedocs.org
Project-URL: Issues, https://github.com/sbobek/acfx/issues
Keywords: xai,tabular data,explainability,model-agnostic,counterfactual,causal
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Operating System :: OS Independent
Requires-Python: <3.15,>=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy==1.26.0; python_version < "3.12"
Requires-Dist: numpy<3,>=1.26.0; python_version >= "3.12"
Requires-Dist: pandas==1.5.3; python_version < "3.12"
Requires-Dist: pandas<4,>=1.5.3; python_version >= "3.12"
Requires-Dist: scipy==1.11.4; python_version < "3.12"
Requires-Dist: scipy<2,>=1.11.4; python_version >= "3.12"
Requires-Dist: scikit-learn==1.6.1; python_version < "3.12"
Requires-Dist: scikit-learn<2,>=1.6.1; python_version >= "3.12"
Requires-Dist: optuna==4.2.0; python_version < "3.12"
Requires-Dist: optuna<6,>=4.2.0; python_version >= "3.12"
Requires-Dist: pgmpy==1.0.0
Requires-Dist: interpret==0.7.3; python_version < "3.12"
Requires-Dist: interpret<0.8,>=0.7.3; python_version >= "3.12"
Requires-Dist: interpret-core==0.7.3; python_version < "3.12"
Requires-Dist: interpret-core<0.8,>=0.7.3; python_version >= "3.12"
Requires-Dist: overrides==7.4.0; python_version < "3.12"
Requires-Dist: overrides<8,>=7.4.0; python_version >= "3.12"
Provides-Extra: benchmark
Requires-Dist: tensorflow==2.14.0; python_version <= "3.11" and extra == "benchmark"
Requires-Dist: lingam==1.9.1; python_version <= "3.11" and extra == "benchmark"
Requires-Dist: openml==0.15.1; python_version <= "3.11" and extra == "benchmark"
Requires-Dist: alibi==0.9.6; python_version <= "3.11" and extra == "benchmark"
Requires-Dist: lux-explainer==1.3.2; python_version <= "3.11" and extra == "benchmark"
Requires-Dist: networkx==3.4.2; python_version <= "3.11" and extra == "benchmark"
Requires-Dist: cfnow==0.0.6; python_version <= "3.11" and extra == "benchmark"
Requires-Dist: dice-ml==0.11; python_version <= "3.11" and extra == "benchmark"
Requires-Dist: pydotplus==2.0.2; python_version <= "3.11" and extra == "benchmark"
Requires-Dist: deap==1.4.2; python_version <= "3.11" and extra == "benchmark"
Requires-Dist: pydot==3.0.4; python_version <= "3.11" and extra == "benchmark"
Provides-Extra: streamlit-app
Requires-Dist: streamlit==1.48.0; python_version < "3.12" and extra == "streamlit-app"
Requires-Dist: streamlit<2,>=1.48.0; python_version >= "3.12" and extra == "streamlit-app"
Requires-Dist: streamlit-sortables==0.3.1; extra == "streamlit-app"
Requires-Dist: pyarrow<25; python_version < "3.12" and extra == "streamlit-app"
Requires-Dist: networkx==3.4.2; python_version < "3.12" and extra == "streamlit-app"
Requires-Dist: networkx<4,>=3.4.2; python_version >= "3.12" and extra == "streamlit-app"
Requires-Dist: lingam==1.9.1; python_version < "3.12" and extra == "streamlit-app"
Requires-Dist: lingam<1.13,>=1.9.1; python_version >= "3.12" and extra == "streamlit-app"
Requires-Dist: semopy>=2.3; python_version >= "3.12" and extra == "streamlit-app"
Requires-Dist: pyvis==0.3.2; extra == "streamlit-app"
Provides-Extra: test
Requires-Dist: pytest>=8; extra == "test"
Requires-Dist: pytest-cov>=5; extra == "test"
Requires-Dist: networkx==3.4.2; python_version < "3.12" and extra == "test"
Requires-Dist: networkx<4,>=3.4.2; python_version >= "3.12" and extra == "test"
Requires-Dist: lingam==1.9.1; python_version < "3.12" and extra == "test"
Requires-Dist: lingam<1.13,>=1.9.1; python_version >= "3.12" and extra == "test"
Dynamic: license-file





# ACFX — Actionable Counterfactual eXplainer

[![PyPI version](https://img.shields.io/pypi/v/acfx.svg)](https://pypi.org/project/acfx/)
[![Python versions](https://img.shields.io/pypi/pyversions/acfx.svg)](https://pypi.org/project/acfx/)
[![License](https://img.shields.io/github/license/sbobek/acfx.svg)](https://github.com/sbobek/acfx/blob/main/LICENSE)
[![Documentation Status](https://readthedocs.org/projects/acfx/badge/?version=latest)](https://acfx.readthedocs.io/en/latest/)
[![GitHub Stars](https://img.shields.io/github/stars/sbobek/acfx.svg)](https://github.com/sbobek/acfx/stargazers)

**ACFX (Actionable Counterfactual eXplainer)** is a **model-agnostic Explainable AI (XAI)** framework for generating **actionable counterfactual explanations** for machine learning models.

It answers the question:

> *What minimal and feasible changes to the input would lead to a desired prediction outcome?*



## Key Features

* Model-agnostic counterfactual explanations
* Actionability and feasibility constraints
* Support for causal structures and expert knowledge
* Built-in benchmarking framework
* Python API and graphical user interface (GUI)



## Installation

### From PyPI

```bash
conda create --name acfx_env python=3.11
conda activate acfx_env
conda install pip
pip install acfx
```

### From source

```bash
git clone https://github.com/sbobek/acfx
cd acfx/src
pip install .
```

**Note**: The `requirements.txt` file includes additional packages that are not required for standard use. It is provided for development purposes and to support reproducibility of the complete development environment. Direct runtime dependencies are specified in `pyproject.toml`.

## Quick Start

```python
from acfx import AcfxEBM
from interpret.glassbox import ExplainableBoostingClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
import numpy as np

# Initialize model and explainer
model = ExplainableBoostingClassifier()
explainer = AcfxEBM(model)

# Load sample data
data = load_iris(as_frame=True)
X_train, X_test, y_train, y_test = train_test_split(data.data, data.target, test_size=0.2, random_state=42)

# Define feature bounds
pbounds = {col: (X_train[col].min(), X_train[col].max()) for col in X_train.columns}

# Example adjacency matrix and causal order
adjacency_matrix = np.array([
    [0.0, 0.0, 0.0, 0.0],
    [0.8, 0.0, 0.0, 0.0],
    [0.0, 0.6, 0.0, 0.0],
    [0.5, 0.0, 0.7, 0.0]
])
causal_order = [0, 1, 2, 3]

# Fit explainer
explainer.fit(
    X=X_train,
    adjacency_matrix=adjacency_matrix,
    causal_order=causal_order,
    pbounds=pbounds,
    y=y_train,
    features_order=X_train.columns.tolist()
)

# Generate counterfactual
query_instance = X_test.iloc[0].values
original_class = model.predict([query_instance])[0]
cf = explainer.counterfactual(desired_class=original_class, query_instance=query_instance)
print(cf)
```

> ⚠️ The adjacency matrix above is a simple example. In practice, it can be provided by expert knowledge or learned using tools like DirectLiNGAM.



## Usage Tutorials

Learn more and explore advanced examples:

* **Documentation**: [ACFX Docs](https://acfx.readthedocs.io/en/latest/)
* **Python API (Colab Notebooks)**: [Interactive Examples](https://colab.research.google.com/drive/1Hj6yH4UIrAp1Jp6B1U542vcdSkXuZHUd?usp=sharing)
* **Graphical User Interface (GUI)**: [ACFX GUI](https://acfx-dashboard.streamlit.app/)



## Testing

The library and the Streamlit GUI are covered by an automated pytest suite with code coverage measurement:

```bash
git clone https://github.com/sbobek/acfx
cd acfx/src
pip install -e ".[test,streamlit-app]"
pytest --cov
```

See [TESTING.md](https://github.com/sbobek/acfx/blob/main/TESTING.md) for details (fast mode, HTML coverage report, what is excluded from coverage and why).



## Benchmarking

### Install dependencies

```bash
pip install acfx[benchmark]
```

### Run benchmark

```bash
git clone https://github.com/sbobek/acfx
cd acfx/src
python -m acfx.benchmark.main
```

> ⚠️ Always run as a module from `acfx/src` using `python -m`. Running directly or from another folder may cause import or path errors.



## Citation

TBD




