Skip to main content

Random Forest with surrogate splits for native missing data handling

Project description

surrogate-forest

Random Forest with surrogate splits for native missing data handling.

Python implementation combining the best ideas from CART (surrogate splits), XGBoost (learned NaN directions), LightGBM (histogram binning), and CatBoost (symmetric trees) into a single sklearn-compatible library.

Installation

pip install -e .

Quick Start

from surrogate_forest import SurrogateRandomForestClassifier
import numpy as np

X = np.random.randn(500, 10)
X[np.random.rand(*X.shape) < 0.2] = np.nan  # 20% missing
y = (X[:, 0] > 0).astype(int)  # NaN-safe comparison not needed — handled internally

clf = SurrogateRandomForestClassifier(n_estimators=100, max_surrogates=5, random_state=42)
clf.fit(X, y)
predictions = clf.predict(X)
probabilities = clf.predict_proba(X)

How It Works

Missing Data Handling (3-layer fallback)

At each internal node during prediction:

  1. Primary split — if the split feature is available, use the threshold
  2. Surrogate splits — if primary is missing, try backup splits on correlated features (first non-missing wins)
  3. Learned direction — if all surrogates are also missing, go left or right based on the direction that was optimal during training (XGBoost-style)

Surrogate Split Discovery

After choosing the primary split at each node:

  1. Determine primary's left/right assignment for all samples
  2. For every other feature, find the threshold maximizing concordance with the primary
  3. Compute predictive measure of association: λ = (p_naive_error - disagreement) / p_naive_error
  4. Support mirrored surrogates (negatively correlated features)
  5. Rank by λ, keep top max_surrogates

Estimators

Estimator Task Key Default
SurrogateDecisionTreeClassifier Classification max_features=None
SurrogateDecisionTreeRegressor Regression criterion='squared_error'
SurrogateRandomForestClassifier Classification max_features='sqrt'
SurrogateRandomForestRegressor Regression max_features='sqrt'

Key Parameters

Parameter Default Description
max_surrogates 5 Surrogate splits per node
use_histogram True Histogram-based splitting (LightGBM-style)
max_bins 255 Histogram resolution
symmetric_tree False CatBoost-style oblivious trees
max_leaf_nodes None If set, enables best-first (leaf-wise) growth

All standard sklearn tree/forest parameters are also supported: max_depth, min_samples_split, min_samples_leaf, max_features, n_estimators, bootstrap, oob_score, n_jobs, etc.

Feature Importance

Three types of feature importance:

from surrogate_forest import impurity_importance, surrogate_importance, permutation_importance

# Standard impurity-based (MDI)
imp = impurity_importance(fitted_model)

# Surrogate-based (unique to this library)
# Captures feature redundancy/substitutability
surr_imp = surrogate_importance(fitted_model)

# Permutation importance (correctly shuffles NaN patterns)
perm_imp = permutation_importance(fitted_model, X, y, n_repeats=10)

Growth Modes

from surrogate_forest import SurrogateDecisionTreeClassifier

# Depth-first (default CART)
tree = SurrogateDecisionTreeClassifier(max_depth=5)

# Best-first / leaf-wise (LightGBM-style)
tree = SurrogateDecisionTreeClassifier(max_leaf_nodes=31)

# Symmetric / oblivious (CatBoost-style)
tree = SurrogateDecisionTreeClassifier(max_depth=6, symmetric_tree=True)

sklearn Compatibility

Full compatibility with sklearn's API:

from sklearn.pipeline import Pipeline
from sklearn.model_selection import cross_val_score, GridSearchCV

# Works in pipelines
pipe = Pipeline([("clf", SurrogateRandomForestClassifier())])

# Works with cross-validation
scores = cross_val_score(clf, X, y, cv=5)

# Works with grid search
param_grid = {"max_depth": [3, 5, 10], "max_surrogates": [0, 3, 5]}
gs = GridSearchCV(SurrogateDecisionTreeClassifier(), param_grid, cv=3)

Testing

pytest tests/ -v

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

surrogate_forest-0.1.1.tar.gz (23.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

surrogate_forest-0.1.1-py3-none-any.whl (22.6 kB view details)

Uploaded Python 3

File details

Details for the file surrogate_forest-0.1.1.tar.gz.

File metadata

  • Download URL: surrogate_forest-0.1.1.tar.gz
  • Upload date:
  • Size: 23.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for surrogate_forest-0.1.1.tar.gz
Algorithm Hash digest
SHA256 6784fe747e5ebbc907d5ae959cc09529d10cc28dfb0d15b50b495b9a73ebadf2
MD5 f20383ae9fd4169e65e8fcf72b3f5803
BLAKE2b-256 7ea25640960c564946cdf1b8a7d3629c4aad9eec3266dd0598907a248fb3cd7e

See more details on using hashes here.

File details

Details for the file surrogate_forest-0.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for surrogate_forest-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 8a593fccb4f2b669203323c3eef9008cdd0178d26dcad9cd510cb9bde5a97e7c
MD5 fc7d11468873668c3a22d05ca77f8536
BLAKE2b-256 096119465d88c52071ef33aa72adc990a00b43f5c5b2420ca0db7da4c7c72d6a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page