Shared base for all multi-target forecasting pipeline tasks.
Inherits the complete data-preparation pipeline (steps 1-7) and all helper methods from spotforecast2_safe.multitask.base.BaseTask. PlottingMixin overrides the three visualisation hooks with live Plotly figures.
The public API — constructor signature, attributes, method names, and the PipelineConfig protocol — is identical to the safe-package base. See spotforecast2_safe.multitask.base.BaseTask for full documentation.
Task subclasses implement run() for their specific mode: LazyTask (lazy), OptunaTask (optuna), SpotOptimTask (spotoptim), PredictTask (predict), CleanTask (clean).
Visualisation additions over the safe base
plot_with_outliers: Renders original vs. cleaned data with outlier markers via spotforecast2.plots.plotter.plot_with_outliers. _show_prediction_figure: Calls make_plot and shows the figure interactively. _show_prediction_figure_agg: Same for the aggregated prediction.
Examples
import tempfileimport numpy as npimport pandas as pdfrom spotforecast2_safe.configurator.config_multi import ConfigMultifrom spotforecast2.multitask.base import BaseTask, PlottingMixinrng = np.random.default_rng(0)idx = pd.date_range("2023-01-01", periods=24*14, freq="h", tz="UTC")df = pd.DataFrame({"load": rng.normal(100, 10, len(idx))}, index=idx)df.index.name ="DateTime"with tempfile.TemporaryDirectory() as tmp: cfg = ConfigMulti( predict_size=6, use_exogenous_features=False, use_outlier_detection=False, auto_save_models=False, cache_home=tmp, ) task = BaseTask(cfg, dataframe=df)# Data-preparation pipeline (steps 1-3) task.prepare_data().detect_outliers().impute()print("Pipeline shape:", task.df_pipeline.shape)print("Targets:", task.config.targets)# PlottingMixin is in the MRO — visualisation hooks are live Plotly calls.print("PlottingMixin in MRO:", PlottingMixin intype(task).__mro__)assert task.df_pipeline.shape[1] ==1assert PlottingMixin intype(task).__mro__
Pipeline shape: (336, 1)
Targets: None
PlottingMixin in MRO: True
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).
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. 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, with provider 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.
Exogenous features used: False
Selected exog feature names: []
create_forecaster
multitask.BaseTask.create_forecaster(target=None)
Create a fresh forecaster for the given target.
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.
required
Returns
Name
Type
Description
TimeSeriesFold
A configured TimeSeriesFold instance ready to be passed to
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.
BaseTask.run is abstract — it raises NotImplementedError to enforce that every concrete task subclass provides its own implementation. Use LazyTask, OptunaTask, SpotOptimTask, PredictTask, or CleanTask for live pipelines.
import tempfileimport numpy as npimport pandas as pdfrom spotforecast2_safe.configurator.config_multi import ConfigMultifrom spotforecast2.multitask.base import BaseTaskfrom spotforecast2.multitask import LazyTaskrng = np.random.default_rng(0)idx = pd.date_range("2023-01-01", periods=24*14, freq="h", tz="UTC")df = pd.DataFrame({"load": rng.normal(100, 10, len(idx))}, index=idx)df.index.name ="DateTime"# BaseTask.run raises NotImplementedError — use a concrete subclass.with tempfile.TemporaryDirectory() as tmp: cfg = ConfigMulti(cache_home=tmp) base = BaseTask(cfg)try: base.run()exceptNotImplementedErroras exc:print("BaseTask.run() raised NotImplementedError (expected).")print(str(exc)[:60])# LazyTask overrides run() with lazy fitting logic.print("LazyTask.run is overridden:", LazyTask.run isnot BaseTask.run)assert LazyTask.run isnot BaseTask.run
BaseTask.run() raised NotImplementedError (expected).
BaseTask must implement run(). Use LazyTask, OptunaTask, Spo
LazyTask.run is overridden: True
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.