Skip to main content

An eXplainable AI package for tabular data.

Project description

Effector

PyPI version Execute Tests codecov Publish Documentation PyPI Downloads Code style: ruff


effector is an eXplainable AI package for tabular data. It:

  • explains any black-box model with global and regional effects: what each feature does, and where the average hides something
  • produces a report in one line: effector.explain(X, model) fits, ranks the features, hunts for subregions, and writes a single self-contained HTML page
  • offers an interactive API when you want the controls: five engines (PDP, d-PDP, ALE, RHALE, SHAP-DP), one verb set
  • is model agnostic: any callable numpy โ†’ numpy works, and adapters wrap scikit-learn, PyTorch, classifiers and DataFrame pipelines
  • is fast, for both global and regional methods: everything after the fit is free

๐Ÿ“– Documentation | ๐Ÿš€ Quickstart | ๐Ÿ”ง API | ๐Ÿ— Examples


Installation

Effector requires Python 3.10+:

pip install effector

This installs a lightweight core (numpy, scipy, matplotlib, tqdm) that covers PDP, ALE, RHALE and their regional effects.

ShapDP needs the heavier shap/shapiq backends (which pull in numba, scikit-learn, pandas, ...). Install them only if you use that method:

pip install effector[shap]

Quickstart

(a) The inputs

A dataset as a numpy array, a model as a numpy โ†’ numpy callable, and, optionally, a schema so the explanation speaks your vocabulary:

import effector
from sklearn.ensemble import HistGradientBoostingRegressor

data = effector.datasets.BikeSharing()  # standardized numpy arrays
model = HistGradientBoostingRegressor(random_state=21).fit(data.x_train, data.y_train)
predict = effector.adapters.from_sklearn(model)  # a plain numpy -> numpy callable

schema = effector.Schema(
    feature_names=data.feature_names,
    feature_types=[
        "nominal", "nominal", "ordinal", "ordinal", "nominal", "nominal",
        "nominal", "ordinal", "continuous", "continuous", "continuous",
    ],
    category_names=[
        ["winter", "spring", "summer", "fall"],
        ["2011", "2012"],
        ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
        None,
        ["no", "yes"],
        ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
        ["no", "yes"],
        ["clear", "mist", "light rain/snow", "heavy rain"],
        None, None, None,
    ],
    scale_x_list=[
        {"mean": data.x_train_mu[i], "std": data.x_train_std[i]}
        for i in range(data.x_train.shape[1])
    ],
    scale_y={"mean": data.y_train_mu, "std": data.y_train_std},
    target_name="bike-rentals",
)

๐Ÿ“„ In depth: the input layer; pandas, sklearn, torch, classifiers, feature types, units.

(b) The one-liner

report = effector.explain(
    data.x_train, predict, y=data.y_train, schema=schema, nof_instances=5000
)

It fits once, ranks the features, hunts for subregions where the average is hiding something, keeps only the splits that pay for themselves, and opens with the one number worth having:

[effector] global effects   (GAM)  -> 72.3% of the model's variance
           regional effects (CALM) -> 92.0%

The result is a Report, a value you can export or print:

report.to_html("report.html")  # a single self-contained page; mail it, commit it
report.show()                  # the same story, as terminal tables
  โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
  PDP report  ยท  target: bike-rentals
  โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

  DATA & MODEL
  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    instances     5,000
    features      11  ยท  5 nominal ยท 3 ordinal ยท 3 continuous
    model output  mean 188 ยท std 176 ยท range [-19.5, 948]
    model Rยฒ      0.960  (on this subsample)

  EXPLAINED VARIANCE
  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    step         split on                 solo     ฮ”Rยฒ      Rยฒ       heter
    โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    GAM          (all features global)       โ€”       โ€”   72.3%           โ€”
  + hr           temp, workingday, yr   +18.3%  +18.3%   90.6% 0.47 โ†’ 0.26
  + temp         hr, hum                 +2.4%   +1.4%   92.0% 0.22 โ†’ 0.19
    โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    FINAL                                                92.0%

  REJECTED SPLITS                                            min gain 1.0%
  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    feature      split on                 solo     ฮ”Rยฒ    reason
    โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  โœ— yr           hr, workingday          +2.7%   -0.8%    redundant
  โœ— hum          hr, temp                +2.2%   +0.2%    below threshold
  โœ— weekday      hr, temp, yr            +0.4%   +0.2%    below threshold
  โœ— workingday   hr, yr                  +6.2%   -4.8%    redundant

    โœ— redundant: it would explain variance on its own (see solo),
      but the accepted splits already account for it.

  FEATURES                                ranked, in the selected snapshot
  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    feature        importance                          heter      #regions
    โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    hr                 0.7273  โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ     0.2608             4
    yr                 0.2271  โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ                 0.2088             1
    temp               0.2098  โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ                  0.1874             4
    hum                0.0932  โ–ˆโ–ˆ                     0.1221             1
    โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    the features above carry 82% of the total importance mass

(the accepted partition trees follow)

๐Ÿ“„ In depth: the report; the explained variance ledger, the triage plane, the regional analysis, every knob of explain(...).

(c) The interactive API

The same engine, as a live handle you query as you go:

pdp = effector.PDP(data.x_train, predict, schema=schema, nof_instances=5000)

pdp.plot("hr")                        # the global effect, ICE curves behind it
pdp.heter_score("hr")                 # 0.47: the average hides a lot
partition = pdp.find_regions("hr")    # where is it hiding it?
partition.show()
Feature 3 - Full partition tree:
๐ŸŒณ Full Tree Structure:
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
hr ๐Ÿ”น [id: 0 | heter: 0.47 | inst: 5000 | w: 1.00]
    workingday = no ๐Ÿ”น [id: 1 | heter: 0.33 | inst: 1545 | w: 0.31]
        temp < 6.86 ๐Ÿ”น [id: 2 | heter: 0.22 | inst: 778 | w: 0.16]
        temp โ‰ฅ 6.86 ๐Ÿ”น [id: 3 | heter: 0.26 | inst: 767 | w: 0.15]
    workingday = yes ๐Ÿ”น [id: 4 | heter: 0.34 | inst: 3455 | w: 0.69]
        yr = 2011 ๐Ÿ”น [id: 5 | heter: 0.23 | inst: 1720 | w: 0.34]
        yr = 2012 ๐Ÿ”น [id: 6 | heter: 0.31 | inst: 1735 | w: 0.35]
--------------------------------------------------
Feature 3 - Statistics per tree level:
๐ŸŒณ Tree Summary:
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
Level 0๐Ÿ”นheter: 0.47
    Level 1๐Ÿ”นheter: 0.34 | ๐Ÿ”ป0.13 (28.12%)
        Level 2๐Ÿ”นheter: 0.26 | ๐Ÿ”ป0.08 (22.91%)

The effect of hr depends on workingday (commute peaks vs a midday plateau), and within each branch on temp and yr. Plot the effect inside a region:

partition.plot(2)  # hr, on non-working days, in the cold
Global effect of hr with ICE curves Effect of hr on cold non-working days

Every verb answers one question:

verb question it answers
.plot(f) what does feature f do?
.eval(f, xs) โ€ฆas numbers, on my grid
.importance(f) how much does f move the output?
.heter_score(f) is the average hiding something?
.find_regions(f) where is it hiding it?
.select_regions() which splits actually earn their keep?
.fit(features, **cfg) (optional) tune the method first

๐Ÿ“„ In depth: the interactive API; construct and fit, customizing .fit(), plot, eval, scores, regions.


Documentation map

Start here:

Going deeper:


Supported Methods

Every method computes global effects, and regional effects via .find_regions(feature):

Method Class Reference ML model Speed
PDP PDP Friedman, 2001 any fast for a small dataset
d-PDP DerPDP Goldstein et al., 2013 differentiable fast for a small dataset
ALE ALE Apley & Zhu, 2020 any fast
RHALE RHALE Gkolemis et al., 2023 differentiable very fast
SHAP-DP ShapDP Lundberg & Lee, 2017 any fast for a small dataset and a light model

Choosing a method

Three questions decide: is the dataset small (N < 10K) or large? Is the model light (< 0.1s per call) or heavy? Is it differentiable or not?

your case use
small + light any: PDP, ALE, ShapDP; plus RHALE, DerPDP if differentiable
small + heavy PDP, ALE; plus RHALE, DerPDP if differentiable
large + differentiable RHALE
large + non-differentiable ALE

Citation

If you use effector, please cite it:

@misc{gkolemis2024effector,
  title={effector: A Python package for regional explanations},
  author={Vasilis Gkolemis et al.},
  year={2024},
  eprint={2404.02629},
  archivePrefix={arXiv},
  primaryClass={cs.LG}
}

Spotlight on effector

๐Ÿ“š Featured Publications

๐ŸŽค Talks & Presentations

๐ŸŒ Adoption & Collaborations

๐Ÿ” Additional Resources

๐Ÿ“š Related Publications

Papers that have inspired effector:

  • REPID: Regional Effects in Predictive Models
    Herbinger et al., 2022 - Link

  • Decomposing Global Feature Effects Based on Feature Interactions
    Herbinger et al., 2023 - Link

  • RHALE: Robust Heterogeneity-Aware Effects
    Gkolemis Vasilis et al., 2023 - Link

  • DALE: Decomposing Global Feature Effects
    Gkolemis Vasilis et al., 2023 - Link

  • Greedy Function Approximation: A Gradient Boosting Machine
    Friedman, 2001 - Link

  • Visualizing Predictor Effects in Black-Box Models
    Apley, 2016 - Link

  • SHAP: A Unified Approach to Model Interpretation
    Lundberg & Lee, 2017 - Link

  • Regionally Additive Models: Explainable-by-design models minimizing feature interactions
    Gkolemis Vasilis et al., 2023 - Link


License

effector is released under the MIT License.


Powered by:

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

effector-0.5.0.tar.gz (160.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

effector-0.5.0-py3-none-any.whl (170.6 kB view details)

Uploaded Python 3

File details

Details for the file effector-0.5.0.tar.gz.

File metadata

  • Download URL: effector-0.5.0.tar.gz
  • Upload date:
  • Size: 160.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for effector-0.5.0.tar.gz
Algorithm Hash digest
SHA256 2e30a339ce07641fea8f3b005441010e7e0786131058b2d527bb49df2f5ec24c
MD5 5f448a5cf9ed3f0e8ffc983dd64331c1
BLAKE2b-256 084276cf3721b5e0577ba5c8fcea0c39c83d7d6513715738433eb083d6d35dcb

See more details on using hashes here.

Provenance

The following attestation bundles were made for effector-0.5.0.tar.gz:

Publisher: publish_to_pypi.yml on givasile/effector

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file effector-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: effector-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 170.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for effector-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1f6f3d458372a49a8db6965071ebee7007922e956c2d701467bf487c9b9e6f97
MD5 2ec31ee8c65823d0d0bb38d74beed976
BLAKE2b-256 650a351cc67c1614597f63cce1a9f80b72efa50b8bda7450498ea958bcc52214

See more details on using hashes here.

Provenance

The following attestation bundles were made for effector-0.5.0-py3-none-any.whl:

Publisher: publish_to_pypi.yml on givasile/effector

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page