Metadata-Version: 2.4
Name: woodtapper
Version: 0.1.0
Summary: A Python toolbox for interpretable and explainable tree ensembles.
Author: Abdoulaye SAKHO
Author-email: Abdoulaye SAKHO <abdoulaye7020@gmail.com>, artefactory <abdoulaye.sakho@artefact.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/artefactory/woodtapper
Project-URL: Repository, https://github.com/artefactory/woodtapper
Keywords: woodtapper,interpretable ML,tree-based models,Cython
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Mathematics
Classifier: Topic :: Software Development
Requires-Python: <3.13,>=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=2.3.1
Requires-Dist: scikit-learn==1.6.1
Requires-Dist: lightgbm>=4.7.0
Provides-Extra: dev
Requires-Dist: pytest>=8.4.2; extra == "dev"
Requires-Dist: pytest-cov>=7.0.0; extra == "dev"
Requires-Dist: pre-commit>=4.3.0; extra == "dev"
Requires-Dist: matplotlib>=3.10.0; extra == "dev"
Requires-Dist: pandas>=2.3.0; extra == "dev"
Requires-Dist: ucimlrepo>=0.0.7; extra == "dev"
Requires-Dist: setuptools>=78.1.1; extra == "dev"
Requires-Dist: Cython>=3.1.2; extra == "dev"
Provides-Extra: docs
Requires-Dist: mkdocs>=1.6.1; extra == "docs"
Requires-Dist: mkdocs-material>=9.6.22; extra == "docs"
Requires-Dist: mkdocstrings-python>=1.18.2; extra == "docs"
Dynamic: author
Dynamic: license-file

<div align="center">


<picture>
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/artefactory/woodtapper/main/data/logos/logo_woodpecker_compressed.png">
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/artefactory/woodtapper/main/data/logos/logo_woodpecker_compressed_light.png" >
<img src="https://raw.githubusercontent.com/artefactory/woodtapper/main/data/logos/logo_woodpecker_compressed_light.png" width="300">


</picture>

*User-friendly Python toolbox for interpreting and manipulating decision tree ensembles from scikit-learn*

[![CI Status](https://github.com/artefactory/woodtapper/actions/workflows/ci.yaml/badge.svg)](https://github.com/artefactory/woodtapper/actions/workflows/ci.yaml?query=branch%3Amain)
[![Linting , formatting, imports sorting: ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
[![Pre-commit](https://img.shields.io/badge/pre--commit-enabled-informational?logo=pre-commit&logoColor=white)](https://github.com/artefactory/woodtapper/blob/main/.pre-commit-config.yaml)
[![Docs](https://img.shields.io/badge/docs-online-blue)](#-documentation)

[![License](https://img.shields.io/github/license/artefactory/woodtapper)](LICENSE)
[![Python Versions](https://img.shields.io/pypi/pyversions/woodtapper?label=python)](https://pypi.org/project/woodtapper/)
[![PyPI Version](https://img.shields.io/pypi/v/woodtapper.svg)](https://pypi.org/project/woodtapper/)
[![status](https://joss.theoj.org/papers/4a4e11dc5d6fb657d3bd74bd7bd3f8e9/status.svg)](https://joss.theoj.org/papers/4a4e11dc5d6fb657d3bd74bd7bd3f8e9)


</div>

## 🪵 Key Features
WoodTapper is a Python toolbox that provides:

- Rule extraction from tree-based ensembles: Generates a final estimator composed of a sequence of simple rule-based on features and thresholds.

- Fairness-Constrained Gradient Boosting: A second-order tree-boosting implementation that directly incorporates demographic fairness into the training objective via a Wasserstein distance penalty.

- Example-based explanations: Connects predictions to a small set of representative samples, returning the most similar examples along with their target values.

[**Detailed information about the modules can be found here.**](https://artefactory.github.io/woodtapper/0_tutorials/)


WoodTapper is supported by a peer reviewed publication:
> &nbsp; &nbsp;  *`WoodTapper`: a Python package for explaining decision tree ensembles*, Sakho et al. (2026) [📄](https://joss.theoj.org/papers/10.21105/joss.10112)

and a preprint:

> &nbsp; &nbsp;  *OT-FairBoost: Optimal Transport-Guided Gradient Boosting for Fairness Regularization on Tabular Data*, Shivola et al. (2026) [📄](https://arxiv.org/pdf/2607.28014)

## 🛠 Installation

**From PyPi**:
```bash
pip install woodtapper
```
> **Compatibility note:**
> WoodTapper includes a compiled Cython component that depends on the binary interface of `scikit-learn`. If `scikit-learn` is already installed in your environment, the prebuilt PyPI wheel may be incompatible with it. WoodTapper is currently pinned to `scikit-learn` 1.6.1: versions 1.9 and newer are not compatible with this component. To use another compatible version, rebuild WoodTapper locally with:
>
> ```bash
> pip uninstall -y woodtapper
> pip install -U pip setuptools wheel
> pip install -U Cython pybind11
> pip install --no-binary=woodtapper --no-build-isolation woodtapper
> ```

**From source**:
```bash
git clone https://github.com/artefactory/woodtapper.git
cd woodtapper
pip install -e .[dev,docs]
```
> **Warning:** If you are a Windows user, you need to have a C/C++ compiler before installing woodtapper.

## 🌿 WoodTapper RulesExtraction module
```python
from woodtapper.extract_rules import SirusClassifier
from woodtapper.extract_rules.visualization import show_rules

sirus = SirusClassifier(
    n_estimators=1000, max_depth=2, quantile=10, p0=0.01, random_state=0
)
sirus.fit(X_train, y_train)
y_pred_sirus = sirus.predict(X_test)
show_rules(sirus, max_rules=10)
```

## ⚖️ WoodTapper boosted trees Fairness module
```python
from woodtapper.fairness import OTFairBoostClassifier

otfair_clf = OTFairBoostClassifier(
    n_estimators=100,
    lambda_fairness_value=0.1,
    fairness_mode="Demographic_Parity",
    verbosity=-1,
)

otfair_clf.fit(X_train, y_train,sensitive_attribute_train)
otfair_clf.predict(X_test)
```

## 🌱 WoodTapper ExampleExplanation module
```python
from woodtapper.example_sampling import RandomForestClassifierExplained

rf_explained = RandomForestClassifierExplained(n_estimators=100)
rf_explained.fit(X_train, y_train)

# Get the 5 most similar samples (and target) for each test sample
Xy_explain = rf_explained.explanation(X_test)
```

## 🙏 Acknowledgements

This work was done through a partnership between the **Artefact Research Center** and the **Laboratoire de Probabilités Statistiques et Modélisation** (LPSM) of Sorbonne University.

<p align="center">
  <a href="https://www.artefact.com/data-consulting-transformation/artefact-research-center/">
    <img src="https://raw.githubusercontent.com/artefactory/woodtapper/main/data/logos/logo_arc.png" height="80" />
  </a>
  &emsp;
  &emsp;
  <a href="https://www.lpsm.paris/">
    <img src="https://raw.githubusercontent.com/artefactory/woodtapper/main/data/logos//logo_LPSM.jpg" height="95" />
  </a>
</p>


## 📜 Citation

If you find the code useful, please consider citing us:

```bibtex
@article{Sakho2026,
doi = {10.21105/joss.10112},
url = {https://doi.org/10.21105/joss.10112},
year = {2026}, publisher = {The Open Journal},
volume = {11},
number = {121},
pages = {10112},
author = {Sakho, Abdoulaye and Aouad, Jad and Gauthier, Carl-Erik and Malherbe, Emmanuel and Scornet, Erwan},
title = {WoodTapper: a Python package for explaining decision tree ensembles},
journal = {Journal of Open Source Software} }
```

```bibtex
@article{shilova2026ot,
  title={OT-FairBoost: Optimal Transport-Guided Gradient Boosting for Fairness Regularization on Tabular Data},
  author={Shilova, Veronika and Sakho, Abdoulaye and Boumoussou, Younes and Risser, Laurent and Loubes, Jean-Michel and Malherbe, Emmanuel},
  journal={arXiv preprint arXiv:2607.28014},
  year={2026}
}
```


For SIRUS methodology, consider citing:
```bibtex
@article{benard2021sirus,
  title={Sirus: Stable and interpretable rule set for classification},
  author={Benard, Clement and Biau, Gerard and Da Veiga, Sebastien and Scornet, Erwan},
  year={2021}
}
```
