Skip to content

Commit ec90c2b

Browse files
committed
Split forecast_all, improve compute_rmse_for_terms
Remove training-window concatenation from forecast_all so it returns raw forecast output only; move the concat to the notebook call site Parameterise `compute_rmse_for_terms` with optional `n_components` (defaults to all fitted components, preserving existing behaviour) Update related docstrings in `pipeline_utils.py` and `plotting_utils.py`
1 parent 6b3ee47 commit ec90c2b

File tree

3 files changed

+13
-25
lines changed

3 files changed

+13
-25
lines changed

Notebooks/Jumper.ipynb

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -376,8 +376,8 @@
376376
"- `load_ts_all(prepared_path, TERM_SPECS)` loads prepared component time series.\n",
377377
"- `build_predictions(...)` creates one `Predictions` object per term.\n",
378378
"- `Predictions.forecast_single_series(...)` is used as a single-component demo.\n",
379-
"- `forecast_all(...)` runs multi-component forecasts for all terms and prepends the training window.\n",
380-
"- `Simulation.reconstruct(...)` maps predicted components back to physical space.\n"
379+
"- `forecast_all(...)` runs multi-component forecasts for all terms; the training window is prepended in the notebook.\n",
380+
"- `Simulation.reconstruct(...)` maps predicted components back to physical space."
381381
]
382382
},
383383
{
@@ -445,8 +445,10 @@
445445
"outputs": [],
446446
"source": [
447447
"hats, hat_stds, metrics_all = forecast_all(\n",
448-
" TERM_SPECS, preds, dfs, train_len=train_len, steps=steps\n",
449-
")"
448+
" TERM_SPECS, preds, train_len=train_len, steps=steps\n",
449+
")\n",
450+
"# Prepend the training window to each forecast for downstream reconstruction.\n",
451+
"hats = {k: pd.concat([dfs[k][:train_len], h]) for k, h in hats.items()}"
450452
]
451453
},
452454
{

src/nemo_spinup_forecast/pipeline_utils.py

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ def decompose_all(sims: Mapping[str, Simulation]) -> None:
122122
def compute_rmse_for_terms(
123123
specs: Sequence[TermSpec],
124124
sims: Mapping[str, Simulation],
125+
n_components: int | None = None,
125126
) -> tuple[dict[str, Any], dict[str, Any], dict[str, Any]]:
126127
"""Compute reconstruction error outputs for each configured term.
127128
@@ -131,24 +132,22 @@ def compute_rmse_for_terms(
131132
Term specifications defining the processing order and output keys.
132133
sims : Mapping[str, Simulation]
133134
Prepared and decomposed simulations keyed by :attr:`TermSpec.key`.
135+
n_components : int or None, default=None
136+
Number of components to use for reconstruction. When ``None``,
137+
all fitted components (``len(s.pca.components_)``) are used.
134138
135139
Returns
136140
-------
137141
tuple[dict[str, Any], dict[str, Any], dict[str, Any]]
138142
Tuple ``(recs, rmseVs, rmseMs)`` where each dictionary is keyed by
139143
:attr:`TermSpec.key`.
140-
141-
Notes
142-
-----
143-
Uses all fitted components via ``len(s.pca.components_)`` before calling
144-
:meth:`Simulation.error`.
145144
"""
146145
recs: dict[str, Any] = {}
147146
rmseVs: dict[str, Any] = {}
148147
rmseMs: dict[str, Any] = {}
149148
for spec in specs:
150149
s = sims[spec.key]
151-
n = len(s.pca.components_)
150+
n = n_components if n_components is not None else len(s.pca.components_)
152151
rec, rmseV, rmseM = s.error(n)
153152
recs[spec.key] = rec
154153
rmseVs[spec.key] = rmseV
@@ -255,21 +254,18 @@ def build_predictions(
255254
def forecast_all(
256255
specs: Sequence[TermSpec],
257256
preds: Mapping[str, Predictions],
258-
dfs: Mapping[str, pd.DataFrame],
259257
*,
260258
train_len: int,
261259
steps: int,
262260
) -> tuple[dict[str, pd.DataFrame], dict[str, Any], dict[str, Any]]:
263-
"""Forecasts for all terms and return outputs by key.
261+
"""Run parallel forecasts for all terms and return raw outputs by key.
264262
265263
Parameters
266264
----------
267265
specs : Sequence[TermSpec]
268266
Term specifications defining processing order and output keys.
269267
preds : Mapping[str, Predictions]
270268
Prediction objects keyed by :attr:`TermSpec.key`.
271-
dfs : Mapping[str, pd.DataFrame]
272-
Original component time-series DataFrames keyed by term.
273269
train_len : int
274270
Number of initial rows used as the training window.
275271
steps : int
@@ -279,21 +275,13 @@ def forecast_all(
279275
-------
280276
tuple[dict[str, pd.DataFrame], dict[str, Any], dict[str, Any]]
281277
Tuple ``(hats, hat_stds, metrics)`` keyed by :attr:`TermSpec.key`.
282-
283-
Notes
284-
-----
285-
For each term, the function prepends ``dfs[key][:train_len]`` to the
286-
forecast output from
287-
:meth:`~nemo_spinup_forecast.forecast.Predictions.parallel_forecast`.
278+
``hats`` contains the raw forecast output (forecast period only).
288279
"""
289280
hats: dict[str, pd.DataFrame] = {}
290281
hat_stds: dict[str, Any] = {}
291282
metrics: dict[str, Any] = {}
292283
for spec in specs:
293-
# Forecast each time series component for each property
294284
hat, hat_std, m = preds[spec.key].parallel_forecast(train_len, steps)
295-
# Concatenate the forecasted time series period with the reference traning period
296-
hat = pd.concat([dfs[spec.key][:train_len], hat[:]])
297285
hats[spec.key] = hat
298286
hat_stds[spec.key] = hat_std
299287
metrics[spec.key] = m

src/nemo_spinup_forecast/plotting_utils.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -411,8 +411,6 @@ def plot_component_timeseries(
411411
Length for the x-axis.
412412
train_len : int
413413
Number of initial time steps that belong to the training window.
414-
Must match the value used in :func:`forecast_all` to concatenate
415-
training data with the forecast.
416414
steps_per_year : int, optional
417415
Number of time steps per year, used to set x-axis tick spacing.
418416
Default is 1 (yearly data).

0 commit comments

Comments
 (0)