autogluon.timeseries 1.4.1b20250821__py3-none-any.whl → 1.4.1b20250823__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of autogluon.timeseries might be problematic. Click here for more details.
- autogluon/timeseries/dataset/ts_dataframe.py +9 -9
- autogluon/timeseries/learner.py +14 -14
- autogluon/timeseries/metrics/__init__.py +5 -5
- autogluon/timeseries/metrics/abstract.py +9 -9
- autogluon/timeseries/models/abstract/abstract_timeseries_model.py +39 -41
- autogluon/timeseries/models/abstract/tunable.py +6 -6
- autogluon/timeseries/models/autogluon_tabular/mlforecast.py +30 -30
- autogluon/timeseries/models/autogluon_tabular/per_step.py +12 -12
- autogluon/timeseries/models/chronos/model.py +10 -10
- autogluon/timeseries/models/chronos/pipeline/base.py +8 -8
- autogluon/timeseries/models/chronos/pipeline/chronos.py +12 -12
- autogluon/timeseries/models/chronos/pipeline/chronos_bolt.py +12 -12
- autogluon/timeseries/models/chronos/pipeline/utils.py +12 -12
- autogluon/timeseries/models/ensemble/abstract.py +19 -19
- autogluon/timeseries/models/ensemble/basic.py +8 -8
- autogluon/timeseries/models/ensemble/greedy.py +13 -13
- autogluon/timeseries/models/gluonts/abstract.py +24 -24
- autogluon/timeseries/models/gluonts/dataset.py +2 -2
- autogluon/timeseries/models/gluonts/models.py +7 -7
- autogluon/timeseries/models/local/abstract_local_model.py +12 -12
- autogluon/timeseries/models/local/statsforecast.py +11 -11
- autogluon/timeseries/models/multi_window/multi_window_model.py +4 -4
- autogluon/timeseries/models/presets.py +14 -14
- autogluon/timeseries/models/registry.py +3 -3
- autogluon/timeseries/predictor.py +35 -35
- autogluon/timeseries/regressor.py +13 -13
- autogluon/timeseries/splitter.py +6 -6
- autogluon/timeseries/trainer.py +50 -49
- autogluon/timeseries/transforms/covariate_scaler.py +3 -3
- autogluon/timeseries/transforms/target_scaler.py +7 -7
- autogluon/timeseries/utils/datetime/lags.py +2 -2
- autogluon/timeseries/utils/datetime/time_features.py +2 -2
- autogluon/timeseries/utils/features.py +31 -31
- autogluon/timeseries/version.py +1 -1
- {autogluon.timeseries-1.4.1b20250821.dist-info → autogluon.timeseries-1.4.1b20250823.dist-info}/METADATA +5 -5
- autogluon.timeseries-1.4.1b20250823.dist-info/RECORD +72 -0
- autogluon.timeseries-1.4.1b20250821.dist-info/RECORD +0 -72
- /autogluon.timeseries-1.4.1b20250821-py3.9-nspkg.pth → /autogluon.timeseries-1.4.1b20250823-py3.9-nspkg.pth +0 -0
- {autogluon.timeseries-1.4.1b20250821.dist-info → autogluon.timeseries-1.4.1b20250823.dist-info}/LICENSE +0 -0
- {autogluon.timeseries-1.4.1b20250821.dist-info → autogluon.timeseries-1.4.1b20250823.dist-info}/NOTICE +0 -0
- {autogluon.timeseries-1.4.1b20250821.dist-info → autogluon.timeseries-1.4.1b20250823.dist-info}/WHEEL +0 -0
- {autogluon.timeseries-1.4.1b20250821.dist-info → autogluon.timeseries-1.4.1b20250823.dist-info}/namespace_packages.txt +0 -0
- {autogluon.timeseries-1.4.1b20250821.dist-info → autogluon.timeseries-1.4.1b20250823.dist-info}/top_level.txt +0 -0
- {autogluon.timeseries-1.4.1b20250821.dist-info → autogluon.timeseries-1.4.1b20250823.dist-info}/zip-safe +0 -0
@@ -4,7 +4,7 @@ import re
|
|
4
4
|
import time
|
5
5
|
from itertools import chain, cycle
|
6
6
|
from pathlib import Path
|
7
|
-
from typing import TYPE_CHECKING, Callable, Iterable, Iterator,
|
7
|
+
from typing import TYPE_CHECKING, Callable, Iterable, Iterator, Literal, Optional
|
8
8
|
|
9
9
|
import numpy as np
|
10
10
|
import torch
|
@@ -73,19 +73,19 @@ class ChronosFineTuningDataset(IterableDataset):
|
|
73
73
|
|
74
74
|
Parameters
|
75
75
|
----------
|
76
|
-
target_df
|
76
|
+
target_df
|
77
77
|
The ``TimeSeriesDataFrame`` to be converted
|
78
|
-
target_column
|
78
|
+
target_column
|
79
79
|
The name of the column which contains the target time series, by default "target"
|
80
|
-
context_length
|
80
|
+
context_length
|
81
81
|
The length of the historical context
|
82
|
-
prediction_length
|
82
|
+
prediction_length
|
83
83
|
The prediction_length, i.e., length of label or target
|
84
|
-
tokenizer
|
84
|
+
tokenizer
|
85
85
|
When a ``ChronosTokenizer`` object is provided, data will be converted into the
|
86
86
|
HuggingFace format accepted by the original Chronos models using this ``ChronosTokenizer``.
|
87
87
|
If None, data will be converted into the format accepted by ChronosBolt models.
|
88
|
-
mode
|
88
|
+
mode
|
89
89
|
When ``training``, random slices from the time series will be returned for training purposes.
|
90
90
|
If ``validation``, the last slice of each time series returned in the original order.
|
91
91
|
"""
|
@@ -145,7 +145,7 @@ class ChronosFineTuningDataset(IterableDataset):
|
|
145
145
|
|
146
146
|
Parameters
|
147
147
|
----------
|
148
|
-
entry
|
148
|
+
entry
|
149
149
|
time series data entry in GluonTS format with ``past_target`` and ``future_target`` keys
|
150
150
|
|
151
151
|
Returns
|
@@ -172,7 +172,7 @@ class ChronosFineTuningDataset(IterableDataset):
|
|
172
172
|
|
173
173
|
Parameters
|
174
174
|
----------
|
175
|
-
entry
|
175
|
+
entry
|
176
176
|
time series data entry in GluonTS format with ``past_target`` and ``future_target`` keys
|
177
177
|
|
178
178
|
Returns
|
@@ -200,7 +200,7 @@ class ChronosFineTuningDataset(IterableDataset):
|
|
200
200
|
|
201
201
|
Parameters
|
202
202
|
----------
|
203
|
-
shuffle_buffer_size
|
203
|
+
shuffle_buffer_size
|
204
204
|
The shuffle buffer size used for pseudo shuffling
|
205
205
|
"""
|
206
206
|
assert shuffle_buffer_size is None or shuffle_buffer_size >= 0
|
@@ -209,7 +209,7 @@ class ChronosFineTuningDataset(IterableDataset):
|
|
209
209
|
return PseudoShuffledIterableDataset(self, shuffle_buffer_size)
|
210
210
|
|
211
211
|
|
212
|
-
def left_pad_and_stack_1D(tensors:
|
212
|
+
def left_pad_and_stack_1D(tensors: list[torch.Tensor]) -> torch.Tensor:
|
213
213
|
max_len = max(len(c) for c in tensors)
|
214
214
|
padded = []
|
215
215
|
for c in tensors:
|
@@ -303,7 +303,7 @@ class TimeLimitCallback(TrainerCallback):
|
|
303
303
|
|
304
304
|
Parameters
|
305
305
|
----------
|
306
|
-
time_limit
|
306
|
+
time_limit
|
307
307
|
maximum time allowed for training in seconds.
|
308
308
|
"""
|
309
309
|
self.time_limit = time_limit
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import functools
|
2
2
|
import logging
|
3
3
|
from abc import ABC, abstractmethod
|
4
|
-
from typing import
|
4
|
+
from typing import Optional
|
5
5
|
|
6
6
|
import numpy as np
|
7
7
|
from typing_extensions import final
|
@@ -18,32 +18,32 @@ class AbstractTimeSeriesEnsembleModel(TimeSeriesModelBase, ABC):
|
|
18
18
|
|
19
19
|
@property
|
20
20
|
@abstractmethod
|
21
|
-
def model_names(self) ->
|
21
|
+
def model_names(self) -> list[str]:
|
22
22
|
"""Names of base models included in the ensemble."""
|
23
23
|
pass
|
24
24
|
|
25
25
|
@final
|
26
26
|
def fit(
|
27
27
|
self,
|
28
|
-
predictions_per_window:
|
29
|
-
data_per_window:
|
30
|
-
model_scores: Optional[
|
28
|
+
predictions_per_window: dict[str, list[TimeSeriesDataFrame]],
|
29
|
+
data_per_window: list[TimeSeriesDataFrame],
|
30
|
+
model_scores: Optional[dict[str, float]] = None,
|
31
31
|
time_limit: Optional[float] = None,
|
32
32
|
):
|
33
33
|
"""Fit ensemble model given predictions of candidate base models and the true data.
|
34
34
|
|
35
35
|
Parameters
|
36
36
|
----------
|
37
|
-
predictions_per_window
|
37
|
+
predictions_per_window
|
38
38
|
Dictionary that maps the names of component models to their respective predictions for each validation
|
39
39
|
window.
|
40
|
-
data_per_window
|
40
|
+
data_per_window
|
41
41
|
Observed ground truth data used to train the ensemble for each validation window. Each entry in the list
|
42
42
|
includes both the forecast horizon (for which the predictions are given in ``predictions``), as well as the
|
43
43
|
"history".
|
44
|
-
model_scores
|
44
|
+
model_scores
|
45
45
|
Scores (higher is better) for the models that will constitute the ensemble.
|
46
|
-
time_limit
|
46
|
+
time_limit
|
47
47
|
Maximum allowed time for training in seconds.
|
48
48
|
"""
|
49
49
|
if time_limit is not None and time_limit <= 0:
|
@@ -67,9 +67,9 @@ class AbstractTimeSeriesEnsembleModel(TimeSeriesModelBase, ABC):
|
|
67
67
|
|
68
68
|
def _fit(
|
69
69
|
self,
|
70
|
-
predictions_per_window:
|
71
|
-
data_per_window:
|
72
|
-
model_scores: Optional[
|
70
|
+
predictions_per_window: dict[str, list[TimeSeriesDataFrame]],
|
71
|
+
data_per_window: list[TimeSeriesDataFrame],
|
72
|
+
model_scores: Optional[dict[str, float]] = None,
|
73
73
|
time_limit: Optional[float] = None,
|
74
74
|
):
|
75
75
|
"""Private method for `fit`. See `fit` for documentation of arguments. Apart from the model
|
@@ -78,7 +78,7 @@ class AbstractTimeSeriesEnsembleModel(TimeSeriesModelBase, ABC):
|
|
78
78
|
raise NotImplementedError
|
79
79
|
|
80
80
|
@final
|
81
|
-
def predict(self, data:
|
81
|
+
def predict(self, data: dict[str, TimeSeriesDataFrame], **kwargs) -> TimeSeriesDataFrame:
|
82
82
|
if not set(self.model_names).issubset(set(data.keys())):
|
83
83
|
raise ValueError(
|
84
84
|
f"Set of models given for prediction in {self.name} differ from those provided during initialization."
|
@@ -93,11 +93,11 @@ class AbstractTimeSeriesEnsembleModel(TimeSeriesModelBase, ABC):
|
|
93
93
|
return self._predict(data=data, **kwargs)
|
94
94
|
|
95
95
|
@abstractmethod
|
96
|
-
def _predict(self, data:
|
96
|
+
def _predict(self, data: dict[str, TimeSeriesDataFrame], **kwargs) -> TimeSeriesDataFrame:
|
97
97
|
pass
|
98
98
|
|
99
99
|
@abstractmethod
|
100
|
-
def remap_base_models(self, model_refit_map:
|
100
|
+
def remap_base_models(self, model_refit_map: dict[str, str]) -> None:
|
101
101
|
"""Update names of the base models based on the mapping in model_refit_map.
|
102
102
|
|
103
103
|
This method should be called after performing refit_full to point to the refitted base models, if necessary.
|
@@ -112,17 +112,17 @@ class AbstractWeightedTimeSeriesEnsembleModel(AbstractTimeSeriesEnsembleModel, A
|
|
112
112
|
if name is None:
|
113
113
|
name = "WeightedEnsemble"
|
114
114
|
super().__init__(name=name, **kwargs)
|
115
|
-
self.model_to_weight:
|
115
|
+
self.model_to_weight: dict[str, float] = {}
|
116
116
|
|
117
117
|
@property
|
118
|
-
def model_names(self) ->
|
118
|
+
def model_names(self) -> list[str]:
|
119
119
|
return list(self.model_to_weight.keys())
|
120
120
|
|
121
121
|
@property
|
122
122
|
def model_weights(self) -> np.ndarray:
|
123
123
|
return np.array(list(self.model_to_weight.values()), dtype=np.float64)
|
124
124
|
|
125
|
-
def _predict(self, data:
|
125
|
+
def _predict(self, data: dict[str, TimeSeriesDataFrame], **kwargs) -> TimeSeriesDataFrame:
|
126
126
|
weighted_predictions = [data[model_name] * weight for model_name, weight in self.model_to_weight.items()]
|
127
127
|
return functools.reduce(lambda x, y: x + y, weighted_predictions)
|
128
128
|
|
@@ -131,7 +131,7 @@ class AbstractWeightedTimeSeriesEnsembleModel(AbstractTimeSeriesEnsembleModel, A
|
|
131
131
|
info["model_weights"] = self.model_to_weight.copy()
|
132
132
|
return info
|
133
133
|
|
134
|
-
def remap_base_models(self, model_refit_map:
|
134
|
+
def remap_base_models(self, model_refit_map: dict[str, str]) -> None:
|
135
135
|
updated_weights = {}
|
136
136
|
for model, weight in self.model_to_weight.items():
|
137
137
|
model_full_name = model_refit_map.get(model, model)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import
|
1
|
+
from typing import Any, Optional
|
2
2
|
|
3
3
|
import numpy as np
|
4
4
|
|
@@ -17,9 +17,9 @@ class SimpleAverageEnsemble(AbstractWeightedTimeSeriesEnsembleModel):
|
|
17
17
|
|
18
18
|
def _fit(
|
19
19
|
self,
|
20
|
-
predictions_per_window:
|
21
|
-
data_per_window:
|
22
|
-
model_scores: Optional[
|
20
|
+
predictions_per_window: dict[str, list[TimeSeriesDataFrame]],
|
21
|
+
data_per_window: list[TimeSeriesDataFrame],
|
22
|
+
model_scores: Optional[dict[str, float]] = None,
|
23
23
|
time_limit: Optional[float] = None,
|
24
24
|
):
|
25
25
|
self.model_to_weight = {}
|
@@ -52,14 +52,14 @@ class PerformanceWeightedEnsemble(AbstractWeightedTimeSeriesEnsembleModel):
|
|
52
52
|
name = "PerformanceWeightedEnsemble"
|
53
53
|
super().__init__(name=name, **kwargs)
|
54
54
|
|
55
|
-
def _get_default_hyperparameters(self) ->
|
55
|
+
def _get_default_hyperparameters(self) -> dict[str, Any]:
|
56
56
|
return {"weight_scheme": "sqrt"}
|
57
57
|
|
58
58
|
def _fit(
|
59
59
|
self,
|
60
|
-
predictions_per_window:
|
61
|
-
data_per_window:
|
62
|
-
model_scores: Optional[
|
60
|
+
predictions_per_window: dict[str, list[TimeSeriesDataFrame]],
|
61
|
+
data_per_window: list[TimeSeriesDataFrame],
|
62
|
+
model_scores: Optional[dict[str, float]] = None,
|
63
63
|
time_limit: Optional[float] = None,
|
64
64
|
):
|
65
65
|
assert model_scores is not None
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import copy
|
2
2
|
import logging
|
3
3
|
import pprint
|
4
|
-
from typing import
|
4
|
+
from typing import Any, Optional
|
5
5
|
|
6
6
|
import numpy as np
|
7
7
|
|
@@ -47,14 +47,14 @@ class TimeSeriesEnsembleSelection(EnsembleSelection):
|
|
47
47
|
self.dummy_pred_per_window = []
|
48
48
|
self.scorer_per_window = []
|
49
49
|
|
50
|
-
self.dummy_pred_per_window: Optional[
|
51
|
-
self.scorer_per_window: Optional[
|
52
|
-
self.data_future_per_window: Optional[
|
50
|
+
self.dummy_pred_per_window: Optional[list[TimeSeriesDataFrame]]
|
51
|
+
self.scorer_per_window: Optional[list[TimeSeriesScorer]]
|
52
|
+
self.data_future_per_window: Optional[list[TimeSeriesDataFrame]]
|
53
53
|
|
54
54
|
def fit( # type: ignore
|
55
55
|
self,
|
56
|
-
predictions:
|
57
|
-
labels:
|
56
|
+
predictions: list[list[TimeSeriesDataFrame]],
|
57
|
+
labels: list[TimeSeriesDataFrame],
|
58
58
|
time_limit: Optional[float] = None,
|
59
59
|
):
|
60
60
|
return super().fit(
|
@@ -65,10 +65,10 @@ class TimeSeriesEnsembleSelection(EnsembleSelection):
|
|
65
65
|
|
66
66
|
def _fit( # type: ignore
|
67
67
|
self,
|
68
|
-
predictions:
|
69
|
-
labels:
|
68
|
+
predictions: list[list[TimeSeriesDataFrame]],
|
69
|
+
labels: list[TimeSeriesDataFrame],
|
70
70
|
time_limit: Optional[float] = None,
|
71
|
-
sample_weight: Optional[
|
71
|
+
sample_weight: Optional[list[float]] = None,
|
72
72
|
):
|
73
73
|
# Stack predictions for each model into a 3d tensor of shape [num_val_windows, num_rows, num_cols]
|
74
74
|
stacked_predictions = [np.stack(preds) for preds in predictions]
|
@@ -157,14 +157,14 @@ class GreedyEnsemble(AbstractWeightedTimeSeriesEnsembleModel):
|
|
157
157
|
name = "WeightedEnsemble"
|
158
158
|
super().__init__(name=name, **kwargs)
|
159
159
|
|
160
|
-
def _get_default_hyperparameters(self) ->
|
160
|
+
def _get_default_hyperparameters(self) -> dict[str, Any]:
|
161
161
|
return {"ensemble_size": 100}
|
162
162
|
|
163
163
|
def _fit(
|
164
164
|
self,
|
165
|
-
predictions_per_window:
|
166
|
-
data_per_window:
|
167
|
-
model_scores: Optional[
|
165
|
+
predictions_per_window: dict[str, list[TimeSeriesDataFrame]],
|
166
|
+
data_per_window: list[TimeSeriesDataFrame],
|
167
|
+
model_scores: Optional[dict[str, float]] = None,
|
168
168
|
time_limit: Optional[float] = None,
|
169
169
|
):
|
170
170
|
ensemble_selection = TimeSeriesEnsembleSelection(
|
@@ -3,7 +3,7 @@ import os
|
|
3
3
|
import shutil
|
4
4
|
from datetime import timedelta
|
5
5
|
from pathlib import Path
|
6
|
-
from typing import TYPE_CHECKING, Any, Callable,
|
6
|
+
from typing import TYPE_CHECKING, Any, Callable, Optional, Type, Union, cast, overload
|
7
7
|
|
8
8
|
import gluonts
|
9
9
|
import gluonts.core.settings
|
@@ -42,20 +42,20 @@ class AbstractGluonTSModel(AbstractTimeSeriesModel):
|
|
42
42
|
|
43
43
|
Parameters
|
44
44
|
----------
|
45
|
-
path
|
45
|
+
path
|
46
46
|
directory to store model artifacts.
|
47
|
-
freq
|
47
|
+
freq
|
48
48
|
string representation (compatible with GluonTS frequency strings) for the data provided.
|
49
49
|
For example, "1D" for daily data, "1H" for hourly data, etc.
|
50
|
-
prediction_length
|
50
|
+
prediction_length
|
51
51
|
Number of time steps ahead (length of the forecast horizon) the model will be optimized
|
52
52
|
to predict. At inference time, this will be the number of time steps the model will
|
53
53
|
predict.
|
54
|
-
name
|
54
|
+
name
|
55
55
|
Name of the model. Also, name of subdirectory inside path where model will be saved.
|
56
|
-
eval_metric
|
56
|
+
eval_metric
|
57
57
|
objective function the model intends to optimize, will use WQL by default.
|
58
|
-
hyperparameters
|
58
|
+
hyperparameters
|
59
59
|
various hyperparameters that will be used by model (can be search spaces instead of
|
60
60
|
fixed values). See *Other Parameters* in each inheriting model's documentation for
|
61
61
|
possible values.
|
@@ -77,7 +77,7 @@ class AbstractGluonTSModel(AbstractTimeSeriesModel):
|
|
77
77
|
path: Optional[str] = None,
|
78
78
|
name: Optional[str] = None,
|
79
79
|
eval_metric: Optional[str] = None,
|
80
|
-
hyperparameters: Optional[
|
80
|
+
hyperparameters: Optional[dict[str, Any]] = None,
|
81
81
|
**kwargs, # noqa
|
82
82
|
):
|
83
83
|
super().__init__(
|
@@ -100,9 +100,9 @@ class AbstractGluonTSModel(AbstractTimeSeriesModel):
|
|
100
100
|
self.num_feat_dynamic_real = 0
|
101
101
|
self.num_past_feat_dynamic_cat = 0
|
102
102
|
self.num_past_feat_dynamic_real = 0
|
103
|
-
self.feat_static_cat_cardinality:
|
104
|
-
self.feat_dynamic_cat_cardinality:
|
105
|
-
self.past_feat_dynamic_cat_cardinality:
|
103
|
+
self.feat_static_cat_cardinality: list[int] = []
|
104
|
+
self.feat_dynamic_cat_cardinality: list[int] = []
|
105
|
+
self.past_feat_dynamic_cat_cardinality: list[int] = []
|
106
106
|
self.negative_data = True
|
107
107
|
|
108
108
|
def save(self, path: Optional[str] = None, verbose: bool = True) -> str:
|
@@ -234,7 +234,7 @@ class AbstractGluonTSModel(AbstractTimeSeriesModel):
|
|
234
234
|
|
235
235
|
return self._get_default_hyperparameters() | init_args
|
236
236
|
|
237
|
-
def _get_estimator_init_args(self) ->
|
237
|
+
def _get_estimator_init_args(self) -> dict[str, Any]:
|
238
238
|
"""Get GluonTS specific constructor arguments for estimator objects, an alias to `self.get_hyperparameters`
|
239
239
|
for better readability."""
|
240
240
|
return self.get_hyperparameters()
|
@@ -277,8 +277,8 @@ class AbstractGluonTSModel(AbstractTimeSeriesModel):
|
|
277
277
|
|
278
278
|
return torch.cuda.is_available()
|
279
279
|
|
280
|
-
def get_minimum_resources(self, is_gpu_available: bool = False) ->
|
281
|
-
minimum_resources:
|
280
|
+
def get_minimum_resources(self, is_gpu_available: bool = False) -> dict[str, Union[int, float]]:
|
281
|
+
minimum_resources: dict[str, Union[int, float]] = {"num_cpus": 1}
|
282
282
|
# if GPU is available, we train with 1 GPU per trial
|
283
283
|
if is_gpu_available:
|
284
284
|
minimum_resources["num_gpus"] = 1
|
@@ -440,7 +440,7 @@ class AbstractGluonTSModel(AbstractTimeSeriesModel):
|
|
440
440
|
self,
|
441
441
|
time_limit: Optional[float],
|
442
442
|
early_stopping_patience: Optional[int] = None,
|
443
|
-
) ->
|
443
|
+
) -> list[Callable]:
|
444
444
|
"""Retrieve a list of callback objects for the GluonTS trainer"""
|
445
445
|
from lightning.pytorch.callbacks import EarlyStopping, Timer
|
446
446
|
|
@@ -473,7 +473,7 @@ class AbstractGluonTSModel(AbstractTimeSeriesModel):
|
|
473
473
|
data: TimeSeriesDataFrame,
|
474
474
|
known_covariates: Optional[TimeSeriesDataFrame] = None,
|
475
475
|
num_samples: Optional[int] = None,
|
476
|
-
) ->
|
476
|
+
) -> list[Forecast]:
|
477
477
|
assert self.gts_predictor is not None, "GluonTS models must be fit before predicting."
|
478
478
|
gts_data = self._to_gluonts_dataset(data, known_covariates=known_covariates)
|
479
479
|
return list(
|
@@ -483,7 +483,7 @@ class AbstractGluonTSModel(AbstractTimeSeriesModel):
|
|
483
483
|
)
|
484
484
|
)
|
485
485
|
|
486
|
-
def _stack_quantile_forecasts(self, forecasts:
|
486
|
+
def _stack_quantile_forecasts(self, forecasts: list[QuantileForecast], item_ids: pd.Index) -> pd.DataFrame:
|
487
487
|
# GluonTS always saves item_id as a string
|
488
488
|
item_id_to_forecast = {str(f.item_id): f for f in forecasts}
|
489
489
|
result_dfs = []
|
@@ -496,7 +496,7 @@ class AbstractGluonTSModel(AbstractTimeSeriesModel):
|
|
496
496
|
columns_order = ["mean"] + [str(q) for q in self.quantile_levels]
|
497
497
|
return forecast_df[columns_order]
|
498
498
|
|
499
|
-
def _stack_sample_forecasts(self, forecasts:
|
499
|
+
def _stack_sample_forecasts(self, forecasts: list[SampleForecast], item_ids: pd.Index) -> pd.DataFrame:
|
500
500
|
item_id_to_forecast = {str(f.item_id): f for f in forecasts}
|
501
501
|
samples_per_item = []
|
502
502
|
for item_id in item_ids:
|
@@ -509,7 +509,7 @@ class AbstractGluonTSModel(AbstractTimeSeriesModel):
|
|
509
509
|
return pd.DataFrame(forecast_array, columns=["mean"] + [str(q) for q in self.quantile_levels])
|
510
510
|
|
511
511
|
def _stack_distribution_forecasts(
|
512
|
-
self, forecasts:
|
512
|
+
self, forecasts: list["DistributionForecast"], item_ids: pd.Index
|
513
513
|
) -> pd.DataFrame:
|
514
514
|
import torch
|
515
515
|
from gluonts.torch.distributions import AffineTransformed
|
@@ -523,7 +523,7 @@ class AbstractGluonTSModel(AbstractTimeSeriesModel):
|
|
523
523
|
"Expected forecast.distribution to be an instance of AffineTransformed"
|
524
524
|
)
|
525
525
|
|
526
|
-
def stack_distributions(distributions:
|
526
|
+
def stack_distributions(distributions: list[Distribution]) -> Distribution:
|
527
527
|
"""Stack multiple torch.Distribution objects into a single distribution"""
|
528
528
|
last_dist: Distribution = distributions[-1]
|
529
529
|
|
@@ -561,18 +561,18 @@ class AbstractGluonTSModel(AbstractTimeSeriesModel):
|
|
561
561
|
|
562
562
|
def _gluonts_forecasts_to_data_frame(
|
563
563
|
self,
|
564
|
-
forecasts:
|
564
|
+
forecasts: list[Forecast],
|
565
565
|
forecast_index: pd.MultiIndex,
|
566
566
|
) -> TimeSeriesDataFrame:
|
567
567
|
from gluonts.torch.model.forecast import DistributionForecast
|
568
568
|
|
569
569
|
item_ids = forecast_index.unique(level=ITEMID)
|
570
570
|
if isinstance(forecasts[0], SampleForecast):
|
571
|
-
forecast_df = self._stack_sample_forecasts(cast(
|
571
|
+
forecast_df = self._stack_sample_forecasts(cast(list[SampleForecast], forecasts), item_ids)
|
572
572
|
elif isinstance(forecasts[0], QuantileForecast):
|
573
|
-
forecast_df = self._stack_quantile_forecasts(cast(
|
573
|
+
forecast_df = self._stack_quantile_forecasts(cast(list[QuantileForecast], forecasts), item_ids)
|
574
574
|
elif isinstance(forecasts[0], DistributionForecast):
|
575
|
-
forecast_df = self._stack_distribution_forecasts(cast(
|
575
|
+
forecast_df = self._stack_distribution_forecasts(cast(list[DistributionForecast], forecasts), item_ids)
|
576
576
|
else:
|
577
577
|
raise ValueError(f"Unrecognized forecast type {type(forecasts[0])}")
|
578
578
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import Any,
|
1
|
+
from typing import Any, Iterator, Optional, Type
|
2
2
|
|
3
3
|
import numpy as np
|
4
4
|
import pandas as pd
|
@@ -76,7 +76,7 @@ class SimpleGluonTSDataset(GluonTSDataset):
|
|
76
76
|
def __len__(self):
|
77
77
|
return len(self.indptr) - 1 # noqa
|
78
78
|
|
79
|
-
def __iter__(self) -> Iterator[
|
79
|
+
def __iter__(self) -> Iterator[dict[str, Any]]:
|
80
80
|
for j in range(len(self.indptr) - 1):
|
81
81
|
start_idx = self.indptr[j]
|
82
82
|
end_idx = self.indptr[j + 1]
|
@@ -3,7 +3,7 @@ Module including wrappers for PyTorch implementations of models in GluonTS
|
|
3
3
|
"""
|
4
4
|
|
5
5
|
import logging
|
6
|
-
from typing import Any,
|
6
|
+
from typing import Any, Type
|
7
7
|
|
8
8
|
from gluonts.model.estimator import Estimator as GluonTSEstimator
|
9
9
|
|
@@ -91,7 +91,7 @@ class DeepARModel(AbstractGluonTSModel):
|
|
91
91
|
|
92
92
|
return DeepAREstimator
|
93
93
|
|
94
|
-
def _get_estimator_init_args(self) ->
|
94
|
+
def _get_estimator_init_args(self) -> dict[str, Any]:
|
95
95
|
init_kwargs = super()._get_estimator_init_args()
|
96
96
|
init_kwargs["num_feat_static_cat"] = self.num_feat_static_cat
|
97
97
|
init_kwargs["num_feat_static_real"] = self.num_feat_static_real
|
@@ -113,7 +113,7 @@ class SimpleFeedForwardModel(AbstractGluonTSModel):
|
|
113
113
|
----------------
|
114
114
|
context_length : int, default = max(10, 2 * prediction_length)
|
115
115
|
Number of time units that condition the predictions
|
116
|
-
hidden_dimensions:
|
116
|
+
hidden_dimensions: list[int], default = [20, 20]
|
117
117
|
Size of hidden layers in the feedforward network
|
118
118
|
distr_output : gluonts.torch.distributions.Output, default = StudentTOutput()
|
119
119
|
Distribution output object that defines how the model output is converted to a forecast, and how the loss is computed.
|
@@ -221,7 +221,7 @@ class TemporalFusionTransformerModel(AbstractGluonTSModel):
|
|
221
221
|
"context_length": min(512, max(64, 2 * self.prediction_length)),
|
222
222
|
}
|
223
223
|
|
224
|
-
def _get_estimator_init_args(self) ->
|
224
|
+
def _get_estimator_init_args(self) -> dict[str, Any]:
|
225
225
|
init_kwargs = super()._get_estimator_init_args()
|
226
226
|
if self.num_feat_dynamic_real > 0:
|
227
227
|
init_kwargs["dynamic_dims"] = [self.num_feat_dynamic_real]
|
@@ -361,7 +361,7 @@ class PatchTSTModel(AbstractGluonTSModel):
|
|
361
361
|
def _get_default_hyperparameters(self):
|
362
362
|
return super()._get_default_hyperparameters() | {"context_length": 96, "patch_len": 16}
|
363
363
|
|
364
|
-
def _get_estimator_init_args(self) ->
|
364
|
+
def _get_estimator_init_args(self) -> dict[str, Any]:
|
365
365
|
init_kwargs = super()._get_estimator_init_args()
|
366
366
|
init_kwargs["num_feat_dynamic_real"] = self.num_feat_dynamic_real
|
367
367
|
return init_kwargs
|
@@ -438,7 +438,7 @@ class WaveNetModel(AbstractGluonTSModel):
|
|
438
438
|
|
439
439
|
return WaveNetEstimator
|
440
440
|
|
441
|
-
def _get_estimator_init_args(self) ->
|
441
|
+
def _get_estimator_init_args(self) -> dict[str, Any]:
|
442
442
|
init_kwargs = super()._get_estimator_init_args()
|
443
443
|
init_kwargs["num_feat_static_cat"] = self.num_feat_static_cat
|
444
444
|
init_kwargs["num_feat_static_real"] = self.num_feat_static_real
|
@@ -547,7 +547,7 @@ class TiDEModel(AbstractGluonTSModel):
|
|
547
547
|
"batch_size": 256,
|
548
548
|
}
|
549
549
|
|
550
|
-
def _get_estimator_init_args(self) ->
|
550
|
+
def _get_estimator_init_args(self) -> dict[str, Any]:
|
551
551
|
init_kwargs = super()._get_estimator_init_args()
|
552
552
|
init_kwargs["num_feat_static_cat"] = self.num_feat_static_cat
|
553
553
|
init_kwargs["num_feat_static_real"] = self.num_feat_static_real
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import logging
|
2
2
|
import time
|
3
3
|
from multiprocessing import TimeoutError
|
4
|
-
from typing import Any, Callable,
|
4
|
+
from typing import Any, Callable, Optional, Union
|
5
5
|
|
6
6
|
import numpy as np
|
7
7
|
import pandas as pd
|
@@ -29,17 +29,17 @@ class AbstractLocalModel(AbstractTimeSeriesModel):
|
|
29
29
|
|
30
30
|
Attributes
|
31
31
|
----------
|
32
|
-
allowed_local_model_args
|
32
|
+
allowed_local_model_args
|
33
33
|
Argument that can be passed to the underlying local model.
|
34
|
-
default_max_ts_length
|
34
|
+
default_max_ts_length
|
35
35
|
If not None, only the last ``max_ts_length`` time steps of each time series will be used to train the model.
|
36
36
|
This significantly speeds up fitting and usually leads to no change in accuracy.
|
37
|
-
init_time_in_seconds
|
37
|
+
init_time_in_seconds
|
38
38
|
Time that it takes to initialize the model in seconds (e.g., because of JIT compilation by Numba).
|
39
39
|
If time_limit is below this number, model won't be trained.
|
40
40
|
"""
|
41
41
|
|
42
|
-
allowed_local_model_args:
|
42
|
+
allowed_local_model_args: list[str] = []
|
43
43
|
default_max_ts_length: Optional[int] = 2500
|
44
44
|
default_max_time_limit_ratio = 1.0
|
45
45
|
init_time_in_seconds: int = 0
|
@@ -51,7 +51,7 @@ class AbstractLocalModel(AbstractTimeSeriesModel):
|
|
51
51
|
path: Optional[str] = None,
|
52
52
|
name: Optional[str] = None,
|
53
53
|
eval_metric: Union[str, TimeSeriesScorer, None] = None,
|
54
|
-
hyperparameters: Optional[
|
54
|
+
hyperparameters: Optional[dict[str, Any]] = None,
|
55
55
|
**kwargs, # noqa
|
56
56
|
):
|
57
57
|
super().__init__(
|
@@ -64,12 +64,12 @@ class AbstractLocalModel(AbstractTimeSeriesModel):
|
|
64
64
|
**kwargs,
|
65
65
|
)
|
66
66
|
|
67
|
-
self._local_model_args:
|
67
|
+
self._local_model_args: dict[str, Any]
|
68
68
|
self._seasonal_period: int
|
69
69
|
self._dummy_forecast: pd.DataFrame
|
70
70
|
|
71
71
|
@property
|
72
|
-
def allowed_hyperparameters(self) ->
|
72
|
+
def allowed_hyperparameters(self) -> list[str]:
|
73
73
|
return (
|
74
74
|
super().allowed_hyperparameters
|
75
75
|
+ ["use_fallback_model", "max_ts_length", "n_jobs"]
|
@@ -82,7 +82,7 @@ class AbstractLocalModel(AbstractTimeSeriesModel):
|
|
82
82
|
known_covariates: Optional[TimeSeriesDataFrame] = None,
|
83
83
|
is_train: bool = False,
|
84
84
|
**kwargs,
|
85
|
-
) ->
|
85
|
+
) -> tuple[TimeSeriesDataFrame, Optional[TimeSeriesDataFrame]]:
|
86
86
|
if not self._get_tags()["allow_nan"]:
|
87
87
|
data = data.fill_missing_values()
|
88
88
|
return data, known_covariates
|
@@ -134,7 +134,7 @@ class AbstractLocalModel(AbstractTimeSeriesModel):
|
|
134
134
|
stats_repeated = np.tile(stats_marginal.values, [self.prediction_length, 1])
|
135
135
|
return pd.DataFrame(stats_repeated, columns=stats_marginal.index)
|
136
136
|
|
137
|
-
def _update_local_model_args(self, local_model_args:
|
137
|
+
def _update_local_model_args(self, local_model_args: dict[str, Any]) -> dict[str, Any]:
|
138
138
|
return local_model_args
|
139
139
|
|
140
140
|
def _predict(self, data: TimeSeriesDataFrame, **kwargs) -> TimeSeriesDataFrame:
|
@@ -185,7 +185,7 @@ class AbstractLocalModel(AbstractTimeSeriesModel):
|
|
185
185
|
time_series: pd.Series,
|
186
186
|
use_fallback_model: bool,
|
187
187
|
end_time: Optional[float] = None,
|
188
|
-
) ->
|
188
|
+
) -> tuple[pd.DataFrame, bool]:
|
189
189
|
if end_time is not None and time.time() >= end_time:
|
190
190
|
raise TimeLimitExceeded
|
191
191
|
|
@@ -222,7 +222,7 @@ class AbstractLocalModel(AbstractTimeSeriesModel):
|
|
222
222
|
|
223
223
|
|
224
224
|
def seasonal_naive_forecast(
|
225
|
-
target: np.ndarray, prediction_length: int, quantile_levels:
|
225
|
+
target: np.ndarray, prediction_length: int, quantile_levels: list[float], seasonal_period: int
|
226
226
|
) -> pd.DataFrame:
|
227
227
|
"""Generate seasonal naive forecast, predicting the last observed value from the same period."""
|
228
228
|
|