autogluon.timeseries 1.3.2b20250712__py3-none-any.whl → 1.4.1b20251116__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 (90) hide show
  1. autogluon/timeseries/configs/__init__.py +3 -2
  2. autogluon/timeseries/configs/hyperparameter_presets.py +62 -0
  3. autogluon/timeseries/configs/predictor_presets.py +84 -0
  4. autogluon/timeseries/dataset/ts_dataframe.py +98 -72
  5. autogluon/timeseries/learner.py +19 -18
  6. autogluon/timeseries/metrics/__init__.py +5 -5
  7. autogluon/timeseries/metrics/abstract.py +17 -17
  8. autogluon/timeseries/metrics/point.py +1 -1
  9. autogluon/timeseries/metrics/quantile.py +2 -2
  10. autogluon/timeseries/metrics/utils.py +4 -4
  11. autogluon/timeseries/models/__init__.py +4 -0
  12. autogluon/timeseries/models/abstract/abstract_timeseries_model.py +52 -75
  13. autogluon/timeseries/models/abstract/tunable.py +6 -6
  14. autogluon/timeseries/models/autogluon_tabular/mlforecast.py +72 -76
  15. autogluon/timeseries/models/autogluon_tabular/per_step.py +104 -46
  16. autogluon/timeseries/models/autogluon_tabular/transforms.py +9 -7
  17. autogluon/timeseries/models/chronos/model.py +115 -78
  18. autogluon/timeseries/models/chronos/{pipeline/utils.py → utils.py} +76 -44
  19. autogluon/timeseries/models/ensemble/__init__.py +29 -2
  20. autogluon/timeseries/models/ensemble/abstract.py +16 -52
  21. autogluon/timeseries/models/ensemble/array_based/__init__.py +3 -0
  22. autogluon/timeseries/models/ensemble/array_based/abstract.py +247 -0
  23. autogluon/timeseries/models/ensemble/array_based/models.py +50 -0
  24. autogluon/timeseries/models/ensemble/array_based/regressor/__init__.py +10 -0
  25. autogluon/timeseries/models/ensemble/array_based/regressor/abstract.py +87 -0
  26. autogluon/timeseries/models/ensemble/array_based/regressor/per_quantile_tabular.py +133 -0
  27. autogluon/timeseries/models/ensemble/array_based/regressor/tabular.py +141 -0
  28. autogluon/timeseries/models/ensemble/weighted/__init__.py +8 -0
  29. autogluon/timeseries/models/ensemble/weighted/abstract.py +41 -0
  30. autogluon/timeseries/models/ensemble/{basic.py → weighted/basic.py} +8 -18
  31. autogluon/timeseries/models/ensemble/{greedy.py → weighted/greedy.py} +13 -13
  32. autogluon/timeseries/models/gluonts/abstract.py +26 -26
  33. autogluon/timeseries/models/gluonts/dataset.py +4 -4
  34. autogluon/timeseries/models/gluonts/models.py +27 -12
  35. autogluon/timeseries/models/local/abstract_local_model.py +14 -14
  36. autogluon/timeseries/models/local/naive.py +4 -0
  37. autogluon/timeseries/models/local/npts.py +1 -0
  38. autogluon/timeseries/models/local/statsforecast.py +30 -14
  39. autogluon/timeseries/models/multi_window/multi_window_model.py +34 -23
  40. autogluon/timeseries/models/registry.py +65 -0
  41. autogluon/timeseries/models/toto/__init__.py +3 -0
  42. autogluon/timeseries/models/toto/_internal/__init__.py +9 -0
  43. autogluon/timeseries/models/toto/_internal/backbone/__init__.py +3 -0
  44. autogluon/timeseries/models/toto/_internal/backbone/attention.py +197 -0
  45. autogluon/timeseries/models/toto/_internal/backbone/backbone.py +262 -0
  46. autogluon/timeseries/models/toto/_internal/backbone/distribution.py +70 -0
  47. autogluon/timeseries/models/toto/_internal/backbone/kvcache.py +136 -0
  48. autogluon/timeseries/models/toto/_internal/backbone/rope.py +94 -0
  49. autogluon/timeseries/models/toto/_internal/backbone/scaler.py +306 -0
  50. autogluon/timeseries/models/toto/_internal/backbone/transformer.py +333 -0
  51. autogluon/timeseries/models/toto/_internal/dataset.py +165 -0
  52. autogluon/timeseries/models/toto/_internal/forecaster.py +423 -0
  53. autogluon/timeseries/models/toto/dataloader.py +108 -0
  54. autogluon/timeseries/models/toto/hf_pretrained_model.py +119 -0
  55. autogluon/timeseries/models/toto/model.py +236 -0
  56. autogluon/timeseries/predictor.py +94 -107
  57. autogluon/timeseries/regressor.py +31 -27
  58. autogluon/timeseries/splitter.py +7 -31
  59. autogluon/timeseries/trainer/__init__.py +3 -0
  60. autogluon/timeseries/trainer/ensemble_composer.py +250 -0
  61. autogluon/timeseries/trainer/model_set_builder.py +256 -0
  62. autogluon/timeseries/trainer/prediction_cache.py +149 -0
  63. autogluon/timeseries/{trainer.py → trainer/trainer.py} +182 -307
  64. autogluon/timeseries/trainer/utils.py +18 -0
  65. autogluon/timeseries/transforms/covariate_scaler.py +4 -4
  66. autogluon/timeseries/transforms/target_scaler.py +14 -14
  67. autogluon/timeseries/utils/datetime/lags.py +2 -2
  68. autogluon/timeseries/utils/datetime/time_features.py +2 -2
  69. autogluon/timeseries/utils/features.py +41 -37
  70. autogluon/timeseries/utils/forecast.py +5 -5
  71. autogluon/timeseries/utils/warning_filters.py +3 -1
  72. autogluon/timeseries/version.py +1 -1
  73. autogluon.timeseries-1.4.1b20251116-py3.9-nspkg.pth +1 -0
  74. {autogluon.timeseries-1.3.2b20250712.dist-info → autogluon_timeseries-1.4.1b20251116.dist-info}/METADATA +32 -17
  75. autogluon_timeseries-1.4.1b20251116.dist-info/RECORD +96 -0
  76. {autogluon.timeseries-1.3.2b20250712.dist-info → autogluon_timeseries-1.4.1b20251116.dist-info}/WHEEL +1 -1
  77. autogluon/timeseries/configs/presets_configs.py +0 -79
  78. autogluon/timeseries/evaluator.py +0 -6
  79. autogluon/timeseries/models/chronos/pipeline/__init__.py +0 -10
  80. autogluon/timeseries/models/chronos/pipeline/base.py +0 -160
  81. autogluon/timeseries/models/chronos/pipeline/chronos.py +0 -544
  82. autogluon/timeseries/models/chronos/pipeline/chronos_bolt.py +0 -530
  83. autogluon/timeseries/models/presets.py +0 -358
  84. autogluon.timeseries-1.3.2b20250712-py3.9-nspkg.pth +0 -1
  85. autogluon.timeseries-1.3.2b20250712.dist-info/RECORD +0 -71
  86. {autogluon.timeseries-1.3.2b20250712.dist-info → autogluon_timeseries-1.4.1b20251116.dist-info/licenses}/LICENSE +0 -0
  87. {autogluon.timeseries-1.3.2b20250712.dist-info → autogluon_timeseries-1.4.1b20251116.dist-info/licenses}/NOTICE +0 -0
  88. {autogluon.timeseries-1.3.2b20250712.dist-info → autogluon_timeseries-1.4.1b20251116.dist-info}/namespace_packages.txt +0 -0
  89. {autogluon.timeseries-1.3.2b20250712.dist-info → autogluon_timeseries-1.4.1b20251116.dist-info}/top_level.txt +0 -0
  90. {autogluon.timeseries-1.3.2b20250712.dist-info → autogluon_timeseries-1.4.1b20251116.dist-info}/zip-safe +0 -0
@@ -1,7 +1,7 @@
1
1
  import logging
2
2
  import time
3
3
  from multiprocessing import TimeoutError
4
- from typing import Any, Callable, Dict, List, Optional, Tuple, Union
4
+ from typing import Any, Callable, Optional, Union
5
5
 
6
6
  import numpy as np
7
7
  import pandas as pd
@@ -9,7 +9,7 @@ from joblib import Parallel, cpu_count, delayed
9
9
  from scipy.stats import norm
10
10
 
11
11
  from autogluon.core.utils.exceptions import TimeLimitExceeded
12
- from autogluon.timeseries.dataset.ts_dataframe import ITEMID, TimeSeriesDataFrame
12
+ from autogluon.timeseries.dataset import TimeSeriesDataFrame
13
13
  from autogluon.timeseries.metrics import TimeSeriesScorer
14
14
  from autogluon.timeseries.models.abstract import AbstractTimeSeriesModel
15
15
  from autogluon.timeseries.utils.datetime import get_seasonality
@@ -29,17 +29,17 @@ class AbstractLocalModel(AbstractTimeSeriesModel):
29
29
 
30
30
  Attributes
31
31
  ----------
32
- allowed_local_model_args : List[str]
32
+ allowed_local_model_args
33
33
  Argument that can be passed to the underlying local model.
34
- default_max_ts_length : Optional[int]
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 : int
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: List[str] = []
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[Dict[str, Any]] = None,
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: Dict[str, Any]
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) -> List[str]:
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
- ) -> Tuple[TimeSeriesDataFrame, Optional[TimeSeriesDataFrame]]:
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: Dict[str, Any]) -> Dict[str, Any]:
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:
@@ -145,7 +145,7 @@ class AbstractLocalModel(AbstractTimeSeriesModel):
145
145
  data = data.slice_by_timestep(-max_ts_length, None)
146
146
 
147
147
  indptr = data.get_indptr()
148
- target_series = data[self.target].droplevel(level=ITEMID)
148
+ target_series = data[self.target].droplevel(level=TimeSeriesDataFrame.ITEMID)
149
149
  all_series = (target_series[indptr[i] : indptr[i + 1]] for i in range(len(indptr) - 1))
150
150
 
151
151
  # timeout ensures that no individual job takes longer than time_limit
@@ -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
- ) -> Tuple[pd.DataFrame, bool]:
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: List[float], seasonal_period: int
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
 
@@ -24,6 +24,7 @@ class NaiveModel(AbstractLocalModel):
24
24
  When set to -1, all CPU cores are used.
25
25
  """
26
26
 
27
+ ag_priority = 100
27
28
  allowed_local_model_args = ["seasonal_period"]
28
29
 
29
30
  def _predict_with_local_model(
@@ -66,6 +67,7 @@ class SeasonalNaiveModel(AbstractLocalModel):
66
67
  When set to -1, all CPU cores are used.
67
68
  """
68
69
 
70
+ ag_priority = 100
69
71
  allowed_local_model_args = ["seasonal_period"]
70
72
 
71
73
  def _predict_with_local_model(
@@ -99,6 +101,7 @@ class AverageModel(AbstractLocalModel):
99
101
  This significantly speeds up fitting and usually leads to no change in accuracy.
100
102
  """
101
103
 
104
+ ag_priority = 100
102
105
  allowed_local_model_args = ["seasonal_period"]
103
106
  default_max_ts_length = None
104
107
 
@@ -138,6 +141,7 @@ class SeasonalAverageModel(AbstractLocalModel):
138
141
  This significantly speeds up fitting and usually leads to no change in accuracy.
139
142
  """
140
143
 
144
+ ag_priority = 100
141
145
  allowed_local_model_args = ["seasonal_period"]
142
146
  default_max_ts_length = None
143
147
 
@@ -36,6 +36,7 @@ class NPTSModel(AbstractLocalModel):
36
36
  This significantly speeds up fitting and usually leads to no change in accuracy.
37
37
  """
38
38
 
39
+ ag_priority = 80
39
40
  allowed_local_model_args = [
40
41
  "kernel_type",
41
42
  "exp_kernel_weights",
@@ -1,5 +1,5 @@
1
1
  import logging
2
- from typing import Any, Dict, Optional, Type
2
+ from typing import Any, Optional, Type
3
3
 
4
4
  import numpy as np
5
5
  import pandas as pd
@@ -14,7 +14,7 @@ class AbstractStatsForecastModel(AbstractLocalModel):
14
14
 
15
15
  init_time_in_seconds = 15 # numba compilation for the first run
16
16
 
17
- def _update_local_model_args(self, local_model_args: Dict[str, Any]) -> Dict[str, Any]:
17
+ def _update_local_model_args(self, local_model_args: dict[str, Any]) -> dict[str, Any]:
18
18
  seasonal_period = local_model_args.pop("seasonal_period")
19
19
  local_model_args["season_length"] = seasonal_period
20
20
  return local_model_args
@@ -22,7 +22,7 @@ class AbstractStatsForecastModel(AbstractLocalModel):
22
22
  def _get_model_type(self, variant: Optional[str] = None) -> Type:
23
23
  raise NotImplementedError
24
24
 
25
- def _get_local_model(self, local_model_args: Dict):
25
+ def _get_local_model(self, local_model_args: dict):
26
26
  local_model_args = local_model_args.copy()
27
27
  variant = local_model_args.pop("variant", None)
28
28
  model_type = self._get_model_type(variant)
@@ -31,7 +31,7 @@ class AbstractStatsForecastModel(AbstractLocalModel):
31
31
  def _get_point_forecast(
32
32
  self,
33
33
  time_series: pd.Series,
34
- local_model_args: Dict,
34
+ local_model_args: dict,
35
35
  ) -> np.ndarray:
36
36
  return self._get_local_model(local_model_args).forecast(
37
37
  h=self.prediction_length, y=time_series.values.ravel()
@@ -133,6 +133,7 @@ class AutoARIMAModel(AbstractProbabilisticStatsForecastModel):
133
133
  This significantly speeds up fitting and usually leads to no change in accuracy.
134
134
  """
135
135
 
136
+ ag_priority = 60
136
137
  init_time_in_seconds = 0 # C++ models require no compilation
137
138
  allowed_local_model_args = [
138
139
  "d",
@@ -175,9 +176,9 @@ class ARIMAModel(AbstractProbabilisticStatsForecastModel):
175
176
 
176
177
  Other Parameters
177
178
  ----------------
178
- order: Tuple[int, int, int], default = (1, 1, 1)
179
+ order: tuple[int, int, int], default = (1, 1, 1)
179
180
  The (p, d, q) order of the model for the number of AR parameters, differences, and MA parameters to use.
180
- seasonal_order: Tuple[int, int, int], default = (0, 0, 0)
181
+ seasonal_order: tuple[int, int, int], default = (0, 0, 0)
181
182
  The (P, D, Q) parameters of the seasonal ARIMA model. Setting to (0, 0, 0) disables seasonality.
182
183
  include_mean : bool, default = True
183
184
  Should the ARIMA model include a mean term?
@@ -193,7 +194,7 @@ class ARIMAModel(AbstractProbabilisticStatsForecastModel):
193
194
  method : {"CSS-ML", "CSS", "ML"}, default = "CSS-ML"
194
195
  Fitting method: CSS (conditional sum of squares), ML (maximum likelihood), CSS-ML (initialize with CSS, then
195
196
  optimize with ML).
196
- fixed : Dict[str, float], optional
197
+ fixed : dict[str, float], optional
197
198
  Dictionary containing fixed coefficients for the ARIMA model.
198
199
  seasonal_period : int or None, default = None
199
200
  Number of time steps in a complete seasonal cycle for seasonal models. For example, 7 for daily data with a
@@ -211,6 +212,7 @@ class ARIMAModel(AbstractProbabilisticStatsForecastModel):
211
212
  This significantly speeds up fitting and usually leads to no change in accuracy.
212
213
  """
213
214
 
215
+ ag_priority = 10
214
216
  init_time_in_seconds = 0 # C++ models require no compilation
215
217
  allowed_local_model_args = [
216
218
  "order",
@@ -267,6 +269,7 @@ class AutoETSModel(AbstractProbabilisticStatsForecastModel):
267
269
  This significantly speeds up fitting and usually leads to no change in accuracy.
268
270
  """
269
271
 
272
+ ag_priority = 70
270
273
  init_time_in_seconds = 0 # C++ models require no compilation
271
274
  allowed_local_model_args = [
272
275
  "damped",
@@ -330,6 +333,8 @@ class ETSModel(AutoETSModel):
330
333
  This significantly speeds up fitting and usually leads to no change in accuracy.
331
334
  """
332
335
 
336
+ ag_priority = 80
337
+
333
338
  def _update_local_model_args(self, local_model_args: dict) -> dict:
334
339
  local_model_args = super()._update_local_model_args(local_model_args)
335
340
  local_model_args.setdefault("model", "AAA")
@@ -369,6 +374,7 @@ class DynamicOptimizedThetaModel(AbstractProbabilisticStatsForecastModel):
369
374
  This significantly speeds up fitting and usually leads to no change in accuracy.
370
375
  """
371
376
 
377
+ ag_priority = 75
372
378
  allowed_local_model_args = [
373
379
  "decomposition_type",
374
380
  "seasonal_period",
@@ -413,6 +419,7 @@ class ThetaModel(AbstractProbabilisticStatsForecastModel):
413
419
  This significantly speeds up fitting and usually leads to no change in accuracy.
414
420
  """
415
421
 
422
+ ag_priority = 75
416
423
  allowed_local_model_args = [
417
424
  "decomposition_type",
418
425
  "seasonal_period",
@@ -442,7 +449,7 @@ class AbstractConformalizedStatsForecastModel(AbstractStatsForecastModel):
442
449
  def _get_nonconformity_scores(
443
450
  self,
444
451
  time_series: pd.Series,
445
- local_model_args: Dict,
452
+ local_model_args: dict,
446
453
  ) -> np.ndarray:
447
454
  h = self.prediction_length
448
455
  y = time_series.values.ravel()
@@ -533,6 +540,7 @@ class AutoCESModel(AbstractProbabilisticStatsForecastModel):
533
540
  This significantly speeds up fitting and usually leads to no change in accuracy.
534
541
  """
535
542
 
543
+ ag_priority = 10
536
544
  allowed_local_model_args = [
537
545
  "model",
538
546
  "seasonal_period",
@@ -548,7 +556,7 @@ class AutoCESModel(AbstractProbabilisticStatsForecastModel):
548
556
  local_model_args.setdefault("model", "Z")
549
557
  return local_model_args
550
558
 
551
- def _get_point_forecast(self, time_series: pd.Series, local_model_args: Dict):
559
+ def _get_point_forecast(self, time_series: pd.Series, local_model_args: dict):
552
560
  # Disable seasonality if time series too short for chosen season_length or season_length == 1,
553
561
  # otherwise model will crash
554
562
  if len(time_series) < 5:
@@ -560,7 +568,7 @@ class AutoCESModel(AbstractProbabilisticStatsForecastModel):
560
568
 
561
569
 
562
570
  class AbstractStatsForecastIntermittentDemandModel(AbstractConformalizedStatsForecastModel):
563
- def _update_local_model_args(self, local_model_args: Dict[str, Any]) -> Dict[str, Any]:
571
+ def _update_local_model_args(self, local_model_args: dict[str, Any]) -> dict[str, Any]:
564
572
  _ = local_model_args.pop("seasonal_period")
565
573
  return local_model_args
566
574
 
@@ -600,6 +608,8 @@ class ADIDAModel(AbstractStatsForecastIntermittentDemandModel):
600
608
  This significantly speeds up fitting and usually leads to no change in accuracy.
601
609
  """
602
610
 
611
+ ag_priority = 10
612
+
603
613
  def _get_model_type(self, variant: Optional[str] = None):
604
614
  from statsforecast.models import ADIDA
605
615
 
@@ -622,9 +632,9 @@ class CrostonModel(AbstractStatsForecastIntermittentDemandModel):
622
632
  variant : {"SBA", "classic", "optimized"}, default = "SBA"
623
633
  Variant of the Croston model that is used. Available options:
624
634
 
625
- - `"classic"` - variant of the Croston method where the smoothing parameter is fixed to 0.1 (based on `statsforecast.models.CrostonClassic <https://nixtla.mintlify.app/statsforecast/docs/models/crostonclassic.html>`_)
626
- - `"SBA"` - variant of the Croston method based on Syntetos-Boylan Approximation (based on `statsforecast.models.CrostonSBA <https://nixtla.mintlify.app/statsforecast/docs/models/crostonsba.html>`_)
627
- - `"optimized"` - variant of the Croston method where the smoothing parameter is optimized (based on `statsforecast.models.CrostonOptimized <https://nixtla.mintlify.app/statsforecast/docs/models/crostonoptimized.html>`_)
635
+ - ``"classic"`` - variant of the Croston method where the smoothing parameter is fixed to 0.1 (based on `statsforecast.models.CrostonClassic <https://nixtla.mintlify.app/statsforecast/docs/models/crostonclassic.html>`_)
636
+ - ``"SBA"`` - variant of the Croston method based on Syntetos-Boylan Approximation (based on `statsforecast.models.CrostonSBA <https://nixtla.mintlify.app/statsforecast/docs/models/crostonsba.html>`_)
637
+ - ``"optimized"`` - variant of the Croston method where the smoothing parameter is optimized (based on `statsforecast.models.CrostonOptimized <https://nixtla.mintlify.app/statsforecast/docs/models/crostonoptimized.html>`_)
628
638
 
629
639
  n_jobs : int or float, default = joblib.cpu_count(only_physical_cores=True)
630
640
  Number of CPU cores used to fit the models in parallel.
@@ -636,6 +646,8 @@ class CrostonModel(AbstractStatsForecastIntermittentDemandModel):
636
646
  This significantly speeds up fitting and usually leads to no change in accuracy.
637
647
  """
638
648
 
649
+ ag_model_aliases = ["CrostonSBA"]
650
+ ag_priority = 80
639
651
  allowed_local_model_args = [
640
652
  "variant",
641
653
  ]
@@ -688,6 +700,8 @@ class IMAPAModel(AbstractStatsForecastIntermittentDemandModel):
688
700
  This significantly speeds up fitting and usually leads to no change in accuracy.
689
701
  """
690
702
 
703
+ ag_priority = 10
704
+
691
705
  def _get_model_type(self, variant: Optional[str] = None):
692
706
  from statsforecast.models import IMAPA
693
707
 
@@ -710,6 +724,8 @@ class ZeroModel(AbstractStatsForecastIntermittentDemandModel):
710
724
  This significantly speeds up fitting and usually leads to no change in accuracy.
711
725
  """
712
726
 
727
+ ag_priority = 100
728
+
713
729
  def _get_model_type(self, variant: Optional[str] = None):
714
730
  # ZeroModel does not depend on a StatsForecast implementation
715
731
  raise NotImplementedError
@@ -717,6 +733,6 @@ class ZeroModel(AbstractStatsForecastIntermittentDemandModel):
717
733
  def _get_point_forecast(
718
734
  self,
719
735
  time_series: pd.Series,
720
- local_model_args: Dict,
736
+ local_model_args: dict,
721
737
  ):
722
738
  return np.zeros(self.prediction_length)
@@ -4,12 +4,13 @@ import logging
4
4
  import math
5
5
  import os
6
6
  import time
7
- from typing import Any, Dict, Optional, Type, Union
7
+ from typing import Any, Optional, Type, Union
8
8
 
9
9
  import numpy as np
10
+ from typing_extensions import Self
10
11
 
11
12
  import autogluon.core as ag
12
- from autogluon.timeseries.dataset.ts_dataframe import TimeSeriesDataFrame
13
+ from autogluon.timeseries.dataset import TimeSeriesDataFrame
13
14
  from autogluon.timeseries.models.abstract import AbstractTimeSeriesModel
14
15
  from autogluon.timeseries.models.local.abstract_local_model import AbstractLocalModel
15
16
  from autogluon.timeseries.splitter import AbstractWindowSplitter, ExpandingWindowSplitter
@@ -25,10 +26,10 @@ class MultiWindowBacktestingModel(AbstractTimeSeriesModel):
25
26
 
26
27
  Parameters
27
28
  ----------
28
- model_base : Union[AbstractTimeSeriesModel, Type[AbstractTimeSeriesModel]]
29
+ model_base
29
30
  The base model to repeatedly train. If a AbstractTimeSeriesModel class, then also provide model_base_kwargs
30
31
  which will be used to initialize the model via model_base(**model_base_kwargs).
31
- model_base_kwargs : Optional[Dict[str, any]], default = None
32
+ model_base_kwargs
32
33
  kwargs used to initialize model_base if model_base is a class.
33
34
  """
34
35
 
@@ -38,7 +39,7 @@ class MultiWindowBacktestingModel(AbstractTimeSeriesModel):
38
39
  def __init__(
39
40
  self,
40
41
  model_base: Union[AbstractTimeSeriesModel, Type[AbstractTimeSeriesModel]],
41
- model_base_kwargs: Optional[Dict[str, Any]] = None,
42
+ model_base_kwargs: Optional[dict[str, Any]] = None,
42
43
  **kwargs,
43
44
  ):
44
45
  if inspect.isclass(model_base) and issubclass(model_base, AbstractTimeSeriesModel):
@@ -73,10 +74,6 @@ class MultiWindowBacktestingModel(AbstractTimeSeriesModel):
73
74
  def supports_past_covariates(self) -> bool:
74
75
  return self.model_base.supports_past_covariates
75
76
 
76
- @property
77
- def supports_cat_covariates(self) -> bool:
78
- return self.model_base.supports_cat_covariates
79
-
80
77
  def _get_model_base(self):
81
78
  return self.model_base
82
79
 
@@ -86,15 +83,18 @@ class MultiWindowBacktestingModel(AbstractTimeSeriesModel):
86
83
  def _is_gpu_available(self) -> bool:
87
84
  return self._get_model_base()._is_gpu_available()
88
85
 
89
- def get_minimum_resources(self, is_gpu_available: bool = False) -> bool:
86
+ def get_minimum_resources(self, is_gpu_available: bool = False) -> dict[str, Union[int, float]]:
90
87
  return self._get_model_base().get_minimum_resources(is_gpu_available)
91
88
 
92
89
  def _fit(
93
90
  self,
94
91
  train_data: TimeSeriesDataFrame,
95
92
  val_data: Optional[TimeSeriesDataFrame] = None,
96
- time_limit: Optional[int] = None,
97
- val_splitter: AbstractWindowSplitter = None,
93
+ time_limit: Optional[float] = None,
94
+ num_cpus: Optional[int] = None,
95
+ num_gpus: Optional[int] = None,
96
+ verbosity: int = 2,
97
+ val_splitter: Optional[AbstractWindowSplitter] = None,
98
98
  refit_every_n_windows: Optional[int] = 1,
99
99
  **kwargs,
100
100
  ):
@@ -111,11 +111,15 @@ class MultiWindowBacktestingModel(AbstractTimeSeriesModel):
111
111
 
112
112
  oof_predictions_per_window = []
113
113
  global_fit_start_time = time.time()
114
+ model: Optional[AbstractTimeSeriesModel] = None
114
115
 
115
116
  for window_index, (train_fold, val_fold) in enumerate(val_splitter.split(train_data)):
116
117
  logger.debug(f"\tWindow {window_index}")
118
+
117
119
  # refit_this_window is always True for the 0th window
118
120
  refit_this_window = window_index % refit_every_n_windows == 0
121
+ assert window_index != 0 or refit_this_window
122
+
119
123
  if time_limit is None:
120
124
  time_left_for_window = None
121
125
  else:
@@ -148,6 +152,7 @@ class MultiWindowBacktestingModel(AbstractTimeSeriesModel):
148
152
  else:
149
153
  time_left_for_prediction = time_limit - (time.time() - global_fit_start_time)
150
154
 
155
+ assert model is not None
151
156
  model.score_and_cache_oof(
152
157
  val_fold, store_val_score=True, store_predict_time=True, time_limit=time_left_for_prediction
153
158
  )
@@ -172,11 +177,13 @@ class MultiWindowBacktestingModel(AbstractTimeSeriesModel):
172
177
 
173
178
  # Only the model trained on most recent data is saved & used for prediction
174
179
  self.most_recent_model = model
175
- self.most_recent_model_folder = most_recent_refit_window
180
+ assert self.most_recent_model is not None
181
+
182
+ self.most_recent_model_folder = most_recent_refit_window # type: ignore
176
183
  self.predict_time = self.most_recent_model.predict_time
177
- self.fit_time = time.time() - global_fit_start_time - self.predict_time
184
+ self.fit_time = time.time() - global_fit_start_time - self.predict_time # type: ignore
178
185
  self._oof_predictions = oof_predictions_per_window
179
- self.val_score = np.mean([info["val_score"] for info in self.info_per_val_window])
186
+ self.val_score = np.mean([info["val_score"] for info in self.info_per_val_window]) # type: ignore
180
187
 
181
188
  def get_info(self) -> dict:
182
189
  info = super().get_info()
@@ -227,7 +234,7 @@ class MultiWindowBacktestingModel(AbstractTimeSeriesModel):
227
234
  train_fn_kwargs["init_params"]["model_base_kwargs"] = self.get_params()
228
235
  return train_fn_kwargs
229
236
 
230
- def save(self, path: str = None, verbose=True) -> str:
237
+ def save(self, path: Optional[str] = None, verbose: bool = True) -> str:
231
238
  most_recent_model = self.most_recent_model
232
239
  self.most_recent_model = None
233
240
  save_path = super().save(path, verbose)
@@ -238,32 +245,36 @@ class MultiWindowBacktestingModel(AbstractTimeSeriesModel):
238
245
  most_recent_model.save()
239
246
  return save_path
240
247
 
241
- def persist(self):
248
+ def persist(self) -> Self:
242
249
  if self.most_recent_model is None:
243
250
  raise ValueError(f"{self.name} must be fit before persisting")
244
251
  self.most_recent_model.persist()
252
+ return self
245
253
 
246
254
  @classmethod
247
255
  def load(
248
256
  cls, path: str, reset_paths: bool = True, load_oof: bool = False, verbose: bool = True
249
257
  ) -> AbstractTimeSeriesModel:
250
258
  model = super().load(path=path, reset_paths=reset_paths, load_oof=load_oof, verbose=verbose)
251
- most_recent_model_path = os.path.join(model.path, model.most_recent_model_folder)
252
- model.most_recent_model = model.model_base_type.load(
253
- most_recent_model_path,
254
- reset_paths=reset_paths,
255
- verbose=verbose,
256
- )
259
+ if model.most_recent_model_folder is not None:
260
+ most_recent_model_path = os.path.join(model.path, model.most_recent_model_folder)
261
+ model.most_recent_model = model.model_base_type.load(
262
+ most_recent_model_path,
263
+ reset_paths=reset_paths,
264
+ verbose=verbose,
265
+ )
257
266
  return model
258
267
 
259
268
  def convert_to_refit_full_template(self) -> AbstractTimeSeriesModel:
260
269
  # refit_model is an instance of base model type, not MultiWindowBacktestingModel
270
+ assert self.most_recent_model is not None, "Most recent model is None. Model must be fit first."
261
271
  refit_model = self.most_recent_model.convert_to_refit_full_template()
262
272
  refit_model.rename(self.name + ag.constants.REFIT_FULL_SUFFIX)
263
273
  return refit_model
264
274
 
265
275
  def convert_to_refit_full_via_copy(self) -> AbstractTimeSeriesModel:
266
276
  # refit_model is an instance of base model type, not MultiWindowBacktestingModel
277
+ assert self.most_recent_model is not None, "Most recent model is None. Model must be fit first."
267
278
  refit_model = self.most_recent_model.convert_to_refit_full_via_copy()
268
279
  refit_model.rename(self.name + ag.constants.REFIT_FULL_SUFFIX)
269
280
  return refit_model
@@ -0,0 +1,65 @@
1
+ from abc import ABCMeta
2
+ from dataclasses import dataclass
3
+ from inspect import isabstract
4
+ from typing import Union
5
+
6
+
7
+ @dataclass
8
+ class ModelRecord:
9
+ model_class: type
10
+ ag_priority: int
11
+
12
+
13
+ class ModelRegistry(ABCMeta):
14
+ """Registry metaclass for time series models. Ensures that TimeSeriesModel classes
15
+ which implement this metaclass are automatically registered, in order to centralize
16
+ access to model types.
17
+
18
+ See, https://github.com/faif/python-patterns.
19
+ """
20
+
21
+ REGISTRY: dict[str, ModelRecord] = {}
22
+
23
+ def __new__(cls, name, bases, attrs):
24
+ new_cls = super().__new__(cls, name, bases, attrs)
25
+
26
+ if name is not None and not isabstract(new_cls):
27
+ record = ModelRecord(
28
+ model_class=new_cls,
29
+ ag_priority=getattr(new_cls, "ag_priority", 0),
30
+ )
31
+ cls._add(name.removesuffix("Model"), record)
32
+
33
+ # if the class provides additional aliases, register them too
34
+ if aliases := attrs.get("ag_model_aliases"):
35
+ for alias in aliases:
36
+ cls._add(alias, record)
37
+
38
+ return new_cls
39
+
40
+ @classmethod
41
+ def _add(cls, alias: str, record: ModelRecord) -> None:
42
+ if alias in cls.REGISTRY:
43
+ raise ValueError(f"You are trying to define a new model with {alias}, but this model already exists.")
44
+ cls.REGISTRY[alias] = record
45
+
46
+ @classmethod
47
+ def _get_model_record(cls, alias: Union[str, type]) -> ModelRecord:
48
+ if isinstance(alias, type):
49
+ alias = alias.__name__
50
+ alias = alias.removesuffix("Model")
51
+ if alias not in cls.REGISTRY:
52
+ raise ValueError(f"Unknown model: {alias}, available models are: {cls.available_aliases()}")
53
+ return cls.REGISTRY[alias]
54
+
55
+ @classmethod
56
+ def get_model_class(cls, alias: Union[str, type]) -> type:
57
+ return cls._get_model_record(alias).model_class
58
+
59
+ @classmethod
60
+ def get_model_priority(cls, alias: Union[str, type]) -> int:
61
+ return cls._get_model_record(alias).ag_priority
62
+
63
+ @classmethod
64
+ def available_aliases(cls) -> list[str]:
65
+ return sorted(cls.REGISTRY.keys())
@@ -0,0 +1,3 @@
1
+ from .model import TotoModel
2
+
3
+ __all__ = ["TotoModel"]
@@ -0,0 +1,9 @@
1
+ from .backbone import TotoBackbone
2
+ from .dataset import MaskedTimeseries
3
+ from .forecaster import TotoForecaster
4
+
5
+ __all__ = [
6
+ "MaskedTimeseries",
7
+ "TotoBackbone",
8
+ "TotoForecaster",
9
+ ]
@@ -0,0 +1,3 @@
1
+ from .backbone import TotoBackbone
2
+
3
+ __all__ = ["TotoBackbone"]