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
@@ -2,29 +2,29 @@ import logging
2
2
  import math
3
3
  import os
4
4
  import time
5
- from typing import Any, Callable, Dict, List, Optional, Type
5
+ from typing import Any, Callable, Literal, Optional, Type
6
6
 
7
7
  import numpy as np
8
8
  import pandas as pd
9
+ import scipy.stats
9
10
  from joblib import Parallel, cpu_count, delayed
10
11
 
12
+ from autogluon.common.loaders import load_pkl
13
+ from autogluon.common.savers import save_pkl
11
14
  from autogluon.common.utils.pandas_utils import get_approximate_df_mem_usage
12
15
  from autogluon.common.utils.resource_utils import ResourceManager
13
- from autogluon.core.constants import QUANTILE
16
+ from autogluon.core.constants import QUANTILE, REGRESSION
14
17
  from autogluon.tabular.models import AbstractModel as AbstractTabularModel
15
18
  from autogluon.tabular.registry import ag_model_registry
16
19
  from autogluon.timeseries import TimeSeriesDataFrame
17
- from autogluon.timeseries.dataset.ts_dataframe import ITEMID, TIMESTAMP
18
20
  from autogluon.timeseries.models.abstract import AbstractTimeSeriesModel
19
21
  from autogluon.timeseries.utils.datetime import get_lags_for_frequency, get_time_features_for_frequency
20
- from autogluon.timeseries.utils.warning_filters import set_loggers_level
22
+ from autogluon.timeseries.utils.warning_filters import set_loggers_level, warning_filter
21
23
 
22
24
  from .utils import MLF_ITEMID, MLF_TARGET, MLF_TIMESTAMP
23
25
 
24
26
  logger = logging.getLogger(__name__)
25
27
 
26
- DUMMY_FREQ = "D"
27
-
28
28
 
29
29
  class PerStepTabularModel(AbstractTimeSeriesModel):
30
30
  """Fit a separate tabular regression model for each time step in the forecast horizon.
@@ -36,43 +36,53 @@ class PerStepTabularModel(AbstractTimeSeriesModel):
36
36
  - known covariates (if available)
37
37
  - static features of each item (if available)
38
38
 
39
- This model is typically much slower to fit compared to other tabular forecasting models.
39
+ This model is typically slower to fit compared to other tabular forecasting models.
40
+
41
+ If ``eval_metric.needs_quantile``, the tabular regression models will be trained with ``"quantile"`` problem type.
42
+ Otherwise, the models will be trained with ``"regression"`` problem type, and dummy quantiles will be
43
+ obtained by assuming that the residuals follow zero-mean normal distribution.
40
44
 
41
45
  This model uses `mlforecast <https://github.com/Nixtla/mlforecast>`_ under the hood for efficient preprocessing,
42
- but the implementation of the per-step forecasting strategy is different from the `max_horizon` in `mlforecast`.
46
+ but the implementation of the per-step forecasting strategy is different from the ``max_horizon`` in ``mlforecast``.
43
47
 
44
48
 
45
49
  Other Parameters
46
50
  ----------------
47
- trailing_lags : List[int], default = None
51
+ trailing_lags : list[int], default = None
48
52
  Trailing window lags of the target that will be used as features for predictions.
49
- Trailing lags are shifted per forecast step: model for step `h` uses `[lag+h for lag in trailing_lags]`.
50
- If None, defaults to [1, 2, ..., 12].
51
- seasonal_lags: List[int], default = None
53
+ Trailing lags are shifted per forecast step: model for step ``h`` uses ``[lag+h for lag in trailing_lags]``.
54
+ If None, defaults to ``[1, 2, ..., 12]``.
55
+ seasonal_lags : list[int], default = None
52
56
  Seasonal lags of the target used as features. Unlike trailing lags, seasonal lags are not shifted
53
- but filtered by availability: model for step `h` uses `[lag for lag in seasonal_lags if lag > h]`.
57
+ but filtered by availability: model for step ``h`` uses ``[lag for lag in seasonal_lags if lag > h]``.
54
58
  If None, determined automatically based on data frequency.
55
- date_features : List[Union[str, Callable]], default = None
59
+ date_features : list[Union[str, Callable]], default = None
56
60
  Features computed from the dates. Can be pandas date attributes or functions that will take the dates as input.
57
61
  If None, will be determined automatically based on the frequency of the data.
58
62
  target_scaler : {"standard", "mean_abs", "min_max", "robust", None}, default = "mean_abs"
59
63
  Scaling applied to each time series.
60
64
  model_name : str, default = "CAT"
61
- Name of the tabular regression model. See `autogluon.tabular.registry.ag_model_registry` or
65
+ Name of the tabular regression model. See ``autogluon.tabular.registry.ag_model_registry`` or
62
66
  `the documentation <https://auto.gluon.ai/stable/api/autogluon.tabular.models.html>`_ for the list of available
63
67
  tabular models.
64
- model_hyperparameters : Dict[str, Any], optional
68
+ model_hyperparameters : dict[str, Any], optional
65
69
  Hyperparameters passed to the tabular regression model.
70
+ validation_fraction : float or None, default = 0.1
71
+ Fraction of the training data to use for validation. If None or 0.0, no validation set is created.
72
+ Validation set contains the most recent observations (chronologically). Must be between 0.0 and 1.0.
66
73
  max_num_items : int or None, default = 20_000
67
74
  If not None, the model will randomly select this many time series for training and validation.
68
75
  max_num_samples : int or None, default = 1_000_000
69
- If not None, training dataset passed to TabularPredictor will contain at most this many rows (starting from the
70
- end of each time series).
76
+ If not None, training dataset passed to the tabular regression model will contain at most this many rows
77
+ (starting from the end of each time series).
71
78
  n_jobs : int or None, default = None
72
79
  Number of parallel jobs for fitting models across forecast horizons.
73
80
  If None, automatically determined based on available memory to prevent OOM errors.
74
81
  """
75
82
 
83
+ ag_priority = 70
84
+ _dummy_freq = "D"
85
+
76
86
  def __init__(self, *args, **kwargs):
77
87
  super().__init__(*args, **kwargs)
78
88
  # We save the relative paths to per-step models. Each worker process independently saves/loads the model.
@@ -83,11 +93,11 @@ class PerStepTabularModel(AbstractTimeSeriesModel):
83
93
  self._date_features: list[Callable]
84
94
  self._model_cls: Type[AbstractTabularModel]
85
95
  self._n_jobs: int
86
- self._non_boolean_real_covariates: List[str] = []
96
+ self._non_boolean_real_covariates: list[str] = []
87
97
  self._max_ts_length: Optional[int] = None
88
98
 
89
99
  @property
90
- def allowed_hyperparameters(self) -> List[str]:
100
+ def allowed_hyperparameters(self) -> list[str]:
91
101
  # TODO: Differencing is currently not supported because it greatly complicates the preprocessing logic
92
102
  return super().allowed_hyperparameters + [
93
103
  "trailing_lags",
@@ -104,7 +114,11 @@ class PerStepTabularModel(AbstractTimeSeriesModel):
104
114
 
105
115
  @property
106
116
  def _ag_to_nixtla(self) -> dict:
107
- return {self.target: MLF_TARGET, ITEMID: MLF_ITEMID, TIMESTAMP: MLF_TIMESTAMP}
117
+ return {
118
+ self.target: MLF_TARGET,
119
+ TimeSeriesDataFrame.ITEMID: MLF_ITEMID,
120
+ TimeSeriesDataFrame.TIMESTAMP: MLF_TIMESTAMP,
121
+ }
108
122
 
109
123
  def _get_default_hyperparameters(self):
110
124
  return {
@@ -116,13 +130,16 @@ class PerStepTabularModel(AbstractTimeSeriesModel):
116
130
  "max_num_items": 20_000,
117
131
  }
118
132
 
119
- @staticmethod
133
+ @classmethod
120
134
  def _fit_single_model(
135
+ cls,
121
136
  train_df: pd.DataFrame,
122
137
  path_root: str,
123
138
  step: int,
124
139
  model_cls: Type[AbstractTabularModel],
125
140
  model_hyperparameters: dict,
141
+ problem_type: Literal["quantile", "regression"],
142
+ eval_metric: str,
126
143
  validation_fraction: Optional[float],
127
144
  quantile_levels: list[float],
128
145
  lags: list[int],
@@ -135,13 +152,15 @@ class PerStepTabularModel(AbstractTimeSeriesModel):
135
152
 
136
153
  start_time = time.monotonic()
137
154
 
138
- mlf = MLForecast(models=[], freq=DUMMY_FREQ, lags=lags, date_features=date_features)
155
+ mlf = MLForecast(models=[], freq=cls._dummy_freq, lags=lags, date_features=date_features)
139
156
 
140
- features_df = mlf.preprocess(train_df, static_features=[], dropna=False)
157
+ with warning_filter():
158
+ features_df = mlf.preprocess(train_df, static_features=[], dropna=False)
141
159
  del train_df
142
160
  del mlf
143
161
  # Sort chronologically for efficient train/test split
144
162
  features_df = features_df.sort_values(by=MLF_TIMESTAMP)
163
+ item_ids = features_df[MLF_ITEMID]
145
164
  X = features_df.drop(columns=[MLF_ITEMID, MLF_TIMESTAMP, MLF_TARGET])
146
165
  y = features_df[MLF_TARGET]
147
166
  del features_df
@@ -162,14 +181,16 @@ class PerStepTabularModel(AbstractTimeSeriesModel):
162
181
 
163
182
  elapsed = time.monotonic() - start_time
164
183
  time_left = time_limit - elapsed if time_limit is not None else None
184
+ if problem_type == QUANTILE:
185
+ model_hyperparameters = model_hyperparameters | {"ag.quantile_levels": quantile_levels}
165
186
  try:
166
187
  with set_loggers_level(regex=r"^autogluon.tabular.*", level=logging.ERROR):
167
188
  model = model_cls(
168
189
  path=os.path.join(path_root, f"step_{step}"),
169
190
  name=model_cls.__name__, # explicitly provide name to avoid warnings
170
- problem_type=QUANTILE,
171
- eval_metric="pinball_loss",
172
- hyperparameters={**model_hyperparameters, "ag.quantile_levels": quantile_levels},
191
+ problem_type=problem_type,
192
+ eval_metric=eval_metric,
193
+ hyperparameters=model_hyperparameters,
173
194
  )
174
195
  model.fit(
175
196
  X=X,
@@ -184,6 +205,9 @@ class PerStepTabularModel(AbstractTimeSeriesModel):
184
205
  except Exception as e:
185
206
  raise RuntimeError(f"Failed when fitting model for {step=}") from e
186
207
  model.save()
208
+ if problem_type == REGRESSION:
209
+ residuals_std = pd.Series((model.predict(X) - y) ** 2).groupby(item_ids).mean() ** 0.5
210
+ save_pkl.save(cls._get_residuals_std_path(model.path), residuals_std)
187
211
  relative_path = os.path.relpath(path=model.path, start=path_root)
188
212
  return relative_path
189
213
 
@@ -225,7 +249,7 @@ class PerStepTabularModel(AbstractTimeSeriesModel):
225
249
  self._non_boolean_real_covariates.append(col)
226
250
 
227
251
  if len(self._non_boolean_real_covariates) > 0:
228
- item_ids = data.index.get_level_values(level=ITEMID)
252
+ item_ids = data.index.get_level_values(level=TimeSeriesDataFrame.ITEMID)
229
253
  scale_per_column: dict[str, pd.Series] = {}
230
254
  columns_grouped = data[self._non_boolean_real_covariates].abs().groupby(item_ids)
231
255
  for col in self._non_boolean_real_covariates:
@@ -256,7 +280,11 @@ class PerStepTabularModel(AbstractTimeSeriesModel):
256
280
  train_df = train_data.to_data_frame().reset_index()
257
281
  if train_data.static_features is not None:
258
282
  train_df = pd.merge(
259
- left=train_df, right=train_data.static_features, left_on=ITEMID, right_index=True, how="left"
283
+ left=train_df,
284
+ right=train_data.static_features,
285
+ left_on=TimeSeriesDataFrame.ITEMID,
286
+ right_index=True,
287
+ how="left",
260
288
  )
261
289
  train_df = train_df.rename(columns=self._ag_to_nixtla)
262
290
  train_df = train_df.assign(**{MLF_TARGET: train_df[MLF_TARGET].fillna(float("inf"))})
@@ -264,10 +292,10 @@ class PerStepTabularModel(AbstractTimeSeriesModel):
264
292
 
265
293
  @staticmethod
266
294
  def _get_lags_for_step(
267
- trailing_lags: List[int],
268
- seasonal_lags: List[int],
295
+ trailing_lags: list[int],
296
+ seasonal_lags: list[int],
269
297
  step: int,
270
- ) -> List[int]:
298
+ ) -> list[int]:
271
299
  """Get the list of lags that can be used by the model for the given step."""
272
300
  shifted_trailing_lags = [lag + step for lag in trailing_lags]
273
301
  # Only keep lags that are available for model predicting `step` values ahead at prediction time
@@ -313,13 +341,8 @@ class PerStepTabularModel(AbstractTimeSeriesModel):
313
341
  date_features = get_time_features_for_frequency(self.freq)
314
342
  self._date_features = date_features
315
343
 
316
- self._model_cls = ag_model_registry.key_to_cls(model_params["model_name"])
317
- supported_problem_types = self._model_cls.supported_problem_types()
318
- if supported_problem_types is not None and QUANTILE not in supported_problem_types:
319
- raise ValueError(
320
- f"Chosen model_name='{model_params['model_name']}' cannot be used by {self.name} because it does not "
321
- f"support problem_type='quantile' ({supported_problem_types=})"
322
- )
344
+ model_name = model_params["model_name"]
345
+ self._model_cls = ag_model_registry.key_to_cls(model_name)
323
346
  model_hyperparameters = model_params["model_hyperparameters"]
324
347
  # User-provided n_jobs takes priority over the automatic estimate
325
348
  if model_params.get("n_jobs") is not None:
@@ -339,18 +362,35 @@ class PerStepTabularModel(AbstractTimeSeriesModel):
339
362
  time_limit_per_model = time_limit / math.ceil(self.prediction_length / n_jobs)
340
363
  else:
341
364
  time_limit_per_model = None
365
+
366
+ if self.eval_metric.needs_quantile:
367
+ problem_type = QUANTILE
368
+ eval_metric = "pinball_loss"
369
+ else:
370
+ problem_type = REGRESSION
371
+ eval_metric = self.eval_metric.equivalent_tabular_regression_metric or "mean_absolute_error"
372
+
373
+ supported_problem_types = self._model_cls.supported_problem_types()
374
+ if supported_problem_types is not None and problem_type not in supported_problem_types:
375
+ raise ValueError(
376
+ f"Chosen model_name='{model_name}' cannot be used by {self.name} with eval_metric={self.eval_metric}"
377
+ f"because {model_name} does not support problem_type={problem_type} ({supported_problem_types=})"
378
+ )
342
379
  model_fit_kwargs = dict(
343
380
  train_df=train_df,
344
381
  path_root=self.path,
345
382
  model_cls=self._model_cls,
346
383
  quantile_levels=self.quantile_levels,
347
384
  validation_fraction=model_params["validation_fraction"],
385
+ problem_type=problem_type,
386
+ eval_metric=eval_metric,
348
387
  date_features=self._date_features,
349
388
  time_limit=time_limit_per_model,
350
389
  num_cpus=num_cpus_per_model,
351
390
  model_hyperparameters=model_hyperparameters.copy(),
352
391
  verbosity=verbosity - 1,
353
392
  )
393
+
354
394
  logger.debug(f"Fitting models in parallel with {n_jobs=}, {num_cpus_per_model=}, {time_limit_per_model=}")
355
395
  self._relative_paths_to_models = Parallel(n_jobs=n_jobs)( # type: ignore
356
396
  delayed(self._fit_single_model)(
@@ -363,12 +403,19 @@ class PerStepTabularModel(AbstractTimeSeriesModel):
363
403
  for step in range(self.prediction_length)
364
404
  )
365
405
 
366
- @staticmethod
406
+ @classmethod
407
+ def _get_residuals_std_path(cls, model_path: str) -> str:
408
+ """Path to the pd.Series storing the standard deviation of residuals for each item_id."""
409
+ return os.path.join(model_path, "residuals_std.pkl")
410
+
411
+ @classmethod
367
412
  def _predict_with_single_model(
413
+ cls,
368
414
  full_df: pd.DataFrame,
369
415
  path_to_model: str,
370
416
  model_cls: Type[AbstractTabularModel],
371
417
  step: int,
418
+ quantile_levels: list[float],
372
419
  prediction_length: int,
373
420
  lags: list[int],
374
421
  date_features: list[Callable],
@@ -377,14 +424,15 @@ class PerStepTabularModel(AbstractTimeSeriesModel):
377
424
 
378
425
  Returns
379
426
  -------
380
- predictions :
427
+ predictions
381
428
  Predictions of the model for the given step. Shape: (num_items, len(quantile_levels)).
382
429
  """
383
430
  from mlforecast import MLForecast
384
431
 
385
- mlf = MLForecast(models=[], freq=DUMMY_FREQ, lags=lags, date_features=date_features)
432
+ mlf = MLForecast(models=[], freq=cls._dummy_freq, lags=lags, date_features=date_features)
386
433
 
387
- features_df = mlf.preprocess(full_df, static_features=[], dropna=False)
434
+ with warning_filter():
435
+ features_df = mlf.preprocess(full_df, static_features=[], dropna=False)
388
436
  del mlf
389
437
 
390
438
  end_idx_per_item = np.cumsum(features_df[MLF_ITEMID].value_counts(sort=False).to_numpy(dtype="int32"))
@@ -395,12 +443,19 @@ class PerStepTabularModel(AbstractTimeSeriesModel):
395
443
  logger.error(f"Could not load model for {step=} from {path_to_model}")
396
444
  raise
397
445
  predictions = model.predict(features_for_step)
446
+ if model.problem_type == REGRESSION:
447
+ predictions = np.tile(predictions[:, None], (1, len(quantile_levels)))
448
+ residuals_std: pd.Series = load_pkl.load(cls._get_residuals_std_path(model.path))
449
+ item_ids = features_for_step[MLF_ITEMID]
450
+ residuals_repeated = residuals_std.reindex(item_ids).fillna(residuals_std.mean()).to_numpy()
451
+ for i, q in enumerate(quantile_levels):
452
+ predictions[:, i] += scipy.stats.norm.ppf(q) * residuals_repeated
398
453
  return predictions
399
454
 
400
455
  def _predict(
401
456
  self,
402
457
  data: TimeSeriesDataFrame,
403
- known_covariates: TimeSeriesDataFrame | None = None,
458
+ known_covariates: Optional[TimeSeriesDataFrame] = None,
404
459
  **kwargs,
405
460
  ) -> TimeSeriesDataFrame:
406
461
  if known_covariates is not None:
@@ -414,7 +469,9 @@ class PerStepTabularModel(AbstractTimeSeriesModel):
414
469
  full_df = full_df.slice_by_timestep(-(self._max_ts_length + self.prediction_length), None)
415
470
  full_df = full_df.to_data_frame().reset_index()
416
471
  if data.static_features is not None:
417
- full_df = pd.merge(full_df, data.static_features, left_on=ITEMID, right_index=True, how="left")
472
+ full_df = pd.merge(
473
+ full_df, data.static_features, left_on=TimeSeriesDataFrame.ITEMID, right_index=True, how="left"
474
+ )
418
475
 
419
476
  full_df = (
420
477
  full_df.rename(columns=self._ag_to_nixtla)
@@ -425,6 +482,7 @@ class PerStepTabularModel(AbstractTimeSeriesModel):
425
482
 
426
483
  model_predict_kwargs = dict(
427
484
  full_df=full_df,
485
+ quantile_levels=self.quantile_levels,
428
486
  prediction_length=self.prediction_length,
429
487
  model_cls=self._model_cls,
430
488
  date_features=self._date_features,
@@ -449,5 +507,5 @@ class PerStepTabularModel(AbstractTimeSeriesModel):
449
507
  predictions["mean"] = predictions["0.5"]
450
508
  return TimeSeriesDataFrame(predictions)
451
509
 
452
- def _more_tags(self) -> Dict[str, Any]:
510
+ def _more_tags(self) -> dict[str, Any]:
453
511
  return {"allow_nan": True, "can_refit_full": True}
@@ -8,11 +8,7 @@ from mlforecast.target_transforms import (
8
8
  _BaseGroupedArrayTargetTransform,
9
9
  )
10
10
 
11
- from autogluon.timeseries.dataset.ts_dataframe import (
12
- ITEMID,
13
- TIMESTAMP,
14
- TimeSeriesDataFrame,
15
- )
11
+ from autogluon.timeseries.dataset import TimeSeriesDataFrame
16
12
  from autogluon.timeseries.transforms.target_scaler import TargetScaler, get_target_scaler
17
13
 
18
14
  from .utils import MLF_ITEMID, MLF_TIMESTAMP
@@ -26,11 +22,17 @@ class MLForecastScaler(BaseTargetTransform):
26
22
 
27
23
  def _df_to_tsdf(self, df: pd.DataFrame) -> TimeSeriesDataFrame:
28
24
  return TimeSeriesDataFrame(
29
- df.rename(columns={self.id_col: ITEMID, self.time_col: TIMESTAMP}).set_index([ITEMID, TIMESTAMP])
25
+ df.rename(
26
+ columns={self.id_col: TimeSeriesDataFrame.ITEMID, self.time_col: TimeSeriesDataFrame.TIMESTAMP}
27
+ ).set_index([TimeSeriesDataFrame.ITEMID, TimeSeriesDataFrame.TIMESTAMP])
30
28
  )
31
29
 
32
30
  def _tsdf_to_df(self, ts_df: TimeSeriesDataFrame) -> pd.DataFrame:
33
- return pd.DataFrame(ts_df).reset_index().rename(columns={ITEMID: self.id_col, TIMESTAMP: self.time_col})
31
+ return (
32
+ pd.DataFrame(ts_df)
33
+ .reset_index()
34
+ .rename(columns={TimeSeriesDataFrame.ITEMID: self.id_col, TimeSeriesDataFrame.TIMESTAMP: self.time_col})
35
+ )
34
36
 
35
37
  def fit_transform(self, df: pd.DataFrame) -> pd.DataFrame: # type: ignore
36
38
  self.ag_scaler = get_target_scaler(name=self.scaler_type, target=self.target_col)