Constrained, threshold-aware counterfactual explanations for tree ensembles.
treecf answers the question: "what is the minimal, feasible change to this instance such
that the model's raw output lands in a target interval?" — for XGBoost, LightGBM, CatBoost
and scikit-learn tree ensembles.
Status: v0.1.0 on PyPI. See the documentation for concepts and tutorials.
- Tree-native and fast. Models are parsed into a shared tree IR; the constrained
genetic search runs on a bundled Rust core 44–58× faster than the equivalent numpy
implementation (see the "Backends and proofs" docs page; the pure-Python engine remains
available as
backend="python"), and every result is float-verified against the IR before it is returned. - Decision thresholds are first-class. Targets are intervals on the raw model output — custom probability cutoffs, regression targets, and whole rating-grade ladders in one call.
- Real-world constraints. Declarative layer for immutability, directionality, ranges,
one-hot consistency, and arbitrary linear inter-feature constraints such as
max_dpd_30d <= max_dpd_12m— compiled once, enforced by every backend. - Missing values are values. NaN can be a legitimate counterfactual state, with per-feature opt-in and explicit transition costs.
- Constraint mining. Candidate invariants are mined from data and presented for human review — never auto-applied.
pip install treecf # bundled Rust engine; numpy is the only Python dep
pip install "treecf[xgboost]" # model parsers as extras; JSON dumps work without them
pip install "treecf[viz]" # matplotlib plotsfrom treecf import Explainer, Target, constraint, Freeze
exp = Explainer(
model="model.json", # native object or dump file
background=X_train_sample,
constraints=[
constraint("max_dpd_30d <= max_dpd_12m"),
Freeze("age_of_bureau_file"),
],
)
res = exp.explain(x, target=Target.probability(range=(0.0, 0.04)), seed=0)MIT