Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes bug when using historical forecast with discrete lags < -1 #2715

Merged
merged 17 commits into from
Mar 7, 2025
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@
{},
(5, 3),
),
(LinearRegressionModel, {"lags": [-5]}, {}, (5, 1)),
(LinearRegressionModel, {"lags": [-5], "output_chunk_shift": 1}, {}, (5, 2)),
]
if not isinstance(CatBoostModel, NotImportedModule):
models_reg_no_cov_cls_kwargs.append((
Expand Down Expand Up @@ -132,6 +134,12 @@
{},
(6, 2),
),
(
LinearRegressionModel,
{"lags": [-3], "lags_past_covariates": 6, "lags_future_covariates": [0, 1]},
{},
(6, 2),
),
]

if TORCH_AVAILABLE:
Expand Down Expand Up @@ -665,7 +673,7 @@ def test_historical_forecasts_negative_rangeindex(self):
def test_historical_forecasts(self, config):
"""Tests historical forecasts with retraining for expected forecast lengths and times"""
forecast_horizon = 8
# if no fit and retrain=false, should fit at fist iteration
# if no fit and retrain=false, should fit at first iteration
model_cls, kwargs, model_kwarg, bounds = config
model = model_cls(**kwargs, **model_kwarg)
# set train length to be the minimum required training length
Expand Down
8 changes: 7 additions & 1 deletion darts/utils/historical_forecasts/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1020,7 +1020,13 @@ def _get_historical_forecast_boundaries(
hist_fct_tgt_start, hist_fct_tgt_end = historical_forecasts_time_index
if min_target_lag is not None:
hist_fct_tgt_start += min_target_lag * freq
hist_fct_tgt_end -= 1 * freq

# target lag has a gap between the max lag and the present
if hasattr(model, "lags") and model._get_lags("target") and not overlap_end:
hist_fct_tgt_end += 1 * freq * model._get_lags("target")[-1]
else:
hist_fct_tgt_end -= 1 * freq

# past lags are <= 0
hist_fct_pc_start, hist_fct_pc_end = historical_forecasts_time_index
if min_past_cov_lag is not None:
Expand Down
59 changes: 59 additions & 0 deletions testing2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from itertools import product

from sklearn.preprocessing import MaxAbsScaler

from darts.dataprocessing.transformers import Scaler
from darts.models import LinearRegressionModel
from darts.tests.utils.historical_forecasts.test_historical_forecasts import (
TestHistoricalforecast,
)
from darts.utils import timeseries_generation as tg

tester = TestHistoricalforecast()

sine_univariate1 = tg.sine_timeseries(length=50) * 2 + 1.5
sine_univariate2 = tg.sine_timeseries(length=50, value_phase=1.5705) * 5 + 1.5
sine_univariate3 = tg.sine_timeseries(length=50, value_phase=0.1963125) * -9 + 1.5

params = product(
[
(
{
"series": sine_univariate1 - 11,
},
{"series": Scaler(scaler=MaxAbsScaler())},
),
(
{
"series": sine_univariate3 + 2,
"past_covariates": sine_univariate1 * 3 + 3,
},
{"past_covariates": Scaler()},
),
(
{
"series": sine_univariate3 + 5,
"future_covariates": sine_univariate1 * (-4) + 3,
},
{"future_covariates": Scaler(scaler=MaxAbsScaler())},
),
(
{
"series": sine_univariate3 * 2 + 7,
"past_covariates": sine_univariate1 + 2,
"future_covariates": sine_univariate2 + 3,
},
{"series": Scaler(), "past_covariates": Scaler()},
),
],
[True, False], # retrain
[True, False], # last point only
[LinearRegressionModel],
)

i = 0

for param in params:
if i == 2 or i == 3:
tester.test_historical_forecasts_with_scaler(params=param)
i += 1
Loading