autogluon.timeseries 1.2.1b20250116__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.
Files changed (30) hide show
  1. autogluon/timeseries/dataset/ts_dataframe.py +22 -56
  2. autogluon/timeseries/learner.py +14 -27
  3. autogluon/timeseries/models/abstract/abstract_timeseries_model.py +25 -7
  4. autogluon/timeseries/models/autogluon_tabular/mlforecast.py +5 -9
  5. autogluon/timeseries/models/chronos/model.py +1 -2
  6. autogluon/timeseries/models/chronos/pipeline/utils.py +0 -1
  7. autogluon/timeseries/models/gluonts/abstract_gluonts.py +8 -3
  8. autogluon/timeseries/models/gluonts/torch/models.py +11 -14
  9. autogluon/timeseries/models/local/abstract_local_model.py +2 -3
  10. autogluon/timeseries/models/local/statsforecast.py +1 -1
  11. autogluon/timeseries/models/multi_window/multi_window_model.py +11 -7
  12. autogluon/timeseries/models/presets.py +1 -1
  13. autogluon/timeseries/predictor.py +49 -69
  14. autogluon/timeseries/regressor.py +41 -18
  15. autogluon/timeseries/{trainer/abstract_trainer.py → trainer.py} +122 -243
  16. autogluon/timeseries/transforms/covariate_scaler.py +13 -2
  17. autogluon/timeseries/transforms/target_scaler.py +1 -1
  18. autogluon/timeseries/utils/forecast.py +2 -1
  19. autogluon/timeseries/version.py +1 -1
  20. {autogluon.timeseries-1.2.1b20250116.dist-info → autogluon.timeseries-1.2.1b20250130.dist-info}/METADATA +6 -4
  21. {autogluon.timeseries-1.2.1b20250116.dist-info → autogluon.timeseries-1.2.1b20250130.dist-info}/RECORD +28 -30
  22. autogluon/timeseries/trainer/__init__.py +0 -4
  23. autogluon/timeseries/trainer/auto_trainer.py +0 -77
  24. /autogluon.timeseries-1.2.1b20250116-py3.8-nspkg.pth → /autogluon.timeseries-1.2.1b20250130-py3.9-nspkg.pth +0 -0
  25. {autogluon.timeseries-1.2.1b20250116.dist-info → autogluon.timeseries-1.2.1b20250130.dist-info}/LICENSE +0 -0
  26. {autogluon.timeseries-1.2.1b20250116.dist-info → autogluon.timeseries-1.2.1b20250130.dist-info}/NOTICE +0 -0
  27. {autogluon.timeseries-1.2.1b20250116.dist-info → autogluon.timeseries-1.2.1b20250130.dist-info}/WHEEL +0 -0
  28. {autogluon.timeseries-1.2.1b20250116.dist-info → autogluon.timeseries-1.2.1b20250130.dist-info}/namespace_packages.txt +0 -0
  29. {autogluon.timeseries-1.2.1b20250116.dist-info → autogluon.timeseries-1.2.1b20250130.dist-info}/top_level.txt +0 -0
  30. {autogluon.timeseries-1.2.1b20250116.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 TimeSeriesDataFrameDeprecatedMixin:
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", "_cached_freq"]
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] = 100, raise_if_irregular: bool = False) -> str:
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 = 100
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
- if self._cached_freq is None:
550
- self._cached_freq = self.infer_frequency()
517
+ """Inferred pandas-compatible frequency of the timestamps in the data frame.
551
518
 
552
- if self._cached_freq == IRREGULAR_TIME_INDEX_FREQSTR:
553
- return None # irregularly sampled time series
554
- else:
555
- return self._cached_freq
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) -> pd.DataFrame: # type: ignore # noqa
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)
@@ -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 AbstractTimeSeriesTrainer, AutoTimeSeriesTrainer
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[AbstractTimeSeriesTrainer] = AutoTimeSeriesTrainer,
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) -> AbstractTimeSeriesTrainer:
54
+ def load_trainer(self) -> TimeSeriesTrainer: # type: ignore
55
55
  """Return the trainer object corresponding to the learner."""
56
- return super().load_trainer() # noqa
56
+ return super().load_trainer() # type: ignore
57
57
 
58
58
  def fit(
59
59
  self,
60
60
  train_data: TimeSeriesDataFrame,
61
- val_data: TimeSeriesDataFrame = None,
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[int] = None,
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
- self.trainer = self.trainer_type(**trainer_init_kwargs)
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 = 1,
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
- supports_known_covariates: bool = False
91
- supports_past_covariates: bool = False
92
- supports_static_features: bool = False
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
- forecast_index = get_forecast_horizon_index_ts_dataframe(
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 = get_forecast_horizon_index_ts_dataframe(data, self.prediction_length, freq=self.freq)
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 = get_forecast_horizon_index_ts_dataframe(data, self.prediction_length, freq=self.freq)
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=get_forecast_horizon_index_ts_dataframe(data, self.prediction_length, freq=self.freq),
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
- supports_cat_covariates: bool = False
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=get_forecast_horizon_index_ts_dataframe(data, self.prediction_length, freq=self.freq),
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
- supports_known_covariates = True
92
- supports_static_features = True
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
- supports_known_covariates = True
208
- supports_past_covariates = True
209
- supports_cat_covariates = True
210
- supports_static_features = True
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
- supports_known_covariates = True
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
- supports_known_covariates = True
421
- supports_static_features = True
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
- supports_known_covariates = True
516
- supports_static_features = True
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(train_data.freq)
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 = get_forecast_horizon_index_ts_dataframe(data, self.prediction_length, freq=self.freq)
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 AbstractTimeSeriesTrainer
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, any]] = None,
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.model_base_type.supports_static_features
66
+ return self.model_base.supports_static_features
67
67
 
68
68
  @property
69
69
  def supports_known_covariates(self) -> bool:
70
- return self.model_base_type.supports_known_covariates
70
+ return self.model_base.supports_known_covariates
71
71
 
72
72
  @property
73
73
  def supports_past_covariates(self) -> bool:
74
- return self.model_base_type.supports_past_covariates
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,