Restricted Decision Trees (RDT)
A native C++ implementation of Restricted Decision Trees — a tree-based algorithm that sits between the rigidity of oblivious trees and the flexibility of standard decision trees, exposed to Python via nanobind.
What is a Restricted Decision Tree?
In a Restricted Decision Tree, all nodes at the same depth use the same feature for splitting, but each node can have a different threshold. This constraint provides:
- Structure: more interpretable than standard decision trees — the feature chosen at each depth is a natural, depth-ordered importance ranking.
- Flexibility: more adaptable than oblivious trees (which use the same feature and threshold at every node in a depth).
- Staged decisions: each depth can correspond to one information source (e.g. a KYC vendor check, a medical test panel, a fraud-investigation stage) — useful when a real deployment pipeline is itself staged.
Tree Type Comparison
| Tree Type | Feature Selection | Threshold Selection | Structure |
|---|---|---|---|
| Standard Decision Tree | Different feature per node | Different threshold per node | Unrestricted |
| Restricted Decision Tree | Same feature per depth | Different threshold per node | Semi-structured |
| Oblivious Decision Tree | Same feature per depth | Same threshold per depth | Highly structured |
Features
- ✅ Classification (binary & multi-class) and regression
- ✅ Multiple splitting criteria: Gini, entropy, MSE, MAE
- ✅ Probability predictions (
predict_proba) - ✅ Random Forest and Gradient Boosting ensembles (
rdt.ensemble), with real cross-tree parallelism and a parameter surface matching scikit-learn/XGBoost/LightGBM - ✅ Interactive D3.js tree visualization, plain-text tree printing, and JSON export
- ✅ Native C++ core — validated for exact output parity (predictions, per-depth feature choice, probabilities) against the project's original Cython reference implementation, and substantially faster in practice
Install
pip install restricted-decision-trees
Quick start
import numpy as np
from rdt import RDT
X = np.array([[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]])
y = np.array([0, 0, 0, 1, 1, 1], dtype=float)
model = RDT(task="classification", criterion="gini", max_depth=3)
model.fit(X, y)
model.predict(X) # array([0., 0., 0., 1., 1., 1.])
model.predict_proba(X) # per-class probabilities
model.depth_features_ # {0: 0} -- feature index chosen at each depth
For regression, pass task="regression" (criterion defaults to "mse";
"mae" is also available).
Visualizing a tree
from rdt.visualize import print_tree, visualize_d3_observable, export_tree_dict
print_tree(model, feature_names=["x"])
# Interactive, collapsible D3.js visualization -- writes an HTML file you
# open in a browser (click nodes to expand/collapse, scroll/drag to zoom+pan).
visualize_d3_observable(model, y, feature_names=["x"], filename="tree.html")
# Or get the same tree structure + per-node stats as a plain dict/JSON,
# for a custom visualization of your own.
tree_dict = export_tree_dict(model, y, feature_names=["x"])
See examples/basic_usage.py and examples/d3_visualization_demo.py for
fuller, runnable examples.
Ensembles
from rdt.ensemble import RandomForestRDT, GradientBoostingRDT
rf = RandomForestRDT(n_estimators=100, max_depth=4, oob_score=True, n_jobs=-1)
rf.fit(X_train, y_train)
rf.predict(X_test)
rf.feature_importances_
rf.oob_score_
gb = GradientBoostingRDT(n_estimators=100, learning_rate=0.1, max_depth=3,
validation_fraction=0.15, n_iter_no_change=10) # early stopping
gb.fit(X_train, y_train)
gb.predict(X_test)
Parameter names follow scikit-learn where a concept maps directly to a
scikit-learn parameter; where XGBoost/LightGBM use a different name for the
same concept (colsample_bytree, gamma, min_child_weight,
early_stopping_rounds, ...) that name is accepted as an alias — setting
both names to conflicting values raises. See rdt/ensemble.py's module
docstring for the full mapping, including the two places where RDT's
structural constraint (every node at a depth splits on the same feature)
means a parameter can't work exactly like it does elsewhere:
max_features/colsample_bytreecan't be resampled per node the way scikit-learn/XGBoost do it — each tree gets one random column subset chosen once, before that tree is fit.reg_alpha/reg_lambda(GradientBoostingRDTonly) are a real effect (post-hoc leaf-value soft-thresholding/shrinkage) but not XGBoost's exact Newton/hessian-derived formula — this engine boosts first-order (Friedman-style), not second-order.
See examples/ensemble_usage.py for a fuller, runnable example.
API reference
rdt.RDT(task="classification", criterion=None, max_depth=5, min_samples_split=2, min_samples_leaf=1)
Parameters
task—"classification"or"regression".criterion— splitting criterion. Defaults to"gini"for classification or"mse"for regression. Classification accepts"gini"or"entropy"; regression accepts"mse"or"mae".max_depth— maximum tree depth.min_samples_split— minimum samples required to split a node.min_samples_leaf— minimum samples required in a leaf node.
Methods
fit(X, y)— build the tree from training data.predict(X)— predict target values.predict_proba(X)— predict class probabilities (classification only).
Attributes (after fitting)
depth_features_—dict[int, int], the feature index chosen at each depth.n_features_— number of features seen duringfit.classes_,n_classes_— unique class labels and their count (classification only).root— the fitted tree's rootNode(.is_leaf,.split_feature,.split_threshold,.value,.class_counts,.left,.right,.indices) for direct programmatic inspection.
rdt.ensemble.RandomForestRDT
Bagging ensemble: n_estimators, task, criterion, max_depth,
min_samples_split, min_samples_leaf (alias min_child_weight),
min_impurity_decrease (alias gamma), max_features (alias
colsample_bytree), bootstrap, max_samples, oob_score, class_weight
('balanced' or dict), random_state, n_jobs. After fitting:
estimators_ (list of RDT, individually introspectable),
feature_importances_, oob_score_ (if requested).
rdt.ensemble.GradientBoostingRDT
First-order boosting: n_estimators, task, loss (classification:
'log_loss', 'exponential'; regression: 'squared_error',
'absolute_error', 'huber', 'quantile'), learning_rate, max_depth,
min_samples_split, min_samples_leaf (alias min_child_weight),
min_impurity_decrease (alias gamma), subsample, max_features (alias
colsample_bytree), validation_fraction, n_iter_no_change (alias
early_stopping_rounds), tol, reg_alpha, reg_lambda,
scale_pos_weight (binary only), huber_delta, quantile_alpha,
random_state, n_jobs. After fitting: feature_importances_,
train_score_ (loss per round), n_estimators_ (rounds actually fitted —
less than n_estimators if early stopping triggered).
rdt.visualize
print_tree(model, feature_names=None)— print an indented text representation of a fitted tree.export_tree_dict(model, y, feature_names=None, class_names=None) -> dict— export the tree as a nested dict with per-node statistics (sample count, impurity, target average, leaf purity).visualize_d3_observable(model, y, feature_names=None, class_names=None, filename="rdt_tree_d3.html", width=1200, height=800) -> str— render an interactive, collapsible D3.js tree to an HTML file (and return the HTML string).
How it works
For each depth, every candidate feature is scored across all currently active nodes at that depth (summing each node's best achievable impurity improvement for that feature); the feature with the highest total wins and is locked in for the whole depth, and the per-node thresholds already found while scoring it are reused directly as the final split points:
For each depth level:
1. For every candidate feature:
for every active node at this depth:
find that node's best threshold for this feature
total_improvement = sum of improvements across all nodes
2. Choose the feature with the highest total_improvement; lock it in.
3. Split every node at this depth using the threshold already found
for the winning feature.
Package structure
restricted-decision-trees/
├── README.md
├── LICENSE
├── pyproject.toml, CMakeLists.txt # nanobind + scikit-build-core build
├── core/include/rdt/ # header-only C++ algorithm core
├── src/bindings.cpp # nanobind bindings
├── python/rdt/
│ ├── __init__.py # RDT (sklearn-style wrapper)
│ ├── ensemble.py # RandomForestRDT / GradientBoostingRDT
│ └── visualize.py # print_tree / D3 viz / JSON export
├── tests/ # pytest unit tests
└── examples/
├── basic_usage.py
├── ensemble_usage.py
└── d3_visualization_demo.py
License
GPL-3.0 — see LICENSE.
Metadata
Release files for restricted-decision-trees 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| restricted_decision_trees-0.2.0.tar.gz | 68.7 kB | Details |
Built distributions (wheels)
Total release size: 2.0 MB
Release files / restricted_decision_trees-0.2.0.tar.gz
| Download URL | restricted_decision_trees-0.2.0.tar.gz |
|---|---|
| Size | 68.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ca54d52ac5da9512bc7ef5cb4e62e80b6fa4e6720241d6a4d333a0034afab692
|
|
BLAKE2b-256 checksum How to use checksums |
0d792892ce1a2a96f71dbc06b0470f2d6fbf7db08b08881e6d07ee4983504d0f
|
| 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 Aug 24, 2026.
Transparency logRelease files / restricted_decision_trees-0.2.0-cp313-cp313-win_amd64.whl
| Download URL | restricted_decision_trees-0.2.0-cp313-cp313-win_amd64.whl |
|---|---|
| Size | 164.9 kB |
| Tags | CPython 3.13 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
b38625d242d5619a2b7aa0d7ce7085ae1b6b1224651f6ee41edfb4239ef3c509
|
|
BLAKE2b-256 checksum How to use checksums |
a5193ab4c543243870851263da5514c4edb3c466a89b077ccc70166a5f200886
|
| 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 Aug 24, 2026.
Transparency logRelease files / restricted_decision_trees-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | restricted_decision_trees-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 182.5 kB |
| Tags | CPython 3.13 Linux glibc 2.17+ x86-64 |
|
SHA-256 checksum How to use checksums |
01eea9d9a76a8fce67e0af0fb06fefd4c1fe6df1538c75a6dd276de9743d722a
|
|
BLAKE2b-256 checksum How to use checksums |
1d314693d1f446c37bea38bee2fa239dd5bb0685181ccda01fb3242fdb27c1f3
|
| 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 Aug 24, 2026.
Transparency logRelease files / restricted_decision_trees-0.2.0-cp313-cp313-macosx_11_0_arm64.whl
| Download URL | restricted_decision_trees-0.2.0-cp313-cp313-macosx_11_0_arm64.whl |
|---|---|
| Size | 136.1 kB |
| Tags | CPython 3.13 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
37468d408c10b1fae56b394460d79c6d35ad86f5df41d5fe454ceae81a00deae
|
|
BLAKE2b-256 checksum How to use checksums |
70a827ae1731ea8b464caef9e89942b689c5e6df3015d6467f6934c7e5e97057
|
| 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 Aug 24, 2026.
Transparency logRelease files / restricted_decision_trees-0.2.0-cp312-cp312-win_amd64.whl
| Download URL | restricted_decision_trees-0.2.0-cp312-cp312-win_amd64.whl |
|---|---|
| Size | 164.9 kB |
| Tags | CPython 3.12 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
d47a7c5cb6b5253c8494fc48bb824a21b013ab510c5b8e3dcfd94e9f377f7279
|
|
BLAKE2b-256 checksum How to use checksums |
bd4677c181bd17bebf43f71e1d4b1bbe71ae43dae9cf65dcbb78c1d8a99b588d
|
| 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 Aug 24, 2026.
Transparency logRelease files / restricted_decision_trees-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | restricted_decision_trees-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 182.5 kB |
| Tags | CPython 3.12 Linux glibc 2.17+ x86-64 |
|
SHA-256 checksum How to use checksums |
61a03944faec9a8f6fe989a1707cafa9620153eeb8c68004e7cf713024d4c661
|
|
BLAKE2b-256 checksum How to use checksums |
94f77290713cecae8ec3d0cf2807ad497274619d23e4eca9ec8c444a7fbdc20a
|
| 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 Aug 24, 2026.
Transparency logRelease files / restricted_decision_trees-0.2.0-cp312-cp312-macosx_11_0_arm64.whl
| Download URL | restricted_decision_trees-0.2.0-cp312-cp312-macosx_11_0_arm64.whl |
|---|---|
| Size | 136.1 kB |
| Tags | CPython 3.12 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
b119130600a7a1f8c4f29ef662f770496a3c74de1cc54c8adea601e473490a1b
|
|
BLAKE2b-256 checksum How to use checksums |
bfe991a85425c8ee88d5875f5dc4f441072bfd871a86aa7bc20149b502ca5515
|
| 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 Aug 24, 2026.
Transparency logRelease files / restricted_decision_trees-0.2.0-cp311-cp311-win_amd64.whl
| Download URL | restricted_decision_trees-0.2.0-cp311-cp311-win_amd64.whl |
|---|---|
| Size | 164.8 kB |
| Tags | CPython 3.11 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
05336c0543cfd5bbda674fb5e6bfd0001d37be2978b3adbb192f64c238250c0f
|
|
BLAKE2b-256 checksum How to use checksums |
1283853388b2f4d468e9054b5e801fde368c21a0754f30a4959d13e30b3c434c
|
| 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 Aug 24, 2026.
Transparency logRelease files / restricted_decision_trees-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | restricted_decision_trees-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 183.1 kB |
| Tags | CPython 3.11 Linux glibc 2.17+ x86-64 |
|
SHA-256 checksum How to use checksums |
cf03957b0d6b18cd1315fa1f5d94d2bf6182342dd91a526fcc4aa70db6451462
|
|
BLAKE2b-256 checksum How to use checksums |
74340c5d92a7a8b7d0442246e405ee8e839feccca6b118311677e07d56be37de
|
| 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 Aug 24, 2026.
Transparency logRelease files / restricted_decision_trees-0.2.0-cp311-cp311-macosx_11_0_arm64.whl
| Download URL | restricted_decision_trees-0.2.0-cp311-cp311-macosx_11_0_arm64.whl |
|---|---|
| Size | 136.9 kB |
| Tags | CPython 3.11 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
e34023d075b0a5d6e1b9330a62f626ccfe4a4b00ba0af0e143cd58c7f732deb7
|
|
BLAKE2b-256 checksum How to use checksums |
b82fd38dc04b277d767a457c28018d11d8a06b89e12a389708d6793e007fef7d
|
| 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 Aug 24, 2026.
Transparency logRelease files / restricted_decision_trees-0.2.0-cp310-cp310-win_amd64.whl
| Download URL | restricted_decision_trees-0.2.0-cp310-cp310-win_amd64.whl |
|---|---|
| Size | 164.4 kB |
| Tags | CPython 3.10 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
332027cb8515977b16ffd2ab72fa2c9df5b3ba60613b1d152b147f96e34601e7
|
|
BLAKE2b-256 checksum How to use checksums |
256ed8055f59a45322e0d263568ee7aaa3b91b01aa0ae0614e91cde80989cdac
|
| 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 Aug 24, 2026.
Transparency logRelease files / restricted_decision_trees-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | restricted_decision_trees-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 183.3 kB |
| Tags | CPython 3.10 Linux glibc 2.17+ x86-64 |
|
SHA-256 checksum How to use checksums |
01e47a0c4cec167bb90edbdb2d98392b6c6c64c8f3c4601aad41754f76ff033a
|
|
BLAKE2b-256 checksum How to use checksums |
79c0fcd096521d5e5f6dda252c0a8073fdd36eae0dd39c004593c589f7a23041
|
| 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 Aug 24, 2026.
Transparency logRelease files / restricted_decision_trees-0.2.0-cp310-cp310-macosx_11_0_arm64.whl
| Download URL | restricted_decision_trees-0.2.0-cp310-cp310-macosx_11_0_arm64.whl |
|---|---|
| Size | 137.3 kB |
| Tags | CPython 3.10 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
078e46f123491160ae5e3d1755cb2256a6fd0b58c8f201624421353a849079fc
|
|
BLAKE2b-256 checksum How to use checksums |
38eea205efb22ac2c87fabe0f739ae060c52abedca041e522dc849c9e714bf22
|
| 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 Aug 24, 2026.
Transparency log