Skip to main content

ndscape

Fit, score, and embed nested-dichotomy (ND) trees for multi-class classification.

A nested dichotomy reduces a C-class problem to a tree of binary splits (e.g. {0,1,2} vs {3,4}, then {0} vs {1,2}, ...). ndscape lets you fit one, score it, or place a whole population of candidate trees in a 2-D "tree-space" to see how a property (accuracy, variance, ...) varies across tree structures.

Install

pip install ndscape
pip install ndscape[spatial]   # adds Moran's I support (esda, libpysal)
pip install ndscape[plot]      # adds plotting (matplotlib, bokeh)

Quickstart

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
import ndscape as nds

X, y = load_iris(return_X_y=True)
classes = sorted(set(y))
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)

nd = nds.fit(X_train, y_train, classes=classes, base="lr")
nd.predict(X_test)
nd.score(X_test, y_test)   # {"accuracy": ..., "logloss": ...}

classes is the list of class labels in your y (sorted(set(y)) works for integer or string labels). nds.fit samples one ND tree automatically; pass tree=... to use a specific one (see "A tree is..." below).

Use cases

You have a dataset and a binary classifier.

base can be the string "lr" or "decisiontree", or your own unfitted scikit-learn estimator — a fresh clone of it is fit at every split.

from sklearn.svm import SVC

nd = nds.fit(X_train, y_train, classes=classes, base=SVC(probability=True, kernel="linear"))

You have a train/test split and want a score.

nd = nds.ND(tree, classes).fit(X_train, y_train, base="lr")
nd.score(X_test, y_test)   # {"accuracy": ..., "logloss": ...}

You already trained the per-split models yourself.

# models in the same order as tree, or a {(left, right): model} dict — either works
nd = nds.ND.from_trained(tree, classes, models=[fitted_model_1, fitted_model_2, ...])
nd.predict_proba(X_test)

You already scored a set of trees and want to see where they sit in tree-space.

trees, coords = nds.embed_trees(classes)
nds.spatial_autocorrelation(my_scores, coords)   # {"I": ..., "p_sim": ...}

You just want the whole picture: fit, score, and embed every candidate tree.

rows = nds.analyze(X_train, y_train, classes, X_test=X_test, y_test=y_test, base="lr")
# [{"tree": ..., "accuracy": ..., "logloss": ..., "coord": array([...])}, ...]

You want a picture of that tree-space.

nds.plot(rows, metric="accuracy", path="tree_space.png")        # static PNG/PDF
nds.plot_interactive(rows, metric="accuracy", path="tree_space.html")  # pan/zoom/hover

Both color points by metric and mark the best tree with a black x. Needs ndscape[plot].

The embedding is slow to recompute and you want to reuse it.

rows = nds.analyze(X_train, y_train, classes, cache="embedding.joblib")

The MDS step in embed_trees/analyze is the slow part. Pass cache= a .joblib path: the first call computes the embedding and saves it there, later calls with the same path just load it.

A tree is a list of (left, right) tuples of class labels, e.g. [((0, 1), (2, 3)), ((0,), (1,)), ((2,), (3,))]. Use nds.all_trees(classes) (exhaustive, for small C) or nds.sample_trees(classes, N) (for larger C) to generate candidates.

base accepts "lr", "decisiontree", or any unfitted scikit-learn estimator with fit/predict_proba.

Metadata

Release files for ndscape 0.1.2

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

Source distribution (sdist)

Source distribution for ndscape 0.1.2
File Size Uploaded
ndscape-0.1.2.tar.gz 14.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ndscape 0.1.2
File Interpreter ABI Platform
ndscape-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 26.4 kB

Release files / ndscape-0.1.2.tar.gz

Download URL ndscape-0.1.2.tar.gz
Size 14.0 kB
Tags Source
SHA-256 checksum
How to use checksums
d6689bbac4036f94c2bfa6930247d1c4bb80750089a959c15b10ca4b92dc4bcb
BLAKE2b-256 checksum
How to use checksums
d7e094a6731730ead4304ccd2f14eeacebd18f12b921fd97c66b1f422e55c71f
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 2, 2026.

Transparency log

Release files / ndscape-0.1.2-py3-none-any.whl

Download URL ndscape-0.1.2-py3-none-any.whl
Size 12.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7e0d13c67778b95b654d42919febc417089386f8fb4457174a46a2013b409e41
BLAKE2b-256 checksum
How to use checksums
eceee7f379d5faea96e925adf8ec41c49d03c8e20a786cd70ca7ca136e6e3371
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 2, 2026.

Transparency log

Release history Release notifications | RSS feed

0.1.3

2 release files

This release

0.1.2 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

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