Skip to content

Commit

Permalink
fix/historical_fore_fut_cov_notarget_lags (unit8co#1685)
Browse files Browse the repository at this point in the history
  • Loading branch information
dumjax authored and alexcolpitts96 committed May 31, 2023
1 parent da0061a commit 97b671d
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 69 deletions.
3 changes: 1 addition & 2 deletions darts/models/forecasting/baselines.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def predict(self, n: int, num_samples: int = 1, verbose: bool = False):

@property
def extreme_lags(self):
return (-self.K, 1, None, None, None)
return -self.K, 0, None, None, None, None


class NaiveDrift(LocalForecastingModel):
Expand Down Expand Up @@ -182,7 +182,6 @@ def fit(
past_covariates: Optional[Union[TimeSeries, Sequence[TimeSeries]]] = None,
future_covariates: Optional[Union[TimeSeries, Sequence[TimeSeries]]] = None,
):

super().fit(
series=series,
past_covariates=past_covariates,
Expand Down
94 changes: 49 additions & 45 deletions darts/models/forecasting/forecasting_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,52 +279,54 @@ def extreme_lags(
Optional[int],
Optional[int],
Optional[int],
Optional[int],
]:
"""
A 5-tuple containing in order:
(minimum target lag, maximum target lag, min past covariate lag, min future covariate lag, max future covariate
lag). If 0 is the index of the first prediction, then all lags are relative to this index, except for the
maximum target lag, which is relative to the last element of the time series before the first prediction.
A 6-tuple containing in order:
(min target lag, max target lag, min past covariate lag, max past covariate lag, min future covariate
lag, max future covariate lag). If 0 is the index of the first prediction, then all lags are relative to this
index.
See examples below.
If the model wasn't fitted with:
- target lag (concerning RegressionModels only) the first element should be `None`.
- target (concerning RegressionModels only): then the first element should be `None`.
- past covariates, the third element should be `None`.
- past covariates: then the third and fourth elements should be `None`.
- future covariates, the fourth and fifth elements should be `None`.
- future covariates: then the fifth and sixth elements should be `None`.
Should be overridden by models that use past or future covariates, and/or for model that have minimum target
lag and maximum target lags potentially different from -1 and 1.
lag and maximum target lags potentially different from -1 and 0.
Notes
-----
maximum target lag (second value) cannot be `None` and is always larger than 1.
maximum target lag (second value) cannot be `None` and is always larger than or equal to 0.
Examples
--------
>>> model = LinearRegressionModel(lags=3, output_chunk_length=2)
>>> model.fit(train_series)
>>> model.extreme_lags
(-3, 2, None, None, None)
>>> model = LinearRegressionModel(lags=[3, 5], past_covariates_lags = 4, output_chunk_length=7)
(-3, 1, None, None, None, None)
>>> model = LinearRegressionModel(lags=[-3, -5], lags_past_covariates = 4, output_chunk_length=7)
>>> model.fit(train_series, past_covariates=past_covariates)
>>> model.extreme_lags
(-5, 7, -4, None, None)
>>> model = LinearRegressionModel(lags=[3, 5], future_covariates_lags = [4, 6], output_chunk_length=7)
(-5, 6, -4, -1, None, None)
>>> model = LinearRegressionModel(lags=[3, 5], lags_future_covariates = [4, 6], output_chunk_length=7)
>>> model.fit(train_series, future_covariates=future_covariates)
>>> model.extreme_lags
(-5, 7, None, 4, 6)
(-5, 6, None, None, 4, 6)
>>> model = NBEATSModel(input_chunk_length=10, output_chunk_length=7)
>>> model.fit(train_series)
>>> model.extreme_lags
(-10, 7, None, None, None)
>>> model = NBEATSModel(input_chunk_length=10, output_chunk_length=7, future_covariates_lags=[4, 6])
(-10, 6, None, None, None, None)
>>> model = NBEATSModel(input_chunk_length=10, output_chunk_length=7, lags_future_covariates=[4, 6])
>>> model.fit(train_series, future_covariates)
>>> model.extreme_lags
(-10, 7, None, 4, 6)
(-10, 6, None, None, 4, 6)
"""

return (-1, 1, None, None, None)
return -1, 0, None, None, None, None

@property
def _training_sample_time_index_length(self) -> int:
Expand All @@ -335,13 +337,14 @@ def _training_sample_time_index_length(self) -> int:
min_target_lag,
max_target_lag,
min_past_cov_lag,
max_past_cov_lag,
min_future_cov_lag,
max_future_cov_lag,
) = self.extreme_lags

return max(
max_target_lag,
max_future_cov_lag if max_future_cov_lag else 0,
max_target_lag + 1,
max_future_cov_lag + 1 if max_future_cov_lag else 0,
) - min(
min_target_lag if min_target_lag else 0,
min_past_cov_lag if min_past_cov_lag else 0,
Expand All @@ -351,27 +354,26 @@ def _training_sample_time_index_length(self) -> int:
@property
def _predict_sample_time_index_length(self) -> int:
"""
Required time_index length for one predict sample, for any model.
A predict sample is the minimum required set of series and covariates chunks to be able to predict
a single point.
Required time_index length for one `predict` function call, for any model.
"""
(
min_target_lag,
max_target_lag,
min_past_cov_lag,
max_past_cov_lag,
min_future_cov_lag,
max_future_cov_lag,
) = self.extreme_lags

return (max_future_cov_lag if max_future_cov_lag else 0) - min(
return (max_future_cov_lag + 1 if max_future_cov_lag else 0) - min(
min_target_lag if min_target_lag else 0,
min_past_cov_lag if min_past_cov_lag else 0,
min_future_cov_lag if min_future_cov_lag else 0,
)

def _get_historical_forecastable_time_index(
self,
series: Optional[TimeSeries] = None,
series: TimeSeries,
past_covariates: Optional[TimeSeries] = None,
future_covariates: Optional[TimeSeries] = None,
is_training: Optional[bool] = False,
Expand All @@ -392,7 +394,7 @@ def _get_historical_forecastable_time_index(
Parameters
----------
series
Optionally, a target series.
A target series.
past_covariates
Optionally, a past covariates.
future_covariates
Expand Down Expand Up @@ -436,49 +438,51 @@ def _get_historical_forecastable_time_index(
min_target_lag,
max_target_lag,
min_past_cov_lag,
max_past_cov_lag,
min_future_cov_lag,
max_future_cov_lag,
) = self.extreme_lags

intersect_ = None

# target longest possible time index
if (min_target_lag is not None) and (series is not None):
intersect_ = generate_index(
start=series.start_time()
- (min_target_lag - max_target_lag) * series.freq
if is_training
else series.start_time() - min_target_lag * series.freq,
end=series.end_time(),
freq=series.freq,
)
if min_target_lag is None:
min_target_lag = 0

# longest possible time index for target
intersect_ = generate_index(
start=series.start_time()
+ (max_target_lag - min_target_lag + 1) * series.freq
if is_training
else series.start_time() - min_target_lag * series.freq,
end=series.end_time() + 1 * series.freq,
freq=series.freq,
)

# past covariates longest possible time index
# longest possible time index for past covariates
if (min_past_cov_lag is not None) and (past_covariates is not None):
tmp_ = generate_index(
start=past_covariates.start_time()
- (min_past_cov_lag - max_target_lag) * past_covariates.freq
- (min_past_cov_lag - max_target_lag - 1) * past_covariates.freq
if is_training
else past_covariates.start_time()
- min_past_cov_lag * past_covariates.freq,
end=past_covariates.end_time(),
end=past_covariates.end_time()
- max_past_cov_lag * past_covariates.freq,
freq=past_covariates.freq,
)
if intersect_ is not None:
intersect_ = intersect_.intersection(tmp_)
else:
intersect_ = tmp_

# future covariates longest possible time index
# longest possible time index for future covariates
if (min_future_cov_lag is not None) and (future_covariates is not None):
tmp_ = generate_index(
start=future_covariates.start_time()
- (min_future_cov_lag - max_target_lag) * future_covariates.freq
- (min_future_cov_lag - max_target_lag - 1) * future_covariates.freq
if is_training
else future_covariates.start_time()
- min_future_cov_lag * future_covariates.freq,
end=future_covariates.end_time()
- (max_future_cov_lag - 1) * future_covariates.freq,
- max_future_cov_lag * future_covariates.freq,
freq=future_covariates.freq,
)

Expand Down Expand Up @@ -2300,4 +2304,4 @@ def _supress_generate_predict_encoding(self) -> bool:

@property
def extreme_lags(self):
return (-1, 1, None, 0, 0)
return -1, 0, None, None, 0, 0
4 changes: 3 additions & 1 deletion darts/models/forecasting/regression_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,8 +276,9 @@ def _model_encoder_settings(
@property
def extreme_lags(self):
min_target_lag = self.lags.get("target")[0] if "target" in self.lags else None
max_target_lag = self.output_chunk_length
max_target_lag = self.output_chunk_length - 1
min_past_cov_lag = self.lags.get("past")[0] if "past" in self.lags else None
max_past_cov_lag = self.lags.get("past")[-1] if "past" in self.lags else None
min_future_cov_lag = (
self.lags.get("future")[0] if "future" in self.lags else None
)
Expand All @@ -289,6 +290,7 @@ def extreme_lags(self):
min_target_lag,
max_target_lag,
min_past_cov_lag,
max_past_cov_lag,
min_future_cov_lag,
max_future_cov_lag,
)
Expand Down

0 comments on commit 97b671d

Please sign in to comment.