Forecasting¶
Medium-range probabilistic forecasting of asset stress features. Requires the [ml] extra (pip install "climagrid[ml]"). See the forecasting guide for an overview.
climagrid.forecast¶
- climagrid.forecasting.api.forecast(assets, model, *, history_end=None, run_fn=None)[source]¶
Forecast asset stress from previously saved model(s). Never trains.
- Parameters:
assets (
AssetRegistry|str|Path) – AssetRegistry or path to an asset CSV/GeoJSON (asset_id, lat, lon).model (
str|Path|LightGBMForecaster) – A directory containingmanifest.json(and the per-factor model files), a path to a single saved.joblib, or a loadedLightGBMForecaster. Train and save these with the Kaggle training notebook (LightGBMForecaster.fit(...).save(...)).history_end (
datetime|None) – End of the recent window to fetch (UTC). Defaults to now. Only the recentmin_inference_history_days(plus a small buffer) is fetched, since that is all the saved model needs to build its predictors.run_fn (
Callable[...,DataFrame] |None) – Injection point forclimagrid.run(used by tests).
- Returns:
Long form: one row per (asset_id, origin_date, target, horizon_day) with
forecast_date, the quantile columns (p10/p50/p90), and arecommendationconfidence flag when served from a manifest. Empty if no recent data could be fetched.- Return type:
ForecastConfig¶
- class climagrid.forecasting.config.ForecastConfig(**data)[source]¶
Bases:
BaseModelParameters controlling the stress-feature forecast pipeline.
- Parameters:
targets (list[str]) – Stress-feature columns to forecast. Default is the single headline target
feat_thermal_aging_factor(a per-row Arrhenius function of temperature, where an ML model has the most to add over naive baselines). Add more targets at the cost of more trained models.horizon_days (int) – Maximum forecast lead time in days. One model is trained per horizon
1..horizon_days(direct multi-horizon strategy).daily_agg (Literal['max', 'mean', 'min']) – How hourly stress features are reduced to one value per day. Default
"max"matches how outputs.report.rank_assets ranks assets by peak stress.history_years (int) – Default length of training history when explicit dates are not given. 15 years balances seasonal-cycle coverage against climate drift in the oldest years; the right value is confirmed by backtest.history_ablation.
lags (list[int]) – Target autoregressive lags (in days) used as predictors.
rolling_windows (list[int]) – Trailing-window sizes (in days) for rolling mean/std predictors.
quantiles (list[float]) – Quantiles to predict for prediction intervals. Must include 0.5.
model (Literal['lightgbm', 'persistence', 'climatology']) – Forecaster family.
"lightgbm"is the trained model; the other two are the baselines the model is scored against.per_asset (bool) – If True, fit one model per asset; otherwise a single global pooled model that generalizes to unseen asset locations (default).
embargo_days (int | None) – Gap in days between train and test in the rolling-origin backtest, so a training target window never overlaps a test predictor window. Defaults to
horizon_dayswhen None.climatology_window_years (int | None) – If set, the climatology baseline uses only the most recent N years of history (a hedge against climate drift). None uses all training years.
calibrate_intervals (bool) – If True, conformally calibrate the prediction intervals: hold out the most recent
calibration_daysas a calibration set, fit on the rest, and adjust the interval so its coverage matches the nominal level.calibration_method (Literal['normalized', 'constant', 'mondrian']) –
"mondrian"(default): a separate width per meteorological season, which keeps the high-stress summer interval on target."normalized": locally adaptive width (even overall, but summer under-covered)."constant": a single additive width per horizon.calibration_days (int) – Size of the held-out calibration window. Should span a full seasonal cycle (default 365) so the calibration is not biased to one season.
sources (list[str]) – climagrid data sources to fetch. Default
["nasa_power"](keyless, hourly back to 2001).n_jobs (int) – LightGBM training parameters; defaults are conservative for a memory-constrained machine.
n_estimators (int) – LightGBM training parameters; defaults are conservative for a memory-constrained machine.
num_leaves (int) – LightGBM training parameters; defaults are conservative for a memory-constrained machine.
learning_rate (float) – LightGBM training parameters; defaults are conservative for a memory-constrained machine.
random_state (int) – LightGBM training parameters; defaults are conservative for a memory-constrained machine.
cache_dir (Path | None) – Directory for the cached daily panel parquet. None disables caching.
- model_config: ClassVar[ConfigDict] = {'frozen': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- property min_inference_history_days: int¶
Days of recent history needed to build predictors at inference time.
Equals the largest lag or rolling window. Forecasting forward from a saved model only needs this many recent days per asset, not the full training history, because the predictors are autoregressive lags and trailing rolling statistics that reach back at most this far.
Dataset construction¶
- climagrid.forecasting.dataset.build_training_panel(assets, history_start, history_end, config, *, run_fn=None)[source]¶
Build the daily training panel for a set of assets.
- Parameters:
assets (
AssetRegistry|str|Path) – An AssetRegistry or a path to an asset CSV/GeoJSON.history_start (
datetime) – Inclusive UTC date range of history to fetch.history_end (
datetime) – Inclusive UTC date range of history to fetch.config (
ForecastConfig) – Forecast configuration (targets, sources, daily aggregation, cache).run_fn (
Callable[...,DataFrame] |None) – Injection point forclimagrid.run(used by tests to mock fetching).
- Returns:
Columns:
asset_id,date,lat,lonand one column per present target, with one row per (asset, day), sorted by (asset_id, date). Empty if no data was returned for any asset.- Return type:
- climagrid.forecasting.dataset.build_supervised_frame(panel, target, config)[source]¶
Turn a daily panel into a supervised frame for one target.
- Return type:
- Parameters:
panel (DataFrame)
target (str)
config (ForecastConfig)
- Predictors (all known at the forecast origin
t): y_t: the target value at the origin,lag_k: the target value att - kfor each configured lag,rollmean_w/rollstd_w: trailing rolling mean/std over thewdays ending att - 1(shifted by 1 so the origin is excluded),doy_sin/doy_cos: day-of-year harmonics of the origin date,lat/lon: static location.
Targets:
y_h{h}is the target value att + hfor each horizon.Returns one row per (asset, origin date). Early rows have NaN lag/rolling predictors and late rows have NaN
y_h*targets; both are retained here (LightGBM tolerates NaN predictors; NaN targets are dropped at fit time).
Model and baselines¶
- class climagrid.forecasting.models.LightGBMForecaster(config)[source]¶
Bases:
objectDirect multi-horizon quantile forecaster backed by LightGBM.
- Parameters:
config (ForecastConfig)
- fit(frame, target)[source]¶
Train one LGBMRegressor per (horizon, quantile).
Rows whose
y_h{h}target is NaN (the tail of each asset’s series) are dropped per horizon. NaN predictors in early rows are kept; LightGBM handles them natively.- Return type:
- Parameters:
- calibrate(frame, target=None, *, method='normalized')[source]¶
Conformalize the outer prediction interval (Romano et al. 2019, CQR).
Uses a held-out calibration
frame(rows NOT seen during fit) to adjust the lowest/highest quantile bounds per horizon so the interval attains its nominal coverage (q_hi - q_lo, e.g. 0.80 for p10-p90) out of sample. The calibration set should span a full seasonal cycle. The conformity score isE = max(p_lo - y, y - p_hi)andQis itsceil((n + 1) * level) / nempirical quantile; predict() widens by Q.- Return type:
- Parameters:
- method:
"normalized"(default) scales the score by the model’s own interval width(p_hi - p_lo) + cso the widening adapts to local uncertainty."constant"applies a single additiveQper horizon (marginal coverage only)."mondrian"fits a separate additiveQper (horizon, meteorological season) keyed on the forecast date, targeting per-season coverage (helps where a season, e.g. summer, is otherwise under-covered); seasons with too few calibration points fall back to the pooled per-horizonQ.
- predict(frame, target=None)[source]¶
Produce long-form forecasts for every (row, horizon).
Returns one row per (asset_id, origin date, horizon) with columns:
asset_id,origin_date,forecast_date,horizon_day,targetand one column per quantile (p10,p50,p90), sorted so the quantile columns are non-decreasing. If the model has been conformally calibrated, the outer interval is widened accordingly.
- class climagrid.forecasting.baselines.PersistenceForecaster(config)[source]¶
Bases:
objectPredicts the origin value
y_tfor every horizon.- Parameters:
config (ForecastConfig)
Backtesting¶
- climagrid.forecasting.backtest.evaluate(panel, config, *, n_splits=3, test_size_days=90, event_threshold=0.0)[source]¶
Backtest the LightGBM model against baselines on a daily panel.
Returns one row per (fold, target, horizon) with point-accuracy metrics, skill scores versus both baselines, and interval calibration metrics.
skill_vs_persistence_eventsis the skill computed on only the active rows (where the actual value exceedsevent_threshold), andevent_fractionis their share. For mostly-zero, sparse targets (e.g. ice loading) the all-rows skill is inflated by the easy zero stretches; the event-conditioned skill reflects how well the model predicts the rare events that matter, and is the honest basis for a deploy decision.
- climagrid.forecasting.backtest.rolling_origin_splits(dates, config, *, n_splits=3, test_size_days=90)[source]¶
Build expanding-window (train, test) origin-date splits.
Test windows are placed back-to-back at the end of the timeline. Each fold’s training set expands to include everything up to
embargodays before its test window starts, whereembargodefaults to the max horizon (so a training target att + Hnever reaches a test origin).
- climagrid.forecasting.backtest.history_ablation(panel, config, *, windows_years=None, n_splits=3, test_size_days=90)[source]¶
Rerun
evaluateacross several history-window lengths.Lets the default history length be chosen on measured skill and calibration rather than assumed. Returns the concatenated per-fold metrics with a
history_yearscolumn.