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

Feat/encoder improvement #1338

Merged
merged 29 commits into from
Dec 22, 2022
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
4b9851d
make encoders work with covariate lags
dennisbader Oct 22, 2022
96477f6
simplify lags logic
dennisbader Oct 23, 2022
5dec1ae
Merge branch 'master' into feat/encoder_improvement_test
dennisbader Oct 30, 2022
0bccdb9
better documentation for index generators
dennisbader Oct 30, 2022
3141323
adapted encoders for LFMs
dennisbader Oct 30, 2022
6dbbeda
add encoders to all FutureCovariatesLocalForecastingModels
dennisbader Oct 30, 2022
d1891a9
adapt TransferableFuture... for encoders without user covariates
dennisbader Nov 1, 2022
e902b8d
transferrable kalman forecaster
dennisbader Nov 1, 2022
48a2fef
fix reset_index bug in TimeSeries.append and slicing future covs in LFMs
dennisbader Nov 6, 2022
3094853
fix integer index frequency
dennisbader Nov 6, 2022
adf4c0d
improve encoder documentation
dennisbader Nov 6, 2022
4e6c916
update Explainers with new encoder logic
dennisbader Nov 6, 2022
3c8ac03
remove absolute position artifact
dennisbader Nov 6, 2022
1d44b3e
Merge branch 'master' into feat/encoder_improvement
dennisbader Nov 6, 2022
7e2deaf
Merge branch 'master' into feat/encoder_improvement
dennisbader Dec 10, 2022
d359971
Merge branch 'master' into feat/encoder_improvement
dennisbader Dec 10, 2022
67f70af
apply suggestions from PR review
dennisbader Dec 11, 2022
b15da52
apply suggestions from PR review part 2
dennisbader Dec 11, 2022
3fb2e43
Merge branch 'master' into feat/encoder_improvement
hrzn Dec 13, 2022
d17a279
Merge branch 'master' into feat/encoder_improvement
hrzn Dec 16, 2022
09539d7
apply suggestions from PR review part 3
dennisbader Dec 11, 2022
0ea58c4
rename *covariates_lags to lags_*_covariates for consistency with reg…
dennisbader Dec 17, 2022
48c16a3
fix failing test from naive model updates
dennisbader Dec 17, 2022
a882a4b
fix regression model prediction to use minimum required covariates
dennisbader Dec 21, 2022
9283525
update regression model encoder settings for one shot model
dennisbader Dec 21, 2022
a62e7ea
fix new prediction logic
dennisbader Dec 22, 2022
838ccd4
Merge branch 'master' into feat/encoder_improvement
dennisbader Dec 22, 2022
eb4f6ae
added changes to changelog
dennisbader Dec 22, 2022
a841116
revert a change from regression model tests
dennisbader Dec 22, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
409 changes: 358 additions & 51 deletions darts/dataprocessing/encoders/encoder_base.py

Large diffs are not rendered by default.

323 changes: 247 additions & 76 deletions darts/dataprocessing/encoders/encoders.py

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions darts/explainability/explainability.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,7 @@ def __init__(
(
background_past_covariates,
background_future_covariates,
) = self.model.generate_predict_encodings(
n=len(background_series) - self.model.min_train_series_length,
) = self.model.generate_fit_encodings(
series=background_series,
past_covariates=background_past_covariates,
future_covariates=background_future_covariates,
Expand Down
17 changes: 3 additions & 14 deletions darts/explainability/shap_explainer.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,22 +201,12 @@ def explain(
foreground_past_covariates = series2seq(foreground_past_covariates)
foreground_future_covariates = series2seq(foreground_future_covariates)

# For encoding inference, in case we don't have past and future covariates,
# We need to provide the minimum elements for the foreground_series. If the foreground_series
# is a list of TimeSeries, we need to provide the minimum elements for each TimeSeries.
foreground_series_start_encoder = []
for i in range(len(foreground_series)):
foreground_series_start_encoder.append(
foreground_series[i][: self.model.min_train_series_length]
)

if self.model.encoders.encoding_available:
(
foreground_past_covariates,
foreground_future_covariates,
) = self.model.generate_predict_encodings(
n=len(foreground_series) - self.model.min_train_series_length,
series=foreground_series_start_encoder,
) = self.model.generate_fit_encodings(
series=foreground_series,
past_covariates=foreground_past_covariates,
future_covariates=foreground_future_covariates,
)
Expand Down Expand Up @@ -377,8 +367,7 @@ def force_plot_from_ts(
(
foreground_past_covariates,
foreground_future_covariates,
) = self.model.generate_predict_encodings(
n=len(foreground_series) - self.model.min_train_series_length,
) = self.model.generate_fit_encodings(
series=foreground_series,
past_covariates=foreground_past_covariates,
future_covariates=foreground_future_covariates,
Expand Down
2 changes: 2 additions & 0 deletions darts/models/filtering/filtering_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ class FilteringModel(ABC):

@abstractmethod
def __init__(self):
self._expect_past_covariates = False
dennisbader marked this conversation as resolved.
Show resolved Hide resolved
self._expect_future_covariates = False
pass

@abstractmethod
Expand Down
11 changes: 5 additions & 6 deletions darts/models/filtering/kalman_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ def __init__(self, dim_x: int = 1, kf: Optional[Kalman] = None):
# TODO: Add support for x_init. Needs reimplementation of NFourSID.

super().__init__()
self._expect_covariates = False

if kf is None:
self.kf = None
Expand All @@ -68,7 +67,7 @@ def __init__(self, dim_x: int = 1, kf: Optional[Kalman] = None):
self.dim_y = kf.state_space.y_dim
self._kf_provided = True
if self.dim_u > 0:
self._expect_covariates = True
self._expect_future_covariates = True

def __str__(self):
return f"KalmanFilter(dim_x={self.dim_x})"
Expand Down Expand Up @@ -101,7 +100,7 @@ def fit(
Fitted Kalman filter.
"""
if covariates is not None:
self._expect_covariates = True
self._expect_future_covariates = True
covariates = covariates.slice_intersect(series)
raise_if_not(
series.has_same_time_as(covariates),
Expand Down Expand Up @@ -181,11 +180,11 @@ def filter(
)

raise_if(
covariates is not None and not self._expect_covariates,
covariates is not None and not self._expect_future_covariates,
"Covariates were provided, but the Kalman filter was not fitted with covariates.",
)

if self._expect_covariates:
if self._expect_future_covariates:
raise_if(
covariates is None,
"The Kalman filter was fitted with covariates, but these were not provided.",
Expand All @@ -205,7 +204,7 @@ def filter(
kf = deepcopy(self.kf)

y_values = series.values(copy=False)
if self._expect_covariates:
if self._expect_future_covariates:
u_values = covariates.values(copy=False)

# set control signal to 0 if it contains NaNs:
Expand Down
23 changes: 22 additions & 1 deletion darts/models/forecasting/arima.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ def __init__(
seasonal_order: Tuple[int, int, int, int] = (0, 0, 0, 0),
trend: Optional[str] = None,
random_state: int = 0,
add_encoders: Optional[dict] = None,
):
"""ARIMA
ARIMA-type models extensible with exogenous variables (future covariates)
Expand All @@ -54,8 +55,28 @@ def __init__(
Parameter controlling the deterministic trend. 'n' indicates no trend,
'c' a constant term, 't' linear trend in time, and 'ct' includes both.
Default is 'c' for models without integration, and no trend for models with integration.
add_encoders
A large number of future covariates can be automatically generated with `add_encoders`.
This can be done by adding multiple pre-defined index encoders and/or custom user-made functions that
will be used as index encoders. Additionally, a transformer such as Darts' :class:`Scaler` can be added to
transform the generated covariates. This happens all under one hood and only needs to be specified at
model creation.
Read :meth:`SequentialEncoder <darts.dataprocessing.encoders.SequentialEncoder>` to find out more about
``add_encoders``. Default: ``None``. An example showing some of ``add_encoders`` features:

.. highlight:: python
.. code-block:: python

add_encoders={
'cyclic': {'future': ['month']},
'datetime_attribute': {'future': ['hour', 'dayofweek']},
'position': {'future': ['relative']},
'custom': {'future': [lambda idx: (idx.year - 1950) / 50]},
'transformer': Scaler()
}
..
"""
super().__init__()
super().__init__(add_encoders=add_encoders)
self.order = p, d, q
self.seasonal_order = seasonal_order
self.trend = trend
Expand Down
26 changes: 24 additions & 2 deletions darts/models/forecasting/auto_arima.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@


class AutoARIMA(FutureCovariatesLocalForecastingModel):
def __init__(self, *autoarima_args, **autoarima_kwargs):
def __init__(
self, *autoarima_args, add_encoders: Optional[dict] = None, **autoarima_kwargs
):
"""Auto-ARIMA

This implementation is a thin wrapper around `pmdarima AutoARIMA model
Expand All @@ -40,8 +42,28 @@ def __init__(self, *autoarima_args, **autoarima_kwargs):
Positional arguments for the pmdarima.AutoARIMA model
autoarima_kwargs
Keyword arguments for the pmdarima.AutoARIMA model
add_encoders
A large number of future covariates can be automatically generated with `add_encoders`.
This can be done by adding multiple pre-defined index encoders and/or custom user-made functions that
will be used as index encoders. Additionally, a transformer such as Darts' :class:`Scaler` can be added to
transform the generated covariates. This happens all under one hood and only needs to be specified at
model creation.
Read :meth:`SequentialEncoder <darts.dataprocessing.encoders.SequentialEncoder>` to find out more about
``add_encoders``. Default: ``None``. An example showing some of ``add_encoders`` features:

.. highlight:: python
.. code-block:: python

add_encoders={
'cyclic': {'future': ['month']},
'datetime_attribute': {'future': ['hour', 'dayofweek']},
'position': {'future': ['relative']},
'custom': {'future': [lambda idx: (idx.year - 1950) / 50]},
'transformer': Scaler()
}
..
"""
super().__init__()
super().__init__(add_encoders=add_encoders)
self.model = PmdAutoARIMA(*autoarima_args, **autoarima_kwargs)
self.trend = self.model.trend

Expand Down
28 changes: 26 additions & 2 deletions darts/models/forecasting/croston.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@

class Croston(FutureCovariatesLocalForecastingModel):
def __init__(
self, version: str = "classic", alpha_d: float = None, alpha_p: float = None
self,
version: str = "classic",
alpha_d: float = None,
alpha_p: float = None,
add_encoders: Optional[dict] = None,
):
"""An implementation of the `Croston method
<https://otexts.com/fpp3/counts.html>`_ for intermittent
Expand All @@ -42,6 +46,26 @@ def __init__(
For the "tsb" version, the alpha smoothing parameter to apply on demand.
alpha_p
For the "tsb" version, the alpha smoothing parameter to apply on probability.
add_encoders
A large number of future covariates can be automatically generated with `add_encoders`.
This can be done by adding multiple pre-defined index encoders and/or custom user-made functions that
will be used as index encoders. Additionally, a transformer such as Darts' :class:`Scaler` can be added to
transform the generated covariates. This happens all under one hood and only needs to be specified at
model creation.
Read :meth:`SequentialEncoder <darts.dataprocessing.encoders.SequentialEncoder>` to find out more about
``add_encoders``. Default: ``None``. An example showing some of ``add_encoders`` features:

.. highlight:: python
.. code-block:: python

add_encoders={
'cyclic': {'future': ['month']},
'datetime_attribute': {'future': ['hour', 'dayofweek']},
'position': {'future': ['relative']},
'custom': {'future': [lambda idx: (idx.year - 1950) / 50]},
'transformer': Scaler()
}
..

References
----------
Expand All @@ -51,7 +75,7 @@ def __init__(
Intermittent demand: Linking forecasting to inventory obsolescence.
European Journal of Operational Research, 214(3):606 – 615, 2011.
"""
super().__init__()
super().__init__(add_encoders=add_encoders)
raise_if_not(
version.lower() in ["classic", "optimized", "sba", "tsb"],
'The provided "version" parameter must be set to "classic", "optimized", "sba" or "tsb".',
Expand Down
Loading