Modeling internals: where the modelling actually happens¶
chap_core is not where models are implemented. Models are developed and
maintained independently, outside this repository; chap_core is the tooling
around them — running them, evaluating them, and storing and serving the results.
If you are looking for the code that learns disease dynamics from data, it is not in this package. This page explains the boundary, and then — because the question keeps coming up — accounts for the ML-looking code you will nonetheless find in the tree.
The external boundary¶
Everything with real modeling weight lives outside chap_core. The production
forecasting models (for example the DeepAR-based autoregressive models, and R/INLA
models) are maintained in their own repositories and executed through a
TrainPredictRunner implementation (Docker, UV, Conda, Renv, command-line, MLflow)
or against a remote chapkit HTTP service (see
Architecture diagrams). chap_core discovers them,
feeds them data, runs them, scores what comes back, and persists it.
The plumbing that loads and runs them is documented in
Code overview, and the reference/example models are catalogued
in Running models in Chap. The two
entry points into this shared core — the chap CLI and the REST API — are compared
in CLI vs REST API.
Why there is still ML-looking code in the tree¶
A few things inside chap_core do use ML libraries. None of them are the
forecasting models the platform exists to run: they are support machinery
(covariate preparation, hyperparameter search, explainability) plus a handful of
trivial baselines used in tests and as fast stand-ins.
The ML that does live inside chap_core is classical/statistical only. There
is no deep learning in the package. Confirmed absent from chap_core: torch,
tensorflow, jax, statsmodels, xgboost, lightgbm, pymc, prophet,
numpyro, pyro, gpflow.
The direct ML-relevant dependencies chap_core actually uses:
| Library | Role in chap_core |
|---|---|
| scikit-learn | climate predictor, Poisson baselines, KMeans clustering, LIME surrogate |
| optuna | hyperparameter search (HPO) |
| gluonts | evaluation (Evaluator) and data adaptors |
| scipy | explainability (signal / distance helpers) |
| numpy / pandas | all hand-written scoring metrics |
Three categories¶
It helps to split the in-tree code into three buckets, because much of what looks like "ML in chap_core" is actually tooling around models, or evaluation statistics.
| Category | What it is | Examples |
|---|---|---|
| A | Genuinely ML — learns from data to predict | climate predictor, Poisson/naive baselines, KMeans |
| B | ML tooling — uses ML, but is not itself a forecaster | HPO (optuna), LIME explainability |
| C | Not ML — evaluation statistics or heuristics | CRPS/Winkler/MAE metrics, preference learning |
A — Genuinely ML (learns to predict)¶
chap_core/climate_predictor.py— fits one scikit-learnLinearRegressionper(location, climate field)on a one-hot month/week feature matrix. This is the one in-tree model that is truly load-bearing: it fabricates the future climate covariates that a disease model needs before it can predict (the disease model never receives ground-truth future weather). It runs in both the real-prediction path (viaforecast_with_predicted_weather) and the backtesting path (viaQuickForecastFetcher).chap_core/predictor/poisson.py,chap_core/predictor/naive_predictor.py— scikit-learnPoissonRegressorbaselines (including a per-location, lagged-cases + one-hot-season variant). Mostly used in tests and example models.chap_core/predictor/naive_estimator.py—NaiveEstimator, the only built-in model wired into the live system: the database special-cases the configured model namednaive_modeland returns it as a fast, R-free stand-in. It predicts the per-location mean and draws Poisson samples — barely ML (essentially a statistic).chap_core/feature_generators/seasonality_cluster.pyandchap_core/plotting/season_plot.py— scikit-learnKMeansseasonality clustering (unsupervised).
B — ML tooling (uses ML, but is not a forecaster)¶
chap_core/hpo/— hyperparameter optimization built on optuna's TPE sampler (plus hand-rolled grid and random searchers). It tunes an external model template's hyperparameters against a backtest metric (default RMSE). It is CLI-only and not exposed in the REST API:
chap_core/explainability/(lime.py,surrogate.py,distance.py) — post-hoc LIME explanations. It fits a scikit-learnRidgelocal surrogate around an already-trained model to report feature importance. Note the nuance: LIME uses ML mechanics (it fits a regression) but is not a predictive model — it is interpretability tooling about a model, so under a strict "learns-to-predict" definition it does not count as an ML model.
C — Not ML (evaluation statistics / heuristics)¶
chap_core/assessment/metrics/— the scoring metrics, all hand-implemented on numpy: a from-scratch order-statistic CRPS estimator, Winkler interval scores, MAE / RMSE / MAPE, percentile-coverage calibration, outbreak-detection sensitivity/specificity, and peak-timing diff. This is substantive statistical code and the busiest ML-adjacent surface (the REST worker, the REST API router, the CLI, and HPO all route through it) — but it is scoring, not learning. See Evaluation pipeline and Creating custom metrics.chap_core/preference_learning/— despite a docstring mentioning Bayesian / bandit strategies, the only implementation is a plain tournament bracket that A/B-compares model configurations. No ML library; one CLI command. See Preference learning.- gluonts
Evaluatorusage inchap_core/assessment/prediction_evaluator.py— quantile-based evaluation plumbing, not a model.
One-line answer¶
The models are external. The only strictly-ML (learns-to-predict) code in
chap_core is the scikit-learn climate-covariate predictor and the Poisson/naive
baselines, plus KMeans clustering — support machinery and baselines, not the
platform's forecasting models. HPO and LIME are ML tooling; the metrics and
preference learning are statistics and heuristics.