Skip to content

Commit

Permalink
- resetting regression_model.py to master version
Browse files Browse the repository at this point in the history
  • Loading branch information
eliane-maalouf committed Oct 7, 2022
1 parent 5c9d913 commit e28d9c6
Showing 1 changed file with 63 additions and 77 deletions.
140 changes: 63 additions & 77 deletions darts/models/forecasting/regression_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
from darts.timeseries import TimeSeries
from darts.utils.data.tabularization import _create_lagged_data
from darts.utils.multioutput import MultiOutputRegressor
from darts.utils.utils import _check_quantiles
from darts.utils.utils import _check_quantiles, seq2series, series2seq

logger = get_logger(__name__)

Expand Down Expand Up @@ -158,7 +158,7 @@ def __init__(
raise_if(
isinstance(lags_future_covariates[0], bool)
or isinstance(lags_future_covariates[1], bool),
"`lags_future_covariates` tuple must contain intergers, not bool",
"`lags_future_covariates` tuple must contain integers, not bool",
)

# set lags
Expand Down Expand Up @@ -249,7 +249,7 @@ def _model_encoder_settings(self) -> Tuple[int, int, bool, bool]:
takes_future_covariates,
)

def _get_encoders_n(self, n):
def _get_encoders_n(self, n) -> int:
"""Returns the `n` encoder prediction steps specific to RegressionModels.
This will generate slightly more past covariates than the minimum requirement when using past and future
covariate lags simultaneously. This is because encoders were written for TorchForecastingModels where we only
Expand Down Expand Up @@ -364,57 +364,38 @@ def fit(
**kwargs
Additional keyword arguments passed to the `fit` method of the model.
"""
# guarantee that all inputs are either list of TimeSeries or None
series = series2seq(series)
past_covariates = series2seq(past_covariates)
future_covariates = series2seq(future_covariates)

self.encoders = self.initialize_encoders()
if self.encoders.encoding_available:
past_covariates, future_covariates = self.encoders.encode_train(
target=series,
past_covariate=past_covariates,
future_covariate=future_covariates,
past_covariates, future_covariates = self.generate_fit_encodings(
series=series,
past_covariates=past_covariates,
future_covariates=future_covariates,
)

super().fit(
series=series,
past_covariates=past_covariates,
future_covariates=future_covariates,
)

raise_if(
past_covariates is not None and "past" not in self.lags,
"`past_covariates` not None in `fit()` method call, but `lags_past_covariates` is None in constructor.",
)

raise_if(
past_covariates is None and "past" in self.lags,
"`past_covariates` is None in `fit()` method call, but `lags_past_covariates` is not None in "
"constructor.",
)

raise_if(
future_covariates is not None and "future" not in self.lags,
"`future_covariates` not None in `fit()` method call, but `lags_future_covariates` is None in "
"constructor.",
)
for covs, name in zip([past_covariates, future_covariates], ["past", "future"]):
raise_if(
covs is not None and name not in self.lags,
f"`{name}_covariates` not None in `fit()` method call, but `lags_{name}_covariates` is None in "
f"constructor.",
)

raise_if(
future_covariates is None and "future" in self.lags,
"`future_covariates` is None in `fit()` method call, but `lags_future_covariates` is not None in "
"constructor.",
)
raise_if(
covs is None and name in self.lags,
f"`{name}_covariates` is None in `fit()` method call, but `lags_{name}_covariates` is not None in "
"constructor.",
)

# saving the dims of all input series to check at prediction time
if isinstance(series, TimeSeries):
self.input_dim = {
"target": series.width,
"past": past_covariates.width if past_covariates else None,
"future": future_covariates.width if future_covariates else None,
}
else:
self.input_dim = {
"target": series[0].width,
"past": past_covariates[0].width if past_covariates else None,
"future": future_covariates[0].width if future_covariates else None,
}
self.input_dim = {
"target": series[0].width,
"past": past_covariates[0].width if past_covariates else None,
"future": future_covariates[0].width if future_covariates else None,
}

# if multi-output regression
if not series[0].is_univariate or self.output_chunk_length > 1:
Expand Down Expand Up @@ -446,6 +427,12 @@ def fit(
):
logger.warning("Provided `n_jobs_multioutput_wrapper` wasn't used.")

super().fit(
series=seq2series(series),
past_covariates=seq2series(past_covariates),
future_covariates=seq2series(future_covariates),
)

self._fit_model(
series, past_covariates, future_covariates, max_samples_per_ts, **kwargs
)
Expand Down Expand Up @@ -489,16 +476,6 @@ def predict(
logger,
)

if self.encoders.encoding_available:
past_covariates, future_covariates = self.encoders.encode_inference(
n=self._get_encoders_n(n),
target=series,
past_covariate=past_covariates,
future_covariate=future_covariates,
)

super().predict(n, series, past_covariates, future_covariates, num_samples)

if series is None:
# then there must be a single TS, and that was saved in super().fit as self.training_series
raise_if(
Expand All @@ -507,21 +484,28 @@ def predict(
)
series = self.training_series

if past_covariates is None and self.past_covariate_series is not None:
past_covariates = self.past_covariate_series
if future_covariates is None and self.future_covariate_series is not None:
future_covariates = self.future_covariate_series
called_with_single_series = True if isinstance(series, TimeSeries) else False

called_with_single_series = False
# guarantee that all inputs are either list of TimeSeries or None
series = series2seq(series)
past_covariates = series2seq(past_covariates)
future_covariates = series2seq(future_covariates)

if isinstance(series, TimeSeries):
called_with_single_series = True
series = [series]
past_covariates = [past_covariates] if past_covariates is not None else None
future_covariates = (
[future_covariates] if future_covariates is not None else None
if self.encoders.encoding_available:
past_covariates, future_covariates = self.generate_predict_encodings(
n=n,
series=series,
past_covariates=past_covariates,
future_covariates=future_covariates,
)

if past_covariates is None and self.past_covariate_series is not None:
past_covariates = series2seq(self.past_covariate_series)
if future_covariates is None and self.future_covariate_series is not None:
future_covariates = series2seq(self.future_covariate_series)

super().predict(n, series, past_covariates, future_covariates, num_samples)

# check that the input sizes of the target series and covariates match
pred_input_dim = {
"target": series[0].width,
Expand Down Expand Up @@ -577,22 +561,24 @@ def predict(
f"but it ranges only from {cov.start_time()} until {cov.end_time()}.",
)

if cov.has_datetime_index:
covariate_matrices[cov_type].append(
cov[first_req_ts:last_req_ts].values()
)
else:
# include last_req_ts when slicing series with integer indices
covariate_matrices[cov_type].append(
cov[first_req_ts : last_req_ts + 1].values()
)
# Note: we use slice() rather than the [] operator because
# for integer-indexed series [] does not act on the time index.
last_req_ts = (
# For range indexes, we need to make the end timestamp inclusive here
last_req_ts + ts.freq
if ts.has_range_index
else last_req_ts
)
covariate_matrices[cov_type].append(
cov.slice(first_req_ts, last_req_ts).values(copy=False)
)

covariate_matrices[cov_type] = np.stack(covariate_matrices[cov_type])

series_matrix = None
if "target" in self.lags:
series_matrix = np.stack(
[ts[self.lags["target"][0] :].values() for ts in series]
[ts[self.lags["target"][0] :].values(copy=False) for ts in series]
)

# repeat series_matrix to shape (num_samples * num_series, n_lags, n_components)
Expand Down

0 comments on commit e28d9c6

Please sign in to comment.