autogluon.timeseries 1.2.1b20250115__py3-none-any.whl → 1.2.1b20250130__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.
- autogluon/timeseries/dataset/ts_dataframe.py +22 -56
- autogluon/timeseries/learner.py +14 -27
- autogluon/timeseries/models/abstract/abstract_timeseries_model.py +25 -7
- autogluon/timeseries/models/autogluon_tabular/mlforecast.py +5 -9
- autogluon/timeseries/models/chronos/model.py +1 -2
- autogluon/timeseries/models/chronos/pipeline/utils.py +0 -1
- autogluon/timeseries/models/gluonts/abstract_gluonts.py +8 -3
- autogluon/timeseries/models/gluonts/torch/models.py +11 -14
- autogluon/timeseries/models/local/abstract_local_model.py +2 -3
- autogluon/timeseries/models/local/statsforecast.py +1 -1
- autogluon/timeseries/models/multi_window/multi_window_model.py +11 -7
- autogluon/timeseries/models/presets.py +1 -1
- autogluon/timeseries/predictor.py +49 -69
- autogluon/timeseries/regressor.py +41 -18
- autogluon/timeseries/{trainer/abstract_trainer.py → trainer.py} +122 -243
- autogluon/timeseries/transforms/covariate_scaler.py +13 -2
- autogluon/timeseries/transforms/target_scaler.py +1 -1
- autogluon/timeseries/utils/forecast.py +2 -1
- autogluon/timeseries/version.py +2 -1
- {autogluon.timeseries-1.2.1b20250115.dist-info → autogluon.timeseries-1.2.1b20250130.dist-info}/METADATA +6 -4
- {autogluon.timeseries-1.2.1b20250115.dist-info → autogluon.timeseries-1.2.1b20250130.dist-info}/RECORD +28 -30
- autogluon/timeseries/trainer/__init__.py +0 -4
- autogluon/timeseries/trainer/auto_trainer.py +0 -77
- /autogluon.timeseries-1.2.1b20250115-py3.8-nspkg.pth → /autogluon.timeseries-1.2.1b20250130-py3.9-nspkg.pth +0 -0
- {autogluon.timeseries-1.2.1b20250115.dist-info → autogluon.timeseries-1.2.1b20250130.dist-info}/LICENSE +0 -0
- {autogluon.timeseries-1.2.1b20250115.dist-info → autogluon.timeseries-1.2.1b20250130.dist-info}/NOTICE +0 -0
- {autogluon.timeseries-1.2.1b20250115.dist-info → autogluon.timeseries-1.2.1b20250130.dist-info}/WHEEL +0 -0
- {autogluon.timeseries-1.2.1b20250115.dist-info → autogluon.timeseries-1.2.1b20250130.dist-info}/namespace_packages.txt +0 -0
- {autogluon.timeseries-1.2.1b20250115.dist-info → autogluon.timeseries-1.2.1b20250130.dist-info}/top_level.txt +0 -0
- {autogluon.timeseries-1.2.1b20250115.dist-info → autogluon.timeseries-1.2.1b20250130.dist-info}/zip-safe +0 -0
@@ -24,23 +24,7 @@ TIMESTAMP = "timestamp"
|
|
24
24
|
IRREGULAR_TIME_INDEX_FREQSTR = "IRREG"
|
25
25
|
|
26
26
|
|
27
|
-
class
|
28
|
-
"""Contains deprecated methods from TimeSeriesDataFrame that shouldn't show up in API documentation."""
|
29
|
-
|
30
|
-
def get_reindexed_view(self, *args, **kwargs) -> TimeSeriesDataFrame:
|
31
|
-
raise ValueError(
|
32
|
-
"`TimeSeriesDataFrame.get_reindexed_view` has been deprecated. If your data has irregular timestamps, "
|
33
|
-
"please convert it to a regular frequency with `convert_frequency`."
|
34
|
-
)
|
35
|
-
|
36
|
-
def to_regular_index(self, *args, **kwargs) -> TimeSeriesDataFrame:
|
37
|
-
raise ValueError(
|
38
|
-
"`TimeSeriesDataFrame.to_regular_index` has been deprecated. "
|
39
|
-
"Please use `TimeSeriesDataFrame.convert_frequency` instead."
|
40
|
-
)
|
41
|
-
|
42
|
-
|
43
|
-
class TimeSeriesDataFrame(pd.DataFrame, TimeSeriesDataFrameDeprecatedMixin):
|
27
|
+
class TimeSeriesDataFrame(pd.DataFrame):
|
44
28
|
"""A collection of univariate time series, where each row is identified by an (``item_id``, ``timestamp``) pair.
|
45
29
|
|
46
30
|
For example, a time series data frame could represent the daily sales of a collection of products, where each
|
@@ -131,20 +115,10 @@ class TimeSeriesDataFrame(pd.DataFrame, TimeSeriesDataFrameDeprecatedMixin):
|
|
131
115
|
Number of CPU cores used to process the iterable dataset in parallel. Set to -1 to use all cores. This argument
|
132
116
|
is only used when constructing a TimeSeriesDataFrame using format 4 (iterable dataset).
|
133
117
|
|
134
|
-
Attributes
|
135
|
-
----------
|
136
|
-
freq : str
|
137
|
-
A pandas-compatible string describing the frequency of the time series. For example ``"D"`` for daily data,
|
138
|
-
``"h"`` for hourly data, etc. This attribute is determined automatically based on the timestamps. For the full
|
139
|
-
list of possible values, see `pandas documentation <https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#offset-aliases>`_.
|
140
|
-
num_items : int
|
141
|
-
Number of items (time series) in the data set.
|
142
|
-
item_ids : pd.Index
|
143
|
-
List of unique time series IDs contained in the data set.
|
144
118
|
"""
|
145
119
|
|
146
120
|
index: pd.MultiIndex
|
147
|
-
_metadata = ["_static_features"
|
121
|
+
_metadata = ["_static_features"]
|
148
122
|
|
149
123
|
def __init__(
|
150
124
|
self,
|
@@ -179,12 +153,6 @@ class TimeSeriesDataFrame(pd.DataFrame, TimeSeriesDataFrameDeprecatedMixin):
|
|
179
153
|
if static_features is not None:
|
180
154
|
self.static_features = self._construct_static_features(static_features, id_column=id_column)
|
181
155
|
|
182
|
-
# internal value for cached frequency values that are inferred. corresponds to either a
|
183
|
-
# pandas-compatible frequency string, the value IRREGULAR_TIME_INDEX_FREQSTR that signals
|
184
|
-
# the time series have irregular timestamps (in which case tsdf.freq returns None), or None
|
185
|
-
# if inference was not yet performed.
|
186
|
-
self._cached_freq: Optional[str] = None
|
187
|
-
|
188
156
|
@property
|
189
157
|
def _constructor(self) -> Type[TimeSeriesDataFrame]:
|
190
158
|
return TimeSeriesDataFrame
|
@@ -194,7 +162,6 @@ class TimeSeriesDataFrame(pd.DataFrame, TimeSeriesDataFrameDeprecatedMixin):
|
|
194
162
|
# repeatedly calling TimeSeriesDataFrame constructor
|
195
163
|
df = self._from_mgr(mgr, axes=axes)
|
196
164
|
df._static_features = self._static_features
|
197
|
-
df._cached_freq = self._cached_freq
|
198
165
|
return df
|
199
166
|
|
200
167
|
@classmethod
|
@@ -417,6 +384,7 @@ class TimeSeriesDataFrame(pd.DataFrame, TimeSeriesDataFrameDeprecatedMixin):
|
|
417
384
|
|
418
385
|
@property
|
419
386
|
def item_ids(self) -> pd.Index:
|
387
|
+
"""List of unique time series IDs contained in the data set."""
|
420
388
|
return self.index.unique(level=ITEMID)
|
421
389
|
|
422
390
|
@classmethod
|
@@ -478,12 +446,12 @@ class TimeSeriesDataFrame(pd.DataFrame, TimeSeriesDataFrameDeprecatedMixin):
|
|
478
446
|
|
479
447
|
self._static_features = value
|
480
448
|
|
481
|
-
def infer_frequency(self, num_items: Optional[int] =
|
449
|
+
def infer_frequency(self, num_items: Optional[int] = None, raise_if_irregular: bool = False) -> str:
|
482
450
|
"""Infer the time series frequency based on the timestamps of the observations.
|
483
451
|
|
484
452
|
Parameters
|
485
453
|
----------
|
486
|
-
num_items : int or None, default =
|
454
|
+
num_items : int or None, default = None
|
487
455
|
Number of items (individual time series) randomly selected to infer the frequency. Lower values speed up
|
488
456
|
the method, but increase the chance that some items with invalid frequency are missed by subsampling.
|
489
457
|
|
@@ -546,23 +514,24 @@ class TimeSeriesDataFrame(pd.DataFrame, TimeSeriesDataFrameDeprecatedMixin):
|
|
546
514
|
|
547
515
|
@property
|
548
516
|
def freq(self):
|
549
|
-
|
550
|
-
self._cached_freq = self.infer_frequency()
|
517
|
+
"""Inferred pandas-compatible frequency of the timestamps in the data frame.
|
551
518
|
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
519
|
+
Computed using a random subset of the time series for speed. This may sometimes result in incorrectly inferred
|
520
|
+
values. For reliable results, use :meth:`~autogluon.timeseries.TimeSeriesDataFrame.infer_frequency`.
|
521
|
+
"""
|
522
|
+
inferred_freq = self.infer_frequency(num_items=50)
|
523
|
+
return None if inferred_freq == IRREGULAR_TIME_INDEX_FREQSTR else inferred_freq
|
556
524
|
|
557
525
|
@property
|
558
526
|
def num_items(self):
|
527
|
+
"""Number of items (time series) in the data set."""
|
559
528
|
return len(self.item_ids)
|
560
529
|
|
561
530
|
def num_timesteps_per_item(self) -> pd.Series:
|
562
531
|
"""Length of each time series in the dataframe."""
|
563
532
|
return self.groupby(level=ITEMID, sort=False).size()
|
564
533
|
|
565
|
-
def copy(self: TimeSeriesDataFrame, deep: bool = True) ->
|
534
|
+
def copy(self: TimeSeriesDataFrame, deep: bool = True) -> TimeSeriesDataFrame:
|
566
535
|
"""Make a copy of the TimeSeriesDataFrame.
|
567
536
|
|
568
537
|
When ``deep=True`` (default), a new object will be created with a copy of the calling object's data and
|
@@ -590,8 +559,6 @@ class TimeSeriesDataFrame(pd.DataFrame, TimeSeriesDataFrameDeprecatedMixin):
|
|
590
559
|
# with the item index
|
591
560
|
if hasattr(other, "_static_features"):
|
592
561
|
self.static_features = other._static_features
|
593
|
-
if hasattr(other, "_cached_freq"):
|
594
|
-
self._cached_freq = other._cached_freq
|
595
562
|
return self
|
596
563
|
|
597
564
|
def split_by_time(self, cutoff_time: pd.Timestamp) -> Tuple[TimeSeriesDataFrame, TimeSeriesDataFrame]:
|
@@ -615,8 +582,6 @@ class TimeSeriesDataFrame(pd.DataFrame, TimeSeriesDataFrameDeprecatedMixin):
|
|
615
582
|
data_after = self.loc[(slice(None), slice(cutoff_time, None)), :]
|
616
583
|
before = TimeSeriesDataFrame(data_before, static_features=self.static_features)
|
617
584
|
after = TimeSeriesDataFrame(data_after, static_features=self.static_features)
|
618
|
-
before._cached_freq = self._cached_freq
|
619
|
-
after._cached_freq = self._cached_freq
|
620
585
|
return before, after
|
621
586
|
|
622
587
|
def slice_by_timestep(
|
@@ -717,7 +682,6 @@ class TimeSeriesDataFrame(pd.DataFrame, TimeSeriesDataFrameDeprecatedMixin):
|
|
717
682
|
time_step_slice = slice(start_index, end_index)
|
718
683
|
result = self.groupby(level=ITEMID, sort=False, as_index=False).nth(time_step_slice)
|
719
684
|
result.static_features = self.static_features
|
720
|
-
result._cached_freq = self._cached_freq
|
721
685
|
return result
|
722
686
|
|
723
687
|
def slice_by_time(self, start_time: pd.Timestamp, end_time: pd.Timestamp) -> TimeSeriesDataFrame:
|
@@ -866,6 +830,15 @@ class TimeSeriesDataFrame(pd.DataFrame, TimeSeriesDataFrameDeprecatedMixin):
|
|
866
830
|
dropped_df = pd.DataFrame(self).dropna(how=how)
|
867
831
|
return TimeSeriesDataFrame(dropped_df, static_features=self.static_features)
|
868
832
|
|
833
|
+
# added for static type checker compatibility
|
834
|
+
def assign(self, **kwargs) -> TimeSeriesDataFrame:
|
835
|
+
"""Assign new columns to the time series dataframe. See :meth:`pandas.DataFrame.assign` for details."""
|
836
|
+
return super().assign(**kwargs) # type: ignore
|
837
|
+
|
838
|
+
# added for static type checker compatibility
|
839
|
+
def sort_index(self, *args, **kwargs) -> TimeSeriesDataFrame:
|
840
|
+
return super().sort_index(*args, **kwargs) # type: ignore
|
841
|
+
|
869
842
|
def get_model_inputs_for_scoring(
|
870
843
|
self, prediction_length: int, known_covariates_names: Optional[List[str]] = None
|
871
844
|
) -> Tuple[TimeSeriesDataFrame, Optional[TimeSeriesDataFrame]]:
|
@@ -1033,8 +1006,6 @@ class TimeSeriesDataFrame(pd.DataFrame, TimeSeriesDataFrameDeprecatedMixin):
|
|
1033
1006
|
2021-12-31 26.0
|
1034
1007
|
"""
|
1035
1008
|
offset = pd.tseries.frequencies.to_offset(freq)
|
1036
|
-
if self.freq == offset.freqstr:
|
1037
|
-
return self
|
1038
1009
|
|
1039
1010
|
# We need to aggregate categorical columns separately because .agg("mean") deletes all non-numeric columns
|
1040
1011
|
aggregation = {}
|
@@ -1064,11 +1035,6 @@ class TimeSeriesDataFrame(pd.DataFrame, TimeSeriesDataFrameDeprecatedMixin):
|
|
1064
1035
|
resampled_df.static_features = self.static_features
|
1065
1036
|
return resampled_df
|
1066
1037
|
|
1067
|
-
def __dir__(self) -> List[str]:
|
1068
|
-
# This hides method from IPython autocomplete, but not VSCode autocomplete
|
1069
|
-
deprecated = ["get_reindexed_view", "to_regular_index"]
|
1070
|
-
return [d for d in super().__dir__() if d not in deprecated]
|
1071
|
-
|
1072
1038
|
def to_data_frame(self) -> pd.DataFrame:
|
1073
1039
|
"""Convert `TimeSeriesDataFrame` to a `pandas.DataFrame`"""
|
1074
1040
|
return pd.DataFrame(self)
|
autogluon/timeseries/learner.py
CHANGED
@@ -10,7 +10,7 @@ from autogluon.timeseries.dataset.ts_dataframe import TimeSeriesDataFrame
|
|
10
10
|
from autogluon.timeseries.metrics import TimeSeriesScorer, check_get_evaluation_metric
|
11
11
|
from autogluon.timeseries.models.abstract import AbstractTimeSeriesModel
|
12
12
|
from autogluon.timeseries.splitter import AbstractWindowSplitter
|
13
|
-
from autogluon.timeseries.trainer import
|
13
|
+
from autogluon.timeseries.trainer import TimeSeriesTrainer
|
14
14
|
from autogluon.timeseries.utils.features import TimeSeriesFeatureGenerator
|
15
15
|
from autogluon.timeseries.utils.forecast import get_forecast_horizon_index_ts_dataframe
|
16
16
|
|
@@ -27,7 +27,7 @@ class TimeSeriesLearner(AbstractLearner):
|
|
27
27
|
path_context: str,
|
28
28
|
target: str = "target",
|
29
29
|
known_covariates_names: Optional[List[str]] = None,
|
30
|
-
trainer_type: Type[
|
30
|
+
trainer_type: Type[TimeSeriesTrainer] = TimeSeriesTrainer,
|
31
31
|
eval_metric: Union[str, TimeSeriesScorer, None] = None,
|
32
32
|
eval_metric_seasonal_period: Optional[int] = None,
|
33
33
|
prediction_length: int = 1,
|
@@ -51,33 +51,17 @@ class TimeSeriesLearner(AbstractLearner):
|
|
51
51
|
target=self.target, known_covariates_names=self.known_covariates_names
|
52
52
|
)
|
53
53
|
|
54
|
-
def load_trainer(self) ->
|
54
|
+
def load_trainer(self) -> TimeSeriesTrainer: # type: ignore
|
55
55
|
"""Return the trainer object corresponding to the learner."""
|
56
|
-
return super().load_trainer() #
|
56
|
+
return super().load_trainer() # type: ignore
|
57
57
|
|
58
58
|
def fit(
|
59
59
|
self,
|
60
60
|
train_data: TimeSeriesDataFrame,
|
61
|
-
|
62
|
-
hyperparameters: Union[str, Dict] = None,
|
63
|
-
hyperparameter_tune_kwargs: Optional[Union[str, dict]] = None,
|
64
|
-
**kwargs,
|
65
|
-
) -> None:
|
66
|
-
return self._fit(
|
67
|
-
train_data=train_data,
|
68
|
-
val_data=val_data,
|
69
|
-
hyperparameters=hyperparameters,
|
70
|
-
hyperparameter_tune_kwargs=hyperparameter_tune_kwargs,
|
71
|
-
**kwargs,
|
72
|
-
)
|
73
|
-
|
74
|
-
def _fit(
|
75
|
-
self,
|
76
|
-
train_data: TimeSeriesDataFrame,
|
61
|
+
hyperparameters: Union[str, Dict],
|
77
62
|
val_data: Optional[TimeSeriesDataFrame] = None,
|
78
|
-
hyperparameters: Union[str, Dict] = None,
|
79
63
|
hyperparameter_tune_kwargs: Optional[Union[str, dict]] = None,
|
80
|
-
time_limit: Optional[
|
64
|
+
time_limit: Optional[float] = None,
|
81
65
|
val_splitter: Optional[AbstractWindowSplitter] = None,
|
82
66
|
refit_every_n_windows: Optional[int] = 1,
|
83
67
|
random_seed: Optional[int] = None,
|
@@ -111,7 +95,9 @@ class TimeSeriesLearner(AbstractLearner):
|
|
111
95
|
ensemble_model_type=self.ensemble_model_type,
|
112
96
|
)
|
113
97
|
)
|
114
|
-
|
98
|
+
|
99
|
+
assert issubclass(self.trainer_type, TimeSeriesTrainer)
|
100
|
+
self.trainer: Optional[TimeSeriesTrainer] = self.trainer_type(**trainer_init_kwargs)
|
115
101
|
self.trainer_path = self.trainer.path
|
116
102
|
self.save()
|
117
103
|
|
@@ -151,6 +137,7 @@ class TimeSeriesLearner(AbstractLearner):
|
|
151
137
|
raise ValueError(
|
152
138
|
f"known_covariates {self.known_covariates_names} for the forecast horizon should be provided at prediction time."
|
153
139
|
)
|
140
|
+
assert known_covariates is not None
|
154
141
|
|
155
142
|
if self.target in known_covariates.columns:
|
156
143
|
known_covariates = known_covariates.drop(self.target, axis=1)
|
@@ -165,7 +152,7 @@ class TimeSeriesLearner(AbstractLearner):
|
|
165
152
|
data, prediction_length=self.prediction_length, freq=self.freq
|
166
153
|
)
|
167
154
|
try:
|
168
|
-
known_covariates = known_covariates.loc[forecast_index]
|
155
|
+
known_covariates = known_covariates.loc[forecast_index] # type: ignore
|
169
156
|
except KeyError:
|
170
157
|
raise ValueError(
|
171
158
|
f"known_covariates should include the values for prediction_length={self.prediction_length} "
|
@@ -197,7 +184,7 @@ class TimeSeriesLearner(AbstractLearner):
|
|
197
184
|
def score(
|
198
185
|
self,
|
199
186
|
data: TimeSeriesDataFrame,
|
200
|
-
model: AbstractTimeSeriesModel = None,
|
187
|
+
model: Optional[Union[str, AbstractTimeSeriesModel]] = None,
|
201
188
|
metric: Union[str, TimeSeriesScorer, None] = None,
|
202
189
|
use_cache: bool = True,
|
203
190
|
) -> float:
|
@@ -223,7 +210,7 @@ class TimeSeriesLearner(AbstractLearner):
|
|
223
210
|
time_limit: Optional[float] = None,
|
224
211
|
method: Literal["naive", "permutation"] = "permutation",
|
225
212
|
subsample_size: int = 50,
|
226
|
-
num_iterations: int =
|
213
|
+
num_iterations: Optional[int] = None,
|
227
214
|
random_seed: Optional[int] = None,
|
228
215
|
relative_scores: bool = False,
|
229
216
|
include_confidence_band: bool = True,
|
@@ -337,7 +324,7 @@ class TimeSeriesLearner(AbstractLearner):
|
|
337
324
|
List of models removed from memory
|
338
325
|
"""
|
339
326
|
unpersisted_models = self.load_trainer().unpersist()
|
340
|
-
self.trainer = None
|
327
|
+
self.trainer = None # type: ignore
|
341
328
|
return unpersisted_models
|
342
329
|
|
343
330
|
def refit_full(self, model: str = "all") -> Dict[str, str]:
|
@@ -87,9 +87,9 @@ class AbstractTimeSeriesModel(AbstractModel):
|
|
87
87
|
_preprocess_nonadaptive = None
|
88
88
|
_preprocess_set_features = None
|
89
89
|
|
90
|
-
|
91
|
-
|
92
|
-
|
90
|
+
_supports_known_covariates: bool = False
|
91
|
+
_supports_past_covariates: bool = False
|
92
|
+
_supports_static_features: bool = False
|
93
93
|
|
94
94
|
def __init__(
|
95
95
|
self,
|
@@ -171,6 +171,23 @@ class AbstractTimeSeriesModel(AbstractModel):
|
|
171
171
|
"""Load the cached OOF predictions from disk."""
|
172
172
|
return load_pkl.load(path=os.path.join(path, "utils", cls._oof_filename), verbose=verbose)
|
173
173
|
|
174
|
+
@property
|
175
|
+
def supports_known_covariates(self) -> bool:
|
176
|
+
return (
|
177
|
+
self._get_model_params().get("covariate_regressor") is not None
|
178
|
+
or self.__class__._supports_known_covariates
|
179
|
+
)
|
180
|
+
|
181
|
+
@property
|
182
|
+
def supports_past_covariates(self) -> bool:
|
183
|
+
return self.__class__._supports_past_covariates
|
184
|
+
|
185
|
+
@property
|
186
|
+
def supports_static_features(self) -> bool:
|
187
|
+
return (
|
188
|
+
self._get_model_params().get("covariate_regressor") is not None or self.__class__._supports_static_features
|
189
|
+
)
|
190
|
+
|
174
191
|
def get_oof_predictions(self):
|
175
192
|
if self._oof_predictions is None:
|
176
193
|
self._oof_predictions = self.load_oof_predictions(self.path)
|
@@ -442,10 +459,7 @@ class AbstractTimeSeriesModel(AbstractModel):
|
|
442
459
|
|
443
460
|
if self.covariate_regressor is not None:
|
444
461
|
if known_covariates is None:
|
445
|
-
|
446
|
-
data, prediction_length=self.prediction_length, freq=self.freq
|
447
|
-
)
|
448
|
-
known_covariates = pd.DataFrame(index=forecast_index, dtype="float32")
|
462
|
+
known_covariates = pd.DataFrame(index=self.get_forecast_horizon_index(data), dtype="float32")
|
449
463
|
|
450
464
|
predictions = self.covariate_regressor.inverse_transform(
|
451
465
|
predictions,
|
@@ -457,6 +471,10 @@ class AbstractTimeSeriesModel(AbstractModel):
|
|
457
471
|
predictions = self.target_scaler.inverse_transform(predictions)
|
458
472
|
return predictions
|
459
473
|
|
474
|
+
def get_forecast_horizon_index(self, data: TimeSeriesDataFrame) -> pd.MultiIndex:
|
475
|
+
"""For each item in the dataframe, get timestamps for the next `prediction_length` time steps into the future."""
|
476
|
+
return get_forecast_horizon_index_ts_dataframe(data, prediction_length=self.prediction_length, freq=self.freq)
|
477
|
+
|
460
478
|
def _predict(
|
461
479
|
self,
|
462
480
|
data: Union[TimeSeriesDataFrame, Dict[str, TimeSeriesDataFrame]],
|
@@ -19,7 +19,6 @@ from autogluon.timeseries.utils.datetime import (
|
|
19
19
|
get_seasonality,
|
20
20
|
get_time_features_for_frequency,
|
21
21
|
)
|
22
|
-
from autogluon.timeseries.utils.forecast import get_forecast_horizon_index_ts_dataframe
|
23
22
|
from autogluon.timeseries.utils.warning_filters import warning_filter
|
24
23
|
|
25
24
|
from .utils import MLF_ITEMID, MLF_TARGET, MLF_TIMESTAMP
|
@@ -54,6 +53,9 @@ class TabularEstimator(BaseEstimator):
|
|
54
53
|
|
55
54
|
|
56
55
|
class AbstractMLForecastModel(AbstractTimeSeriesModel):
|
56
|
+
_supports_known_covariates = True
|
57
|
+
_supports_static_features = True
|
58
|
+
|
57
59
|
def __init__(
|
58
60
|
self,
|
59
61
|
freq: Optional[str] = None,
|
@@ -468,9 +470,6 @@ class DirectTabularModel(AbstractMLForecastModel):
|
|
468
470
|
end of each time series).
|
469
471
|
"""
|
470
472
|
|
471
|
-
supports_known_covariates = True
|
472
|
-
supports_static_features = True
|
473
|
-
|
474
473
|
@property
|
475
474
|
def is_quantile_model(self) -> bool:
|
476
475
|
return self.eval_metric.needs_quantile
|
@@ -519,7 +518,7 @@ class DirectTabularModel(AbstractMLForecastModel):
|
|
519
518
|
if known_covariates is not None:
|
520
519
|
data_future = known_covariates.copy()
|
521
520
|
else:
|
522
|
-
future_index =
|
521
|
+
future_index = self.get_forecast_horizon_index(data)
|
523
522
|
data_future = pd.DataFrame(columns=[self.target], index=future_index, dtype="float32")
|
524
523
|
# MLForecast raises exception of target contains NaN. We use inf as placeholder, replace them by NaN afterwards
|
525
524
|
data_future[self.target] = float("inf")
|
@@ -624,9 +623,6 @@ class RecursiveTabularModel(AbstractMLForecastModel):
|
|
624
623
|
end of each time series).
|
625
624
|
"""
|
626
625
|
|
627
|
-
supports_known_covariates = True
|
628
|
-
supports_static_features = True
|
629
|
-
|
630
626
|
def _get_model_params(self) -> dict:
|
631
627
|
model_params = super()._get_model_params()
|
632
628
|
model_params.setdefault("target_scaler", "standard")
|
@@ -652,7 +648,7 @@ class RecursiveTabularModel(AbstractMLForecastModel):
|
|
652
648
|
if self._max_ts_length is not None:
|
653
649
|
new_df = self._shorten_all_series(new_df, self._max_ts_length)
|
654
650
|
if known_covariates is None:
|
655
|
-
future_index =
|
651
|
+
future_index = self.get_forecast_horizon_index(data)
|
656
652
|
known_covariates = pd.DataFrame(columns=[self.target], index=future_index, dtype="float32")
|
657
653
|
X_df = self._to_mlforecast_df(known_covariates, data.static_features, include_target=False)
|
658
654
|
# If both covariates & static features are missing, set X_df = None to avoid exception from MLForecast
|
@@ -11,7 +11,6 @@ import pandas as pd
|
|
11
11
|
from autogluon.common.loaders import load_pkl
|
12
12
|
from autogluon.timeseries.dataset.ts_dataframe import TimeSeriesDataFrame
|
13
13
|
from autogluon.timeseries.models.abstract import AbstractTimeSeriesModel
|
14
|
-
from autogluon.timeseries.utils.forecast import get_forecast_horizon_index_ts_dataframe
|
15
14
|
from autogluon.timeseries.utils.warning_filters import disable_duplicate_logs, warning_filter
|
16
15
|
|
17
16
|
logger = logging.getLogger("autogluon.timeseries.models.chronos")
|
@@ -631,7 +630,7 @@ class ChronosModel(AbstractTimeSeriesModel):
|
|
631
630
|
axis=1,
|
632
631
|
),
|
633
632
|
columns=["mean"] + [str(q) for q in self.quantile_levels],
|
634
|
-
index=
|
633
|
+
index=self.get_forecast_horizon_index(data),
|
635
634
|
)
|
636
635
|
|
637
636
|
return TimeSeriesDataFrame(df)
|
@@ -253,7 +253,6 @@ class ChronosInferenceDataset:
|
|
253
253
|
assert context_length > 0
|
254
254
|
self.context_length = context_length
|
255
255
|
self.target_array = target_df[target_column].to_numpy(dtype=np.float32)
|
256
|
-
self.freq = target_df.freq
|
257
256
|
|
258
257
|
# store pointer to start:end of each time series
|
259
258
|
cum_sizes = target_df.num_timesteps_per_item().values.cumsum()
|
@@ -24,7 +24,6 @@ from autogluon.tabular.models.tabular_nn.utils.categorical_encoders import (
|
|
24
24
|
from autogluon.timeseries.dataset.ts_dataframe import ITEMID, TIMESTAMP, TimeSeriesDataFrame
|
25
25
|
from autogluon.timeseries.models.abstract import AbstractTimeSeriesModel
|
26
26
|
from autogluon.timeseries.utils.datetime import norm_freq_str
|
27
|
-
from autogluon.timeseries.utils.forecast import get_forecast_horizon_index_ts_dataframe
|
28
27
|
from autogluon.timeseries.utils.warning_filters import disable_root_logger, warning_filter
|
29
28
|
|
30
29
|
# NOTE: We avoid imports for torch and lightning.pytorch at the top level and hide them inside class methods.
|
@@ -162,7 +161,9 @@ class AbstractGluonTSModel(AbstractTimeSeriesModel):
|
|
162
161
|
_dummy_gluonts_freq = "D"
|
163
162
|
# default number of samples for prediction
|
164
163
|
default_num_samples: int = 250
|
165
|
-
|
164
|
+
|
165
|
+
#: whether the GluonTS model supports categorical variables as covariates
|
166
|
+
_supports_cat_covariates: bool = False
|
166
167
|
|
167
168
|
def __init__(
|
168
169
|
self,
|
@@ -227,6 +228,10 @@ class AbstractGluonTSModel(AbstractTimeSeriesModel):
|
|
227
228
|
model.gts_predictor = PyTorchPredictor.deserialize(Path(path) / cls.gluonts_model_path, device="auto")
|
228
229
|
return model
|
229
230
|
|
231
|
+
@property
|
232
|
+
def supports_cat_covariates(self) -> bool:
|
233
|
+
return self.__class__._supports_cat_covariates
|
234
|
+
|
230
235
|
def _get_hpo_backend(self):
|
231
236
|
return RAY_BACKEND
|
232
237
|
|
@@ -530,7 +535,7 @@ class AbstractGluonTSModel(AbstractTimeSeriesModel):
|
|
530
535
|
predicted_targets = self._predict_gluonts_forecasts(data, known_covariates=known_covariates, **kwargs)
|
531
536
|
df = self._gluonts_forecasts_to_data_frame(
|
532
537
|
predicted_targets,
|
533
|
-
forecast_index=
|
538
|
+
forecast_index=self.get_forecast_horizon_index(data),
|
534
539
|
)
|
535
540
|
return df
|
536
541
|
|
@@ -88,8 +88,8 @@ class DeepARModel(AbstractGluonTSModel):
|
|
88
88
|
|
89
89
|
# TODO: Replace "scaling: bool" with "window_scaler": {"mean_abs", None} for consistency?
|
90
90
|
|
91
|
-
|
92
|
-
|
91
|
+
_supports_known_covariates = True
|
92
|
+
_supports_static_features = True
|
93
93
|
|
94
94
|
def _get_estimator_class(self) -> Type[GluonTSEstimator]:
|
95
95
|
from gluonts.torch.model.deepar import DeepAREstimator
|
@@ -204,10 +204,10 @@ class TemporalFusionTransformerModel(AbstractGluonTSModel):
|
|
204
204
|
If True, ``lightning_logs`` directory will NOT be removed after the model finished training.
|
205
205
|
"""
|
206
206
|
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
207
|
+
_supports_known_covariates = True
|
208
|
+
_supports_past_covariates = True
|
209
|
+
_supports_cat_covariates = True
|
210
|
+
_supports_static_features = True
|
211
211
|
|
212
212
|
def _get_estimator_class(self) -> Type[GluonTSEstimator]:
|
213
213
|
from gluonts.torch.model.tft import TemporalFusionTransformerEstimator
|
@@ -341,7 +341,7 @@ class PatchTSTModel(AbstractGluonTSModel):
|
|
341
341
|
If True, ``lightning_logs`` directory will NOT be removed after the model finished training.
|
342
342
|
"""
|
343
343
|
|
344
|
-
|
344
|
+
_supports_known_covariates = True
|
345
345
|
|
346
346
|
def _get_estimator_class(self) -> Type[GluonTSEstimator]:
|
347
347
|
from gluonts.torch.model.patch_tst import PatchTSTEstimator
|
@@ -417,8 +417,8 @@ class WaveNetModel(AbstractGluonTSModel):
|
|
417
417
|
If True, ``lightning_logs`` directory will NOT be removed after the model finished training.
|
418
418
|
"""
|
419
419
|
|
420
|
-
|
421
|
-
|
420
|
+
_supports_known_covariates = True
|
421
|
+
_supports_static_features = True
|
422
422
|
default_num_samples: int = 100
|
423
423
|
|
424
424
|
def _get_estimator_class(self) -> Type[GluonTSEstimator]:
|
@@ -462,9 +462,6 @@ class TiDEModel(AbstractGluonTSModel):
|
|
462
462
|
disable_known_covariates : bool, default = False
|
463
463
|
If True, known covariates won't be used by the model even if they are present in the dataset.
|
464
464
|
If False, known covariates will be used by the model if they are present in the dataset.
|
465
|
-
disable_past_covariates : bool, default = False
|
466
|
-
If True, past covariates won't be used by the model even if they are present in the dataset.
|
467
|
-
If False, past covariates will be used by the model if they are present in the dataset.
|
468
465
|
feat_proj_hidden_dim : int, default = 4
|
469
466
|
Size of the feature projection layer.
|
470
467
|
encoder_hidden_dim : int, default = 64
|
@@ -512,8 +509,8 @@ class TiDEModel(AbstractGluonTSModel):
|
|
512
509
|
If True, ``lightning_logs`` directory will NOT be removed after the model finished training.
|
513
510
|
"""
|
514
511
|
|
515
|
-
|
516
|
-
|
512
|
+
_supports_known_covariates = True
|
513
|
+
_supports_static_features = True
|
517
514
|
|
518
515
|
def _get_estimator_class(self) -> Type[GluonTSEstimator]:
|
519
516
|
from gluonts.torch.model.tide import TiDEEstimator
|
@@ -12,7 +12,6 @@ from autogluon.core.utils.exceptions import TimeLimitExceeded
|
|
12
12
|
from autogluon.timeseries.dataset.ts_dataframe import ITEMID, TimeSeriesDataFrame
|
13
13
|
from autogluon.timeseries.models.abstract import AbstractTimeSeriesModel
|
14
14
|
from autogluon.timeseries.utils.datetime import get_seasonality
|
15
|
-
from autogluon.timeseries.utils.forecast import get_forecast_horizon_index_ts_dataframe
|
16
15
|
from autogluon.timeseries.utils.warning_filters import warning_filter
|
17
16
|
|
18
17
|
logger = logging.getLogger(__name__)
|
@@ -134,7 +133,7 @@ class AbstractLocalModel(AbstractTimeSeriesModel):
|
|
134
133
|
)
|
135
134
|
|
136
135
|
if "seasonal_period" not in local_model_args or local_model_args["seasonal_period"] is None:
|
137
|
-
local_model_args["seasonal_period"] = get_seasonality(
|
136
|
+
local_model_args["seasonal_period"] = get_seasonality(self.freq)
|
138
137
|
self._seasonal_period = local_model_args["seasonal_period"]
|
139
138
|
|
140
139
|
self._local_model_args = self._update_local_model_args(local_model_args=local_model_args)
|
@@ -183,7 +182,7 @@ class AbstractLocalModel(AbstractTimeSeriesModel):
|
|
183
182
|
f"({fraction_failed_models:.1%}). Fallback model SeasonalNaive was used for these time series."
|
184
183
|
)
|
185
184
|
predictions_df = pd.concat([pred for pred, _ in predictions_with_flags])
|
186
|
-
predictions_df.index =
|
185
|
+
predictions_df.index = self.get_forecast_horizon_index(data)
|
187
186
|
return TimeSeriesDataFrame(predictions_df)
|
188
187
|
|
189
188
|
def _predict_wrapper(self, time_series: pd.Series, end_time: Optional[float] = None) -> Tuple[pd.DataFrame, bool]:
|
@@ -496,7 +496,7 @@ class AbstractConformalizedStatsForecastModel(AbstractStatsForecastModel):
|
|
496
496
|
|
497
497
|
class AutoCESModel(AbstractProbabilisticStatsForecastModel):
|
498
498
|
"""Forecasting with an Complex Exponential Smoothing model where the model selection is performed using the
|
499
|
-
Akaike Information Criterion.
|
499
|
+
Akaike Information Criterion [Svetunkov2022]_.
|
500
500
|
|
501
501
|
Based on `statsforecast.models.AutoCES <https://nixtla.mintlify.app/statsforecast/docs/models/autoces.html>`_.
|
502
502
|
|
@@ -4,7 +4,7 @@ import logging
|
|
4
4
|
import math
|
5
5
|
import os
|
6
6
|
import time
|
7
|
-
from typing import Dict, Optional, Type, Union
|
7
|
+
from typing import Any, Dict, Optional, Type, Union
|
8
8
|
|
9
9
|
import numpy as np
|
10
10
|
|
@@ -32,13 +32,13 @@ class MultiWindowBacktestingModel(AbstractTimeSeriesModel):
|
|
32
32
|
kwargs used to initialize model_base if model_base is a class.
|
33
33
|
"""
|
34
34
|
|
35
|
-
# TODO: Remove the MultiWindowBacktestingModel class, move the logic to
|
35
|
+
# TODO: Remove the MultiWindowBacktestingModel class, move the logic to TimeSeriesTrainer
|
36
36
|
default_max_time_limit_ratio = 1.0
|
37
37
|
|
38
38
|
def __init__(
|
39
39
|
self,
|
40
40
|
model_base: Union[AbstractTimeSeriesModel, Type[AbstractTimeSeriesModel]],
|
41
|
-
model_base_kwargs: Optional[Dict[str,
|
41
|
+
model_base_kwargs: Optional[Dict[str, Any]] = None,
|
42
42
|
**kwargs,
|
43
43
|
):
|
44
44
|
if inspect.isclass(model_base) and issubclass(model_base, AbstractTimeSeriesModel):
|
@@ -57,21 +57,25 @@ class MultiWindowBacktestingModel(AbstractTimeSeriesModel):
|
|
57
57
|
self.model_base_type = type(self.model_base)
|
58
58
|
self.info_per_val_window = []
|
59
59
|
|
60
|
-
self.most_recent_model: AbstractTimeSeriesModel = None
|
60
|
+
self.most_recent_model: Optional[AbstractTimeSeriesModel] = None
|
61
61
|
self.most_recent_model_folder: Optional[str] = None
|
62
62
|
super().__init__(**kwargs)
|
63
63
|
|
64
64
|
@property
|
65
65
|
def supports_static_features(self) -> bool:
|
66
|
-
return self.
|
66
|
+
return self.model_base.supports_static_features
|
67
67
|
|
68
68
|
@property
|
69
69
|
def supports_known_covariates(self) -> bool:
|
70
|
-
return self.
|
70
|
+
return self.model_base.supports_known_covariates
|
71
71
|
|
72
72
|
@property
|
73
73
|
def supports_past_covariates(self) -> bool:
|
74
|
-
return self.
|
74
|
+
return self.model_base.supports_past_covariates
|
75
|
+
|
76
|
+
@property
|
77
|
+
def supports_cat_covariates(self) -> bool:
|
78
|
+
return self.model_base.supports_cat_covariates
|
75
79
|
|
76
80
|
def _get_model_base(self):
|
77
81
|
return self.model_base
|
@@ -182,7 +182,7 @@ def get_preset_models(
|
|
182
182
|
freq: Optional[str],
|
183
183
|
prediction_length: int,
|
184
184
|
path: str,
|
185
|
-
eval_metric: TimeSeriesScorer,
|
185
|
+
eval_metric: str | TimeSeriesScorer,
|
186
186
|
eval_metric_seasonal_period: Optional[int],
|
187
187
|
hyperparameters: Union[str, Dict, None],
|
188
188
|
hyperparameter_tune: bool,
|