scikit-learn compatible

Zone boosting you can read like a spreadsheet.

Fully transparent zone boosting — no decision trees, no gradient descent, no neural weights. Every number in a prediction traces back to a quantile, a group count, or a group average, and is inspectable directly from the fitted model.

pip install zoneboost
One predictor split into data-driven zones — each zone's contribution is just that zone's average residual, shrunk and added in.

Quickstart

Regression

import pandas as pd
from zoneboost import ZoneBoostRegressor

X = pd.DataFrame({
    "rooms": [3, 4, 2, 5, 3, 4, 2, 5],
    "distance_km": [5.0, 2.0, 8.0, 1.0, 6.0, 3.0, 7.5, 1.5],
    "neighborhood": ["a", "b", "a", "b", "a", "b", "a", "b"],
})
y = [300, 450, 220, 520, 310, 470, 230, 510]

model = ZoneBoostRegressor(
    categorical_features=["neighborhood"], random_state=0
)
model.fit(X, y)
model.predict(X)

Classification

from zoneboost import ZoneBoostClassifier

y_class = [0, 1, 0, 1, 0, 1, 0, 1]
clf = ZoneBoostClassifier(
    categorical_features=["neighborhood"], random_state=0
)
clf.fit(X, y_class)
clf.predict_proba(X)   # (n_samples, n_classes), rows sum to 1
clf.predict(X)          # binary and 3+ classes alike

What zoneboost gives you

One weak learner, two estimators

ZoneBoostRegressor and ZoneBoostClassifier (binary and multiclass) share the exact same underlying weak learner — classification just boosts in log-odds space instead of raw target space.

Adaptive zones, not fixed bins

Continuous predictors get variance-reducing split points re-derived fresh every round from that round's residual — the same criterion a regression tree split uses, without growing a tree.

Exact categorical handling

Declared or auto-detected categorical columns skip cut-point search entirely: every distinct value gets its own zone, with no assumption that nearby encoded values behave alike.

Missing values, handled honestly

NaN/None need no imputation — a missing value gets its own dedicated zone, so informative missingness is learned rather than silently imputed away.

Explainable by construction

explain(X) is an exact algebraic decomposition of what predict already computes — not a post-hoc approximation — and its terms sum exactly to the prediction.

Drop into scikit-learn

Works with Pipeline, GridSearchCV, cross_val_score, and clone — no special-cased fitting code required.

How it works, in brief

Each boosting round fits a weak learner made of two transparent pieces: a main effect (a 1D lookup from zone to average residual) for every predictor, and an interaction (a 2D lookup from joint zones to average residual) for every pair of predictors. Every zone's own mean is shrunk toward a hierarchical prior via empirical Bayes — so sparse zones lean toward their prior instead of overfitting a handful of rows. Read the full mechanics, including missing-value handling and how classification reuses the same learner, in How It Works.

Read the docs

Installation, the full parameter table, and how explain() decomposes a prediction.

Get started →