Task 1 — Lazy Fitting with default LightGBM parameters.
Creates an unfitted forecaster per target and fits with default hyperparameters. No cross-validation or tuning is performed.
When cached tuning results are available (saved by a prior run in the spotforecast2 sibling package), they are loaded and applied automatically so that the lazy task benefits from prior tuning without re-running the search.
Aggregate per-target prediction packages into a weighted forecast.
Delegates to the module-level agg_predictor function. Available as an instance method so that subclasses can override the aggregation strategy when needed.
Build, combine, encode, and merge exogenous feature covariates.
This is step 4-7 of the pipeline (run after prepare_data, detect_outliers, and impute). It assembles the full exogenous-covariate matrix that the forecaster consumes, then merges it onto the target data. The orchestration proceeds in order:
4a — Weather, via get_weather_features (Open-Meteo). The response is parquet-cached only when config.cache_home is set. Fetch failures are handled per config.on_weather_failure: "raise" re-raises WeatherFetchError; "skip" logs a warning and continues with an empty weather frame (fail-safe). When config.zone_weather_columns is set (opt-in, mutually exclusive with per_zone_weather / use_population_weighted_weather), this step instead calls weather.zone_columns.build_zone_weather_columns and concatenates population-weighted weather for each of the four German TSO zones as __<zone_short>-suffixed columns (e.g. temperature_2m__50hertz) for the single target.
4b — Calendar features, via get_calendar_features.
4c — Day/night (solar) features, via get_day_night_features (computed with astral from config.latitude / config.longitude).
4d — Holiday features, via get_holiday_features for config.country_code / config.state.
5 — The four frames are concatenated along the columns and any residual gaps are back- then forward-filled.
4f — Lagged-load exog (opt-in, default OFF, gated by config.include_load_lag_exog), via preprocessing.load_lags.build_load_lag_features. Runs AFTER the Step-5 backfill so a load-lag coverage failure is never masked by it. Appends load_lag_<L> / load_<zone>_lag_<L> / share_<zone>_lag_<L> columns per config.load_lag_hours / config.load_lag_sources. A coverage or staleness failure (or a missing zone-interim file for the "zones"/"zone_shares" sources) is governed by config.on_load_lag_failure: "raise" re-raises; "skip" logs a warning and omits the columns (fail-safe). Provider-based exogenous columns are then appended via build_providers_from_config (requires spotforecast2-safe >= 15.7.0). The active providers are governed by the config flags include_covid_infection_rate, include_entsoe_forecast_load, include_entsoe_renewable_forecast, include_entsoe_net_load, and include_entsoe_day_ahead_price. Cyclical (sine/cosine) encoding is then applied via apply_cyclical_encoding, and degree-config.poly_features_degree interaction terms are added via create_interaction_features. When the degree is at least 2, the polynomial columns are ranked by mutual information with the primary target and capped to config.max_poly_features via select_top_poly_features.
6 — The training feature set is chosen via select_exogenous_features (including, when config.include_day_type_features is set, the day-type columns is_workday / day_type), with provider and load-lag columns appended (order-preserving, de-duplicated).
7 — Targets and covariates are merged via merge_data_and_covariates into self.data_with_exog and the forecast-horizon covariates self.exo_pred.
When config.use_exogenous_features is False the method is a no-op and returns self immediately, leaving the pipeline target-only.
Per-zone weather frames keyed by target name, indexed over [data_start, cov_end] (covering the forecast horizon). Populated only when config.per_zone_weather is True and every zone fetch succeeded; empty otherwise (including the fail-safe “skip” degradation). Consumed at the per-target seam in _get_target_data to overwrite the shared weather columns.
If the Open-Meteo fetch fails (single-point, population-weighted, per-zone, or zone_weather_columns path) and config.on_weather_failure == "raise".
LoadLagError
If config.include_load_lag_exog is set, the load-lag builder cannot produce NaN-free columns (stale source, excessive staleness), and config.on_load_lag_failure == "raise".
If config.include_load_lag_exog is set with load_lag_sources in {"zones", "zone_shares"}, the zone-interim CSV is missing, and config.on_load_lag_failure == "raise".
Examples
With exogenous features disabled the method is a no-op, so the example below runs without any network access and leaves the pipeline target-only.
Delegates to config.forecaster_factory when set; otherwise falls back to default_lgbm_forecaster_factory. This factory hook lets callers swap the estimator without subclassing BaseTask.
Constructs the cross-validation splitter used by all tuning tasks. Internally uses sklearn.model_selection.TimeSeriesSplit to compute split boundaries that respect temporal ordering and avoid data leakage between folds.
The validation boundary is determined by run_state.end_train_ts minus config.delta_val. When config.train_size is set, the sklearn splitter uses a sliding fixed-size training window (max_train_size); otherwise an expanding window is used.
Training time series for the current target. Used both to determine the validation boundary and as the sequence passed to TimeSeriesSplit.split to derive initial_train_size.
Apply hard-bound filtering and IsolationForest outlier detection.
Hard bounds from config.bounds are applied to the pipeline data (out-of-bound values are removed and later filled by impute()). IsolationForest detection (config.use_outlier_detection) is advisory: detected outliers are logged per column but not removed.
Load the most recent fitted models from the cache directory.
Scans <cache_home>/models/<data_frame_name>/ for .joblib files matching the current data_frame_name. Optionally filters by task_name, target, and max_age_days.
Load the most recent tuning results for a target from cache.
Scans <cache_home>/tuning_results/ for files matching the current data_frame_name and target. Optionally filters by task_name and discards results older than max_age_days.
Plotting unavailable in spotforecast2-safe: Plotting is not available in spotforecast2-safe (no plotly/matplotlib). Use the spotforecast2 package for visualisation.
Save fitted forecaster models to the cache directory.
Each model is serialised with joblib (compress=3) into <cache_home>/models/<data_frame_name>/ using a datetime-stamped filename so that multiple snapshots can coexist.
If forecasters is None the method collects fitted models from self.results[task_name], where each prediction package is expected to contain a "forecaster" key.
Task identifier ("lazy", "defaults"). The names "optuna" and "spotoptim" are also accepted so that model caches produced by the spotforecast2 sibling package can be saved and loaded; no tuning is performed in this package.