Getting Started
This guide takes you from a modeling question to a validated CartoBoost model. It is written for Python developers and data scientists working with tabular, spatial, or time-indexed data. You will install the package, fit a model, choose an appropriate validation split, compare a baseline, and save the result.
If you already know which API you need, jump to Choose A Model or the Python API Reference.
1. Define The Prediction Task
CartoBoost is meant for regression and forecasting tasks where temporal or spatial structure is part of the hypothesis. Typical questions include:
- Can time, location, and distance explain the target under a leakage-aware split?
- Does source-to-target direction change the estimate compared with treating the two ends as unordered IDs?
- Can demand be forecast from lagged demand, calendar features, and context?
- Do spatial splitters or sparse zone memberships recover signal that an axis-only model misses?
Define the target and evaluation split before selecting model features. For temporal-spatial data, random splits can overstate quality when near-duplicate times, zones, or route patterns appear in both train and validation data.
2. Match Features To The Data Structure
A first regression table might include:
- dense numeric columns: distance, coordinates, time of day, weekday, passenger count;
- periodic columns: hour-of-day with period
24, day-of-week with period7; - sparse-set columns: zones, route cells, or memberships derived from source and target identifiers;
- graph context: directed source-to-target flows when source and target roles should remain distinct.
Declare the split policy and feature schema for the scientific structure you want to test:
- use
SplitPolicy.AXIS_ONLYas the dense baseline; - use
SplitPolicy.STRUCTUREDwith periodic, spatial-pair, and sparse-set schema entries when those structures are part of the question.
3. Install
uv add cartoboost
Verify the install:
python -c "import cartoboost; print(cartoboost.__version__)"
python examples/quickstart.py
For pandas-backed forecasting examples, install pandas directly:
uv add pandas
Optional packages are installed only when needed. Install polars for Polars
inputs, optuna for Optuna tuning, or onnx for the supported ONNX export
subset.
4. Fit A Regression Model
Run the maintained NumPy quickstart for a complete fit, leakage-aware split, baseline comparison, and artifact round-trip. It is the canonical first example used by the README and browser documentation.
Start with SplitPolicy.AXIS_ONLY if the study only needs dense numeric
features. Use SplitPolicy.STRUCTURED only when the schema declares the
periodic, spatial, or sparse structure and the same validation split is used.
5. Use Sparse Memberships
Use sparse-set features when a trip belongs to multiple route or zone-derived sets and a wide one-hot matrix would be awkward or unstable.
schema = {
"dense": [
{"name": "trip_distance", "kind": "numeric"},
{"name": "pickup_hour", "kind": "periodic", "period": 24},
{"name": "pickup_x", "kind": "numeric"},
{"name": "pickup_y", "kind": "numeric"},
],
"sparse_sets": [
{"name": "zone_ids", "kind": "sparse_set"},
],
}
model = CartoBoostRegressor(
n_estimators=200,
learning_rate=0.04,
max_depth=5,
min_samples_leaf=30,
split_policy="structured",
)
model.fit(
X_train_dense,
y_train,
sparse_sets={"zone_ids": zone_ids_train},
feature_schema=schema,
)
See Spatial Modeling and Sparse Features for zone membership examples and blocked evaluation patterns.
6. Forecast Demand
Use ForecastFrame when the target is future demand, fare, duration, or another
time-indexed quantity. Panel data should identify the series, such as
pickup/dropoff lane or pickup zone.
from cartoboost.forecasting import ForecastFrame, ThetaForecaster
import pandas as pd
daily_lanes = pd.DataFrame(
{
"lane_id": ["route_a"] * 10 + ["route_b"] * 10,
"date": list(pd.date_range("2026-01-01", periods=10, freq="D")) * 2,
"pickup_trips": [
20, 21, 24, 23, 25, 28, 29, 27, 30, 31,
35, 36, 38, 37, 40, 42, 43, 41, 45, 46,
],
}
)
frame = ForecastFrame.from_pandas(
daily_lanes,
timestamp_col="date",
target_col="pickup_trips",
series_id_col="lane_id",
freq="D",
)
model = ThetaForecaster(season_length=7, prediction_interval_levels=[0.8, 0.95])
model.fit(frame)
forecast = model.predict(horizon=3).to_pandas()
Forecast tables are deterministic: series_id, timestamp, horizon,
model, mean, and interval columns such as lower_80 and upper_80.
Use Forecasting for rolling-origin backtesting, CartoBoost lag
features, artifact persistence, CLI workflows, and model selection.
7. Validate Against Strong Baselines
For temporal-spatial problems, hold out the latest rows before trusting model quality:
import cartoboost
from cartoboost.geo import PanelIndex, TimeIndex
from cartoboost.validation import native_out_of_time_split
time = TimeIndex(pickup_times, frequency="h")
panel = PanelIndex(["nyc_taxi"] * len(pickup_times), time=time)
manifest = native_out_of_time_split(
panel,
min_train_size=int(len(pickup_times) * 0.8),
horizon=len(pickup_times) - int(len(pickup_times) * 0.8),
step=len(pickup_times) - int(len(pickup_times) * 0.8),
dataset_fingerprint="sha256:...",
coordinate_crs_note="not_applicable",
model_version=cartoboost.__version__,
dependency_versions={"cartoboost": cartoboost.__version__},
)
_, train_idx, validation_idx = manifest.folds()[0]
model.fit(X_all[train_idx], y_all[train_idx])
predictions = model.predict(X_all[validation_idx])
Report the split design, target transform, feature set, RMSE, MAE, R2, training time, prediction time, and model settings. Compare against serious baselines on the same train/validation rows, such as LightGBM or XGBoost for tabular regression and appropriate local or external forecasting models for demand forecasting.
For benchmark claims, document out-of-time, spatial-blocked, grouped, and leakage-aware validation details in the benchmark writeup.
8. Add Graph Or Neural Structure When Justified
Graph, neural, and causal surfaces solve more specialized problems. Add them only when the data and validation design can test the extra structure; they are intentionally excluded from the core quickstart.
Use learned embeddings when high-cardinality IDs carry stable signal that is not captured by dense features alone.
from cartoboost import NeuralEmbeddingRegressor
neural_model = NeuralEmbeddingRegressor(
dim=16,
base_model_kwargs={"n_estimators": 80, "split_policy": "axis_only"},
final_model_kwargs={
"n_estimators": 120,
"split_policy": "structured",
},
)
neural_model.fit(X_train, y_train, ids=pickup_zone_ids_train)
predictions = neural_model.predict(X_validation, ids=pickup_zone_ids_validation)
Use CartoBoost graph features or CartoBoost graph models when the observed units are connected entities, such as directed pickup/dropoff lanes, borough-zone hierarchies, or repeated OD-pair flow patterns. See CartoBoost Graph Models And Features and CartoBoost Neural Embedding Models And Features.
9. Save Reproducible Artifacts
model.save("cartoboost-regressor.json")
loaded = CartoBoostRegressor.load("cartoboost-regressor.json")
model.save_weights("cartoboost-regressor.weights.json")
weights_loaded = CartoBoostRegressor.load_weights("cartoboost-regressor.weights.json")
Use save for CartoBoost JSON model artifacts and save_weights for portable
prediction artifacts. ONNX export is available only for dense axis-tree
constant-leaf models when the optional onnx dependency is installed.
10. Source Checkout Checks
For a source checkout, run the full local validation suite with:
just validate
For a faster Python-focused loop:
uv run --group dev pre-commit run --all-files
uv run --group dev pytest