Skip to main content

pytrees-rs

pytrees-rs learns decision trees by search rather than by greedy splitting. The algorithms are written in Rust and exposed in Python through estimators that follow the scikit-learn API.

Estimator Features What it learns
DL85Classifier binary The optimal tree of a given depth (DL8.5) for the misclassification error or an error of your own, with optional anytime search strategies
LGDTClassifier binary A tree grown top-down whose tests are chosen with a depth-2 lookahead (LGDT)
ConTreeClassifier continuous The optimal tree of a given depth (ConTree), with an anytime variant
DL85Cluster binary A clustering whose clusters are the leaves of an optimal tree

"Optimal" means the tree with the lowest training error among all trees of at most max_depth levels, with at least min_sup training rows per leaf. Finding it can take a long time on large problems, so every search has a time limit and reports whether it proved optimality (status_).

Installation

pip install pytrees-rs

Wheels are provided for Linux, macOS and Windows, for Python 3.10 and later. To build from source you need a Rust toolchain (1.77 or later):

git clone https://github.com/haroldks/pytrees-rs.git
cd pytrees-rs
pip install .

Quick start

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from pytrees import ConTreeClassifier

X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

clf = ConTreeClassifier(max_depth=3, min_sup=5).fit(X_train, y_train)
print(clf.status_)              # "optimal", or "time_limit" if it ran out of time
print(clf.train_error_)         # training misclassifications
print(clf.score(X_test, y_test))
print(clf.to_dot())             # the tree in Graphviz format

DL8.5 and LGDT need binary features (0 or 1). A Binarizer or KBinsDiscretizer with one-hot output in a Pipeline takes care of that:

from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import KBinsDiscretizer
from pytrees import DL85Classifier

model = make_pipeline(
    KBinsDiscretizer(n_bins=4, encode="onehot-dense"),
    DL85Classifier(max_depth=3, min_sup=5, max_time=60),
)
model.fit(X_train, y_train)

An exact search may not finish in the time you have. The anytime searches return a good tree early and improve it until they prove it optimal. fit_anytime calls you back after each improvement:

from pytrees import DL85Classifier
from pytrees.rules import DiscrepancyRule

X_bin = KBinsDiscretizer(n_bins=4, encode="onehot-dense").fit_transform(X)
clf = DL85Classifier(
    max_depth=5,
    heuristic="information_gain",
    discrepancy=DiscrepancyRule(),   # limited discrepancy search
    max_time=120,
)
clf.fit_anytime(X_bin, y, callback=lambda error, seconds, status: print(seconds, error, status))

ConTreeClassifier has the same method, and use_lds=True makes its plain fit anytime too.

Custom error functions

DL8.5 finds the tree that minimises the sum of its leaf errors, and the error of a leaf does not have to be the number of misclassified rows. Pass your own as error_function: it receives the class counts of a leaf (or its row indices, with error_function_input="indices") and returns the error and the predicted class. Class-dependent costs, sample weights and clustering objectives (DL85Cluster works this way) all fit:

import numpy as np

y_bin = (y == 2).astype(int)   # is it Iris virginica?
costs = np.array([1.0, 5.0])   # missing a virginica costs five times more

def cost_sensitive(class_counts):
    counts = np.asarray(class_counts, dtype=float)
    per_prediction = [(costs * counts).sum() - costs[k] * counts[k] for k in range(len(counts))]
    best = int(np.argmin(per_prediction))
    return per_prediction[best], best

clf = DL85Classifier(max_depth=3, error_function=cost_sensitive).fit(X_bin, y_bin)

The documentation covers the details.

All estimators can be cloned, pickled and used in Pipeline, GridSearchCV or cross_val_score. Their fitted tree is in tree_, with scikit-learn's layout (children_left, children_right, feature, threshold, value), and a row goes left when x[feature] <= threshold.

Documentation

The documentation covers every estimator and parameter, the anytime search rules, the command line tools and the Rust crates in more detail. The Rust API documentation is at haroldks.github.io/pytrees-rs/api.

Repository layout

The Python package is built from a Cargo workspace:

Path Contents
crates/dtrees The dtrees-rs library: DL8.5, LGDT and the search rules, over binary features
crates/contree The contree-rs library: ConTree and its anytime variant, over continuous features
crates/dtrees-cli, crates/contree-cli Command line front ends
crates/pytrees-py The Python bindings (pytrees._native)
python/pytrees The Python package and its scikit-learn estimators
doc The documentation site (mdBook)

To work on it:

cargo test --workspace                     # Rust tests
pip install maturin && maturin develop     # build the Python package in place
pytest python/tests                        # Python tests

Publications

The algorithms in this repository come from the following papers. If you use them in your work, please cite the relevant one.

  • H. Kiossou, P. Schaus, S. Nijssen and V. R. Houndji. Time Constrained DL8.5 Using Limited Discrepancy Search. ECML PKDD 2022, LNCS 13717, pp. 443-459. doi:10.1007/978-3-031-26419-1_27 (DL85Classifier with DiscrepancyRule)
  • H. Kiossou, P. Schaus, S. Nijssen and G. Aglin. Efficient Lookahead Decision Trees. IDA 2024, pp. 133-144. doi:10.1007/978-3-031-58553-1_11 (LGDTClassifier)
  • H. Kiossou and P. Schaus. A Generic Complete Anytime Beam Search for Optimal Decision Tree. IDA 2026. doi:10.1007/978-3-032-23833-7_8, arXiv:2508.06064 (the search rules of DL85Classifier: CA-DL8.5)
  • H. Kiossou, P. Schaus and S. Nijssen. Anytime Optimal Decision Tree Learning with Continuous Features. ECML PKDD 2026. arXiv:2601.14765 (ConTreeClassifier with use_lds=True)

They build on:

  • G. Aglin, S. Nijssen and P. Schaus. Learning Optimal Decision Trees Using Caching Branch-and-Bound Search. AAAI 2020. (DL8.5; the original implementation is pydl8.5.)
  • E. Demirović, A. Lukina, E. Hebrard, J. Chan, J. Bailey, C. Leckie, K. Ramamohanarao and P. J. Stuckey. MurTree: Optimal Decision Trees via Dynamic Programming and Search. JMLR 23, 2022. (The depth-2 solver.)
  • C. E. Briţa, J. G. M. van der Linden and E. Demirović. Optimal Classification Trees for Continuous Feature Data Using Dynamic Programming with Branch-and-Bound. AAAI 2025. (ConTree; the original implementation is ConSol-Lab/contree.)

License

MIT; see LICENSE.

Release files for pytrees-rs 2.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pytrees-rs 2.0.0
File Size Uploaded
pytrees_rs-2.0.0.tar.gz 1.1 MB Details

Built distributions (wheels)

Table of built distributions (wheels) for pytrees-rs 2.0.0
File
pytrees_rs-2.0.0-cp310-abi3-win_amd64.whl CPython 3.10 abi3 Windows x86-64 Details
pytrees_rs-2.0.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.10 abi3 Linux glibc 2.17+ x86-64 Details
pytrees_rs-2.0.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.10 abi3 Linux glibc 2.17+ ARM64 Details
pytrees_rs-2.0.0-cp310-abi3-macosx_11_0_arm64.whl CPython 3.10 abi3 macOS 11.0+ ARM64 Details
pytrees_rs-2.0.0-cp310-abi3-macosx_10_12_x86_64.whl CPython 3.10 abi3 macOS 10.12+ x86-64 Details

Total release size: 3.4 MB

Release files / pytrees_rs-2.0.0.tar.gz

Download URL pytrees_rs-2.0.0.tar.gz
Size 1.1 MB
Tags Source
SHA-256 checksum
How to use checksums
0a9dbcc7a36b9cbddbed3c7010a6dda942aca6b3881b7d4e46e9f53204075312
BLAKE2b-256 checksum
How to use checksums
27b0a7dd0714264dedf9c56bd299ded8b8e815d7e2a6113dbbb3b00b82296e51
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 22, 2026.

Transparency log

Release files / pytrees_rs-2.0.0-cp310-abi3-win_amd64.whl

Download URL pytrees_rs-2.0.0-cp310-abi3-win_amd64.whl
Size 381.7 kB
Tags CPython 3.10 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
9539aeae66a8ff109403ccb286bd076b24c07c508d62e22c2c1c5933fa075741
BLAKE2b-256 checksum
How to use checksums
1f54ef6b989bcb04d029e6c010a3f1201c4a94606cfc36b638470be26f860236
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 22, 2026.

Transparency log

Release files / pytrees_rs-2.0.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL pytrees_rs-2.0.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 504.1 kB
Tags CPython 3.10 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
775e33b7a28cc357e97fb66a729dc74699ebd5cd043da7e0bb0df821aaa732e4
BLAKE2b-256 checksum
How to use checksums
1b64593217cdce11d9ca201f000e8780eb8cb9c6b7d318eaa1411ea887f53ca4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 22, 2026.

Transparency log

Release files / pytrees_rs-2.0.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL pytrees_rs-2.0.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 480.2 kB
Tags CPython 3.10 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
d086bb7e0d0a26b8da5d69ba9ae480b353106d604dff599dce9fefbc764f569a
BLAKE2b-256 checksum
How to use checksums
e2b91eb3dfe4178f4692fec58933bf22920d4f43e4c8be7c59a5ef0e1a3c3b84
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 22, 2026.

Transparency log

Release files / pytrees_rs-2.0.0-cp310-abi3-macosx_11_0_arm64.whl

Download URL pytrees_rs-2.0.0-cp310-abi3-macosx_11_0_arm64.whl
Size 454.3 kB
Tags CPython 3.10 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
8761e7f17f393a886df50231518628ef33e4fbf0c63c96965ebcbe1f1fd14308
BLAKE2b-256 checksum
How to use checksums
a679441788c3aa18a4bda58eb866aa862737c0d90006e891fdfe51345287ac6b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 22, 2026.

Transparency log

Release files / pytrees_rs-2.0.0-cp310-abi3-macosx_10_12_x86_64.whl

Download URL pytrees_rs-2.0.0-cp310-abi3-macosx_10_12_x86_64.whl
Size 486.2 kB
Tags CPython 3.10 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
386363a92bb06c44a78055308b12240ace5ec42924bf919b5b3318a05ce6c918
BLAKE2b-256 checksum
How to use checksums
48d49734cb6d4cbd86484c1c4cdd0395b2efb7850465cb41c9e799989c1d8083
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 22, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

2.0.0 This release

6 release files

1.0.0

13 release files

0.1.3

5 release files

0.1.2

9 release files

0.1.1

9 release files

0.1.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page