Thanks for your interest. This document covers everything you need to go from zero to an open pull request.
For significant changes — new algorithms, API modifications, or benchmark methodology — please open an issue first so the approach can be discussed before implementation.
git clone https://github.com/delgadopanadero/deepgboost.git
cd deepgboost
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e '.[dev]'
pre-commit installThe [dev] extra installs pytest, ruff, nbmake, pre-commit, xgboost, tqdm, and matplotlib. The editable install means changes to src/ are reflected immediately without reinstalling.
Fast unit tests (134 tests, completes in seconds):
.venv/bin/pytest tests/With coverage report:
.venv/bin/pytest tests/ --cov=deepgboost --cov-report=term-missingNotebook tests (executes every notebook end-to-end):
.venv/bin/pytest --nbmake examples/ benchmark/Notebook tests are slower — run them before opening a PR if you touched any notebook or the public API. CI runs both suites on every push.
Tree budget: any test or example you add must keep
n_layers × n_trees ≤ 100to stay fast in CI.
The project uses ruff with a single active rule set: COM812 (trailing commas). ruff-format enforces 80-character line width.
The pre-commit hook runs both ruff --fix and ruff-format automatically on every git commit. You can also run them manually:
ruff check --fix src/ tests/
ruff format src/ tests/No other linting conventions are enforced programmatically. Style expectations for new code:
- Concise — no unnecessary inline comments.
- No defensive error handling in internal (non-public) code.
- Follow sklearn naming and interface conventions for anything user-facing.
src/deepgboost/
__init__.py # Public API — all exports listed here
deepgboost_regressor.py # DeepGBoostRegressor (sklearn estimator)
deepgboost_classifier.py # DeepGBoostClassifier
deepgboost_multiclassifier.py# DeepGBoostMultiClassifier
dgbf/ # Core DGBF model (DGBFModel, DGBFMultiOutputModel)
objectives/ # Loss functions (get_objective)
tree/ # Decision tree utilities
callbacks/ # TrainingCallback and built-in callbacks
metric/ # Evaluation metrics (get_metric)
linear/ # Linear algebra helpers (NNLS, condition number)
predictor/ # Prediction aggregation
common/ # Shared utilities
plotting.py # plot_importance
tests/
test_regressor.py
test_classifier.py
test_multiclassifier.py
test_dgbf.py
test_callback.py
test_adaptive_layer_width.py
test_metric.py
test_objective.py
benchmark/
config.json # Models, datasets, and experiment settings
run_experiments.py # Entry point — run from benchmark/
models/ # Wrapper classes for each model in the benchmark
experiments/ # Experiment types (e.g. CrossValidationModelTest)
data/ # Downloaded datasets (git-ignored)
results/ # Output CSVs and figures (git-ignored)
examples/
quickstart.ipynb
regressor.ipynb
classifier.ipynb
serialization.ipynb
Do NOT modify dgbf/ unless you are intentionally changing the algorithm. If you are, open an issue first.
Follow this pattern when adding a public estimator (e.g. DeepGBoostQuantileRegressor):
-
New file:
src/deepgboost/deepgboost_<name>.py. Subclasssklearn.base.BaseEstimatorand the appropriate mixin (RegressorMixin,ClassifierMixin). Implement at minimumfit,predict,get_params,set_params. -
Export: add the class to
src/deepgboost/__init__.py— both the import and the__all__list. -
Tests: add
tests/test_<name>.py. Coverfit/predict,sklearn.clone(),Pipelineintegration, serialization viapickle, and any estimator-specific behaviour. -
Docstring: the class docstring must have
Parameters,Attributes,Examplessections. Public methods need at minimum a one-line summary and aParameters/Returnsblock. -
Notebook (if user-facing): add or update a notebook in
examples/demonstrating realistic use. Keep tree budget withinn_layers × n_trees ≤ 100. -
Benchmark wrapper (optional): if you want the estimator to appear in benchmark comparisons, add a wrapper class in
benchmark/models/following the pattern ofdeepgboost_regressor_model.py, then register it inbenchmark/config.json.
The benchmark is configured entirely through benchmark/config.json. No code changes are required to add a dataset or swap a model.
Add a dataset:
{
"name": "MyDataset",
"url": "https://example.com/data.csv",
"function": "read_csv",
"file": "data/mydataset.csv",
"sep": ",",
"target_column": "target",
"task": "regression"
}Add the object to the "Datasets" array. Supported "task" values: "regression", "classification".
Add a model:
- Create a wrapper in
benchmark/models/that inherits fromAbstractModel(see existing wrappers for the interface). - Register it in
config.jsonunder the appropriate task key ("regression"or"classification"):
"model_5": {
"module": "benchmark.models",
"object": "MyModel",
"parameters": { "n_estimators": 100 }
}Run the benchmark from the benchmark/ directory:
cd benchmark
python run_experiments.pyResults are written to benchmark/results/. The benchmark/data/ directory is git-ignored; datasets are downloaded on first run.
Before opening a PR, confirm:
-
pytest tests/passes locally with no failures. -
ruff check src/ tests/reports no errors (pre-commit should handle this automatically). - Any new public class or method has a docstring with
ParametersandReturnssections. - New or changed behaviour is covered by at least one test.
- If you touched a notebook,
pytest --nbmake examples/passes. - The PR description explains why the change is needed, not just what it does.
- Branch is up to date with
mainbefore requesting review.
Branch off main, keep commits focused, and use squash merge when landing. Commit messages follow the pattern type(#issue): description (e.g. feat(#42): add quantile regression objective).