autogluon.timeseries 1.4.1b20250906__py3-none-any.whl → 1.4.1b20251210__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of autogluon.timeseries might be problematic. Click here for more details.
- autogluon/timeseries/configs/hyperparameter_presets.py +2 -2
- autogluon/timeseries/dataset/ts_dataframe.py +97 -86
- autogluon/timeseries/learner.py +68 -35
- autogluon/timeseries/metrics/__init__.py +4 -4
- autogluon/timeseries/metrics/abstract.py +8 -8
- autogluon/timeseries/metrics/point.py +9 -9
- autogluon/timeseries/metrics/quantile.py +5 -5
- autogluon/timeseries/metrics/utils.py +4 -4
- autogluon/timeseries/models/__init__.py +4 -1
- autogluon/timeseries/models/abstract/abstract_timeseries_model.py +52 -39
- autogluon/timeseries/models/abstract/model_trial.py +2 -1
- autogluon/timeseries/models/abstract/tunable.py +8 -8
- autogluon/timeseries/models/autogluon_tabular/mlforecast.py +58 -62
- autogluon/timeseries/models/autogluon_tabular/per_step.py +26 -15
- autogluon/timeseries/models/autogluon_tabular/transforms.py +11 -9
- autogluon/timeseries/models/chronos/__init__.py +2 -1
- autogluon/timeseries/models/chronos/chronos2.py +361 -0
- autogluon/timeseries/models/chronos/model.py +125 -87
- autogluon/timeseries/models/chronos/{pipeline/utils.py → utils.py} +68 -36
- autogluon/timeseries/models/ensemble/__init__.py +34 -2
- autogluon/timeseries/models/ensemble/abstract.py +5 -42
- autogluon/timeseries/models/ensemble/array_based/__init__.py +3 -0
- autogluon/timeseries/models/ensemble/array_based/abstract.py +236 -0
- autogluon/timeseries/models/ensemble/array_based/models.py +73 -0
- autogluon/timeseries/models/ensemble/array_based/regressor/__init__.py +12 -0
- autogluon/timeseries/models/ensemble/array_based/regressor/abstract.py +88 -0
- autogluon/timeseries/models/ensemble/array_based/regressor/linear_stacker.py +167 -0
- autogluon/timeseries/models/ensemble/array_based/regressor/per_quantile_tabular.py +94 -0
- autogluon/timeseries/models/ensemble/array_based/regressor/tabular.py +107 -0
- autogluon/timeseries/models/ensemble/{greedy.py → ensemble_selection.py} +41 -61
- autogluon/timeseries/models/ensemble/per_item_greedy.py +162 -0
- autogluon/timeseries/models/ensemble/weighted/__init__.py +8 -0
- autogluon/timeseries/models/ensemble/weighted/abstract.py +40 -0
- autogluon/timeseries/models/ensemble/{basic.py → weighted/basic.py} +6 -16
- autogluon/timeseries/models/ensemble/weighted/greedy.py +57 -0
- autogluon/timeseries/models/gluonts/abstract.py +25 -25
- autogluon/timeseries/models/gluonts/dataset.py +11 -11
- autogluon/timeseries/models/local/__init__.py +0 -7
- autogluon/timeseries/models/local/abstract_local_model.py +15 -18
- autogluon/timeseries/models/local/naive.py +2 -2
- autogluon/timeseries/models/local/npts.py +1 -1
- autogluon/timeseries/models/local/statsforecast.py +12 -12
- autogluon/timeseries/models/multi_window/multi_window_model.py +39 -24
- autogluon/timeseries/models/registry.py +3 -4
- autogluon/timeseries/models/toto/__init__.py +3 -0
- autogluon/timeseries/models/toto/_internal/__init__.py +9 -0
- autogluon/timeseries/models/toto/_internal/backbone/__init__.py +3 -0
- autogluon/timeseries/models/toto/_internal/backbone/attention.py +196 -0
- autogluon/timeseries/models/toto/_internal/backbone/backbone.py +262 -0
- autogluon/timeseries/models/toto/_internal/backbone/distribution.py +70 -0
- autogluon/timeseries/models/toto/_internal/backbone/kvcache.py +136 -0
- autogluon/timeseries/models/toto/_internal/backbone/rope.py +89 -0
- autogluon/timeseries/models/toto/_internal/backbone/rotary_embedding_torch.py +342 -0
- autogluon/timeseries/models/toto/_internal/backbone/scaler.py +305 -0
- autogluon/timeseries/models/toto/_internal/backbone/transformer.py +333 -0
- autogluon/timeseries/models/toto/_internal/dataset.py +165 -0
- autogluon/timeseries/models/toto/_internal/forecaster.py +423 -0
- autogluon/timeseries/models/toto/dataloader.py +108 -0
- autogluon/timeseries/models/toto/hf_pretrained_model.py +118 -0
- autogluon/timeseries/models/toto/model.py +236 -0
- autogluon/timeseries/predictor.py +301 -103
- autogluon/timeseries/regressor.py +27 -30
- autogluon/timeseries/splitter.py +3 -27
- autogluon/timeseries/trainer/ensemble_composer.py +439 -0
- autogluon/timeseries/trainer/model_set_builder.py +9 -9
- autogluon/timeseries/trainer/prediction_cache.py +16 -16
- autogluon/timeseries/trainer/trainer.py +300 -275
- autogluon/timeseries/trainer/utils.py +17 -0
- autogluon/timeseries/transforms/covariate_scaler.py +8 -8
- autogluon/timeseries/transforms/target_scaler.py +15 -15
- autogluon/timeseries/utils/constants.py +10 -0
- autogluon/timeseries/utils/datetime/lags.py +1 -3
- autogluon/timeseries/utils/datetime/seasonality.py +1 -3
- autogluon/timeseries/utils/features.py +18 -14
- autogluon/timeseries/utils/forecast.py +6 -7
- autogluon/timeseries/utils/timer.py +173 -0
- autogluon/timeseries/version.py +1 -1
- autogluon.timeseries-1.4.1b20251210-py3.11-nspkg.pth +1 -0
- {autogluon.timeseries-1.4.1b20250906.dist-info → autogluon_timeseries-1.4.1b20251210.dist-info}/METADATA +39 -22
- autogluon_timeseries-1.4.1b20251210.dist-info/RECORD +103 -0
- {autogluon.timeseries-1.4.1b20250906.dist-info → autogluon_timeseries-1.4.1b20251210.dist-info}/WHEEL +1 -1
- autogluon/timeseries/evaluator.py +0 -6
- autogluon/timeseries/models/chronos/pipeline/__init__.py +0 -10
- autogluon/timeseries/models/chronos/pipeline/base.py +0 -160
- autogluon/timeseries/models/chronos/pipeline/chronos.py +0 -544
- autogluon/timeseries/models/chronos/pipeline/chronos_bolt.py +0 -580
- autogluon.timeseries-1.4.1b20250906-py3.9-nspkg.pth +0 -1
- autogluon.timeseries-1.4.1b20250906.dist-info/RECORD +0 -75
- {autogluon.timeseries-1.4.1b20250906.dist-info → autogluon_timeseries-1.4.1b20251210.dist-info/licenses}/LICENSE +0 -0
- {autogluon.timeseries-1.4.1b20250906.dist-info → autogluon_timeseries-1.4.1b20251210.dist-info/licenses}/NOTICE +0 -0
- {autogluon.timeseries-1.4.1b20250906.dist-info → autogluon_timeseries-1.4.1b20251210.dist-info}/namespace_packages.txt +0 -0
- {autogluon.timeseries-1.4.1b20250906.dist-info → autogluon_timeseries-1.4.1b20251210.dist-info}/top_level.txt +0 -0
- {autogluon.timeseries-1.4.1b20250906.dist-info → autogluon_timeseries-1.4.1b20251210.dist-info}/zip-safe +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import warnings
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Sequence, overload
|
|
3
3
|
|
|
4
4
|
import numpy as np
|
|
5
5
|
import pandas as pd
|
|
@@ -52,13 +52,13 @@ class TimeSeriesScorer:
|
|
|
52
52
|
optimum: float = 0.0
|
|
53
53
|
optimized_by_median: bool = False
|
|
54
54
|
needs_quantile: bool = False
|
|
55
|
-
equivalent_tabular_regression_metric:
|
|
55
|
+
equivalent_tabular_regression_metric: str | None = None
|
|
56
56
|
|
|
57
57
|
def __init__(
|
|
58
58
|
self,
|
|
59
59
|
prediction_length: int = 1,
|
|
60
|
-
seasonal_period:
|
|
61
|
-
horizon_weight:
|
|
60
|
+
seasonal_period: int | None = None,
|
|
61
|
+
horizon_weight: Sequence[float] | None = None,
|
|
62
62
|
):
|
|
63
63
|
self.prediction_length = int(prediction_length)
|
|
64
64
|
if self.prediction_length < 1:
|
|
@@ -192,7 +192,7 @@ class TimeSeriesScorer:
|
|
|
192
192
|
return self.optimum - self.score(*args, **kwargs)
|
|
193
193
|
|
|
194
194
|
@staticmethod
|
|
195
|
-
def _safemean(array:
|
|
195
|
+
def _safemean(array: np.ndarray | pd.Series) -> float:
|
|
196
196
|
"""Compute mean of a numpy array-like object, ignoring inf, -inf and nan values."""
|
|
197
197
|
return float(np.mean(array[np.isfinite(array)]))
|
|
198
198
|
|
|
@@ -240,13 +240,13 @@ class TimeSeriesScorer:
|
|
|
240
240
|
@overload
|
|
241
241
|
@staticmethod
|
|
242
242
|
def check_get_horizon_weight(
|
|
243
|
-
horizon_weight:
|
|
243
|
+
horizon_weight: Sequence[float] | np.ndarray, prediction_length: int
|
|
244
244
|
) -> np.ndarray: ...
|
|
245
245
|
|
|
246
246
|
@staticmethod
|
|
247
247
|
def check_get_horizon_weight(
|
|
248
|
-
horizon_weight:
|
|
249
|
-
) ->
|
|
248
|
+
horizon_weight: Sequence[float] | np.ndarray | None, prediction_length: int
|
|
249
|
+
) -> np.ndarray | None:
|
|
250
250
|
"""Convert horizon_weight to a non-negative numpy array that sums up to prediction_length.
|
|
251
251
|
Raises an exception if horizon_weight has an invalid shape or contains invalid values.
|
|
252
252
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import warnings
|
|
3
|
-
from typing import
|
|
3
|
+
from typing import Sequence
|
|
4
4
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
import pandas as pd
|
|
@@ -279,13 +279,13 @@ class MASE(TimeSeriesScorer):
|
|
|
279
279
|
def __init__(
|
|
280
280
|
self,
|
|
281
281
|
prediction_length: int = 1,
|
|
282
|
-
seasonal_period:
|
|
283
|
-
horizon_weight:
|
|
282
|
+
seasonal_period: int | None = None,
|
|
283
|
+
horizon_weight: Sequence[float] | None = None,
|
|
284
284
|
):
|
|
285
285
|
super().__init__(
|
|
286
286
|
prediction_length=prediction_length, seasonal_period=seasonal_period, horizon_weight=horizon_weight
|
|
287
287
|
)
|
|
288
|
-
self._past_abs_seasonal_error:
|
|
288
|
+
self._past_abs_seasonal_error: pd.Series | None = None
|
|
289
289
|
|
|
290
290
|
def save_past_metrics(
|
|
291
291
|
self, data_past: TimeSeriesDataFrame, target: str = "target", seasonal_period: int = 1, **kwargs
|
|
@@ -353,13 +353,13 @@ class RMSSE(TimeSeriesScorer):
|
|
|
353
353
|
def __init__(
|
|
354
354
|
self,
|
|
355
355
|
prediction_length: int = 1,
|
|
356
|
-
seasonal_period:
|
|
357
|
-
horizon_weight:
|
|
356
|
+
seasonal_period: int | None = None,
|
|
357
|
+
horizon_weight: Sequence[float] | None = None,
|
|
358
358
|
):
|
|
359
359
|
super().__init__(
|
|
360
360
|
prediction_length=prediction_length, seasonal_period=seasonal_period, horizon_weight=horizon_weight
|
|
361
361
|
)
|
|
362
|
-
self._past_squared_seasonal_error:
|
|
362
|
+
self._past_squared_seasonal_error: pd.Series | None = None
|
|
363
363
|
|
|
364
364
|
def save_past_metrics(
|
|
365
365
|
self, data_past: TimeSeriesDataFrame, target: str = "target", seasonal_period: int = 1, **kwargs
|
|
@@ -471,8 +471,8 @@ class WCD(TimeSeriesScorer):
|
|
|
471
471
|
self,
|
|
472
472
|
alpha: float = 0.5,
|
|
473
473
|
prediction_length: int = 1,
|
|
474
|
-
seasonal_period:
|
|
475
|
-
horizon_weight:
|
|
474
|
+
seasonal_period: int | None = None,
|
|
475
|
+
horizon_weight: Sequence[float] | None = None,
|
|
476
476
|
):
|
|
477
477
|
super().__init__(
|
|
478
478
|
prediction_length=prediction_length, seasonal_period=seasonal_period, horizon_weight=horizon_weight
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import Sequence
|
|
2
2
|
|
|
3
3
|
import numpy as np
|
|
4
4
|
import pandas as pd
|
|
5
5
|
|
|
6
|
-
from autogluon.timeseries.dataset
|
|
6
|
+
from autogluon.timeseries.dataset import TimeSeriesDataFrame
|
|
7
7
|
|
|
8
8
|
from .abstract import TimeSeriesScorer
|
|
9
9
|
from .utils import in_sample_abs_seasonal_error
|
|
@@ -92,13 +92,13 @@ class SQL(TimeSeriesScorer):
|
|
|
92
92
|
def __init__(
|
|
93
93
|
self,
|
|
94
94
|
prediction_length: int = 1,
|
|
95
|
-
seasonal_period:
|
|
96
|
-
horizon_weight:
|
|
95
|
+
seasonal_period: int | None = None,
|
|
96
|
+
horizon_weight: Sequence[float] | None = None,
|
|
97
97
|
):
|
|
98
98
|
super().__init__(
|
|
99
99
|
prediction_length=prediction_length, seasonal_period=seasonal_period, horizon_weight=horizon_weight
|
|
100
100
|
)
|
|
101
|
-
self._past_abs_seasonal_error:
|
|
101
|
+
self._past_abs_seasonal_error: pd.Series | None = None
|
|
102
102
|
|
|
103
103
|
def save_past_metrics(
|
|
104
104
|
self, data_past: TimeSeriesDataFrame, target: str = "target", seasonal_period: int = 1, **kwargs
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import pandas as pd
|
|
2
2
|
|
|
3
|
-
from autogluon.timeseries.dataset
|
|
3
|
+
from autogluon.timeseries.dataset import TimeSeriesDataFrame
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
def _get_seasonal_diffs(*, y_past: pd.Series, seasonal_period: int = 1) -> pd.Series:
|
|
7
|
-
return y_past.groupby(level=ITEMID, sort=False).diff(seasonal_period).abs()
|
|
7
|
+
return y_past.groupby(level=TimeSeriesDataFrame.ITEMID, sort=False).diff(seasonal_period).abs()
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
def in_sample_abs_seasonal_error(*, y_past: pd.Series, seasonal_period: int = 1) -> pd.Series:
|
|
11
11
|
"""Compute seasonal naive forecast error (predict value from seasonal_period steps ago) for each time series."""
|
|
12
12
|
seasonal_diffs = _get_seasonal_diffs(y_past=y_past, seasonal_period=seasonal_period)
|
|
13
|
-
return seasonal_diffs.groupby(level=ITEMID, sort=False).mean().fillna(1.0)
|
|
13
|
+
return seasonal_diffs.groupby(level=TimeSeriesDataFrame.ITEMID, sort=False).mean().fillna(1.0)
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
def in_sample_squared_seasonal_error(*, y_past: pd.Series, seasonal_period: int = 1) -> pd.Series:
|
|
17
17
|
seasonal_diffs = _get_seasonal_diffs(y_past=y_past, seasonal_period=seasonal_period)
|
|
18
|
-
return seasonal_diffs.pow(2.0).groupby(level=ITEMID, sort=False).mean().fillna(1.0)
|
|
18
|
+
return seasonal_diffs.pow(2.0).groupby(level=TimeSeriesDataFrame.ITEMID, sort=False).mean().fillna(1.0)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from .autogluon_tabular import DirectTabularModel, PerStepTabularModel, RecursiveTabularModel
|
|
2
|
-
from .chronos import ChronosModel
|
|
2
|
+
from .chronos import Chronos2Model, ChronosModel
|
|
3
3
|
from .gluonts import (
|
|
4
4
|
DeepARModel,
|
|
5
5
|
DLinearModel,
|
|
@@ -28,6 +28,7 @@ from .local import (
|
|
|
28
28
|
ZeroModel,
|
|
29
29
|
)
|
|
30
30
|
from .registry import ModelRegistry
|
|
31
|
+
from .toto import TotoModel
|
|
31
32
|
|
|
32
33
|
__all__ = [
|
|
33
34
|
"ADIDAModel",
|
|
@@ -44,6 +45,7 @@ __all__ = [
|
|
|
44
45
|
"ETSModel",
|
|
45
46
|
"IMAPAModel",
|
|
46
47
|
"ChronosModel",
|
|
48
|
+
"Chronos2Model",
|
|
47
49
|
"ModelRegistry",
|
|
48
50
|
"NPTSModel",
|
|
49
51
|
"NaiveModel",
|
|
@@ -56,6 +58,7 @@ __all__ = [
|
|
|
56
58
|
"TemporalFusionTransformerModel",
|
|
57
59
|
"ThetaModel",
|
|
58
60
|
"TiDEModel",
|
|
61
|
+
"TotoModel",
|
|
59
62
|
"WaveNetModel",
|
|
60
63
|
"ZeroModel",
|
|
61
64
|
]
|
|
@@ -4,7 +4,7 @@ import os
|
|
|
4
4
|
import re
|
|
5
5
|
import time
|
|
6
6
|
from abc import ABC, abstractmethod
|
|
7
|
-
from typing import Any,
|
|
7
|
+
from typing import Any, Sequence
|
|
8
8
|
|
|
9
9
|
import pandas as pd
|
|
10
10
|
from typing_extensions import Self
|
|
@@ -75,15 +75,15 @@ class TimeSeriesModelBase(ModelBase, ABC):
|
|
|
75
75
|
|
|
76
76
|
def __init__(
|
|
77
77
|
self,
|
|
78
|
-
path:
|
|
79
|
-
name:
|
|
80
|
-
hyperparameters:
|
|
81
|
-
freq:
|
|
78
|
+
path: str | None = None,
|
|
79
|
+
name: str | None = None,
|
|
80
|
+
hyperparameters: dict[str, Any] | None = None,
|
|
81
|
+
freq: str | None = None,
|
|
82
82
|
prediction_length: int = 1,
|
|
83
|
-
covariate_metadata:
|
|
83
|
+
covariate_metadata: CovariateMetadata | None = None,
|
|
84
84
|
target: str = "target",
|
|
85
85
|
quantile_levels: Sequence[float] = (0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9),
|
|
86
|
-
eval_metric:
|
|
86
|
+
eval_metric: str | TimeSeriesScorer | None = None,
|
|
87
87
|
):
|
|
88
88
|
self.name = name or re.sub(r"Model$", "", self.__class__.__name__)
|
|
89
89
|
|
|
@@ -102,7 +102,7 @@ class TimeSeriesModelBase(ModelBase, ABC):
|
|
|
102
102
|
self.target: str = target
|
|
103
103
|
self.covariate_metadata = covariate_metadata or CovariateMetadata()
|
|
104
104
|
|
|
105
|
-
self.freq:
|
|
105
|
+
self.freq: str | None = freq
|
|
106
106
|
self.prediction_length: int = prediction_length
|
|
107
107
|
self.quantile_levels: list[float] = list(quantile_levels)
|
|
108
108
|
|
|
@@ -117,17 +117,21 @@ class TimeSeriesModelBase(ModelBase, ABC):
|
|
|
117
117
|
else:
|
|
118
118
|
self.must_drop_median = False
|
|
119
119
|
|
|
120
|
-
self._oof_predictions:
|
|
120
|
+
self._oof_predictions: list[TimeSeriesDataFrame] | None = None
|
|
121
121
|
|
|
122
122
|
# user provided hyperparameters and extra arguments that are used during model training
|
|
123
123
|
self._hyperparameters, self._extra_ag_args = self._check_and_split_hyperparameters(hyperparameters)
|
|
124
124
|
|
|
125
|
-
|
|
126
|
-
self.
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
)
|
|
130
|
-
self.
|
|
125
|
+
# Time taken to fit in seconds (Training data)
|
|
126
|
+
self.fit_time: float | None = None
|
|
127
|
+
# Time taken to predict in seconds, for a single prediction horizon on validation data
|
|
128
|
+
self.predict_time: float | None = None
|
|
129
|
+
# Time taken to predict 1 row of data in seconds (with batch size `predict_1_batch_size`)
|
|
130
|
+
self.predict_1_time: float | None = None
|
|
131
|
+
# Useful for ensembles, additional prediction time excluding base models. None for base models.
|
|
132
|
+
self.predict_time_marginal: float | None = None
|
|
133
|
+
# Score with eval_metric on validation data
|
|
134
|
+
self.val_score: float | None = None
|
|
131
135
|
|
|
132
136
|
def __repr__(self) -> str:
|
|
133
137
|
return self.name
|
|
@@ -143,9 +147,14 @@ class TimeSeriesModelBase(ModelBase, ABC):
|
|
|
143
147
|
self.path = path_context
|
|
144
148
|
self.path_root = self.path.rsplit(self.name, 1)[0]
|
|
145
149
|
|
|
150
|
+
def cache_oof_predictions(self, predictions: TimeSeriesDataFrame | list[TimeSeriesDataFrame]) -> None:
|
|
151
|
+
if isinstance(predictions, TimeSeriesDataFrame):
|
|
152
|
+
predictions = [predictions]
|
|
153
|
+
self._oof_predictions = predictions
|
|
154
|
+
|
|
146
155
|
@classmethod
|
|
147
156
|
def _check_and_split_hyperparameters(
|
|
148
|
-
cls, hyperparameters:
|
|
157
|
+
cls, hyperparameters: dict[str, Any] | None = None
|
|
149
158
|
) -> tuple[dict[str, Any], dict[str, Any]]:
|
|
150
159
|
"""Given the user-specified hyperparameters, split into `hyperparameters` and `extra_ag_args`, intended
|
|
151
160
|
to be used during model initialization.
|
|
@@ -180,7 +189,7 @@ class TimeSeriesModelBase(ModelBase, ABC):
|
|
|
180
189
|
)
|
|
181
190
|
return hyperparameters, extra_ag_args
|
|
182
191
|
|
|
183
|
-
def save(self, path:
|
|
192
|
+
def save(self, path: str | None = None, verbose: bool = True) -> str:
|
|
184
193
|
if path is None:
|
|
185
194
|
path = self.path
|
|
186
195
|
|
|
@@ -242,9 +251,13 @@ class TimeSeriesModelBase(ModelBase, ABC):
|
|
|
242
251
|
return {}
|
|
243
252
|
|
|
244
253
|
def get_hyperparameters(self) -> dict:
|
|
245
|
-
"""Get hyperparameters that will be passed to the "inner model" that AutoGluon wraps."""
|
|
254
|
+
"""Get dictionary of hyperparameters that will be passed to the "inner model" that AutoGluon wraps."""
|
|
246
255
|
return {**self._get_default_hyperparameters(), **self._hyperparameters}
|
|
247
256
|
|
|
257
|
+
def get_hyperparameter(self, key: str) -> Any:
|
|
258
|
+
"""Get a single hyperparameter value for the "inner model"."""
|
|
259
|
+
return self.get_hyperparameters()[key]
|
|
260
|
+
|
|
248
261
|
def get_info(self) -> dict:
|
|
249
262
|
"""
|
|
250
263
|
Returns a dictionary of numerous fields describing the model.
|
|
@@ -384,15 +397,15 @@ class AbstractTimeSeriesModel(TimeSeriesModelBase, TimeSeriesTunable, metaclass=
|
|
|
384
397
|
|
|
385
398
|
def __init__(
|
|
386
399
|
self,
|
|
387
|
-
path:
|
|
388
|
-
name:
|
|
389
|
-
hyperparameters:
|
|
390
|
-
freq:
|
|
400
|
+
path: str | None = None,
|
|
401
|
+
name: str | None = None,
|
|
402
|
+
hyperparameters: dict[str, Any] | None = None,
|
|
403
|
+
freq: str | None = None,
|
|
391
404
|
prediction_length: int = 1,
|
|
392
|
-
covariate_metadata:
|
|
405
|
+
covariate_metadata: CovariateMetadata | None = None,
|
|
393
406
|
target: str = "target",
|
|
394
407
|
quantile_levels: Sequence[float] = (0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9),
|
|
395
|
-
eval_metric:
|
|
408
|
+
eval_metric: str | TimeSeriesScorer | None = None,
|
|
396
409
|
):
|
|
397
410
|
# TODO: make freq a required argument in AbstractTimeSeriesModel
|
|
398
411
|
super().__init__(
|
|
@@ -406,9 +419,9 @@ class AbstractTimeSeriesModel(TimeSeriesModelBase, TimeSeriesTunable, metaclass=
|
|
|
406
419
|
quantile_levels=quantile_levels,
|
|
407
420
|
eval_metric=eval_metric,
|
|
408
421
|
)
|
|
409
|
-
self.target_scaler:
|
|
410
|
-
self.covariate_scaler:
|
|
411
|
-
self.covariate_regressor:
|
|
422
|
+
self.target_scaler: TargetScaler | None
|
|
423
|
+
self.covariate_scaler: CovariateScaler | None
|
|
424
|
+
self.covariate_regressor: CovariateRegressor | None
|
|
412
425
|
|
|
413
426
|
def _initialize_transforms_and_regressor(self) -> None:
|
|
414
427
|
self.target_scaler = get_target_scaler(self.get_hyperparameters().get("target_scaler"), target=self.target)
|
|
@@ -433,8 +446,8 @@ class AbstractTimeSeriesModel(TimeSeriesModelBase, TimeSeriesTunable, metaclass=
|
|
|
433
446
|
def fit(
|
|
434
447
|
self,
|
|
435
448
|
train_data: TimeSeriesDataFrame,
|
|
436
|
-
val_data:
|
|
437
|
-
time_limit:
|
|
449
|
+
val_data: TimeSeriesDataFrame | None = None,
|
|
450
|
+
time_limit: float | None = None,
|
|
438
451
|
verbosity: int = 2,
|
|
439
452
|
**kwargs,
|
|
440
453
|
) -> Self:
|
|
@@ -527,10 +540,10 @@ class AbstractTimeSeriesModel(TimeSeriesModelBase, TimeSeriesTunable, metaclass=
|
|
|
527
540
|
def _fit(
|
|
528
541
|
self,
|
|
529
542
|
train_data: TimeSeriesDataFrame,
|
|
530
|
-
val_data:
|
|
531
|
-
time_limit:
|
|
532
|
-
num_cpus:
|
|
533
|
-
num_gpus:
|
|
543
|
+
val_data: TimeSeriesDataFrame | None = None,
|
|
544
|
+
time_limit: float | None = None,
|
|
545
|
+
num_cpus: int | None = None,
|
|
546
|
+
num_gpus: int | None = None,
|
|
534
547
|
verbosity: int = 2,
|
|
535
548
|
**kwargs,
|
|
536
549
|
) -> None:
|
|
@@ -551,7 +564,7 @@ class AbstractTimeSeriesModel(TimeSeriesModelBase, TimeSeriesTunable, metaclass=
|
|
|
551
564
|
"as hyperparameters when initializing or use `hyperparameter_tune` instead."
|
|
552
565
|
)
|
|
553
566
|
|
|
554
|
-
def _log_unused_hyperparameters(self, extra_allowed_hyperparameters:
|
|
567
|
+
def _log_unused_hyperparameters(self, extra_allowed_hyperparameters: list[str] | None = None) -> None:
|
|
555
568
|
"""Log a warning if unused hyperparameters were provided to the model."""
|
|
556
569
|
allowed_hyperparameters = self.allowed_hyperparameters
|
|
557
570
|
if extra_allowed_hyperparameters is not None:
|
|
@@ -567,7 +580,7 @@ class AbstractTimeSeriesModel(TimeSeriesModelBase, TimeSeriesTunable, metaclass=
|
|
|
567
580
|
def predict(
|
|
568
581
|
self,
|
|
569
582
|
data: TimeSeriesDataFrame,
|
|
570
|
-
known_covariates:
|
|
583
|
+
known_covariates: TimeSeriesDataFrame | None = None,
|
|
571
584
|
**kwargs,
|
|
572
585
|
) -> TimeSeriesDataFrame:
|
|
573
586
|
"""Given a dataset, predict the next `self.prediction_length` time steps.
|
|
@@ -648,7 +661,7 @@ class AbstractTimeSeriesModel(TimeSeriesModelBase, TimeSeriesTunable, metaclass=
|
|
|
648
661
|
def _predict(
|
|
649
662
|
self,
|
|
650
663
|
data: TimeSeriesDataFrame,
|
|
651
|
-
known_covariates:
|
|
664
|
+
known_covariates: TimeSeriesDataFrame | None = None,
|
|
652
665
|
**kwargs,
|
|
653
666
|
) -> TimeSeriesDataFrame:
|
|
654
667
|
"""Private method for `predict`. See `predict` for documentation of arguments."""
|
|
@@ -731,7 +744,7 @@ class AbstractTimeSeriesModel(TimeSeriesModelBase, TimeSeriesTunable, metaclass=
|
|
|
731
744
|
)
|
|
732
745
|
predict_start_time = time.time()
|
|
733
746
|
oof_predictions = self.predict(past_data, known_covariates=known_covariates, **predict_kwargs)
|
|
734
|
-
self.
|
|
747
|
+
self.cache_oof_predictions(oof_predictions)
|
|
735
748
|
if store_predict_time:
|
|
736
749
|
self.predict_time = time.time() - predict_start_time
|
|
737
750
|
if store_val_score:
|
|
@@ -740,9 +753,9 @@ class AbstractTimeSeriesModel(TimeSeriesModelBase, TimeSeriesTunable, metaclass=
|
|
|
740
753
|
def preprocess(
|
|
741
754
|
self,
|
|
742
755
|
data: TimeSeriesDataFrame,
|
|
743
|
-
known_covariates:
|
|
756
|
+
known_covariates: TimeSeriesDataFrame | None = None,
|
|
744
757
|
is_train: bool = False,
|
|
745
758
|
**kwargs,
|
|
746
|
-
) -> tuple[TimeSeriesDataFrame,
|
|
759
|
+
) -> tuple[TimeSeriesDataFrame, TimeSeriesDataFrame | None]:
|
|
747
760
|
"""Method that implements model-specific preprocessing logic."""
|
|
748
761
|
return data, known_covariates
|
|
@@ -76,7 +76,8 @@ def fit_and_save_model(model, fit_kwargs, train_data, val_data, eval_metric, tim
|
|
|
76
76
|
time_fit_start = time.time()
|
|
77
77
|
model.fit(train_data=train_data, val_data=val_data, time_limit=time_left, **fit_kwargs)
|
|
78
78
|
model.fit_time = time.time() - time_fit_start
|
|
79
|
-
|
|
79
|
+
if val_data is not None:
|
|
80
|
+
model.score_and_cache_oof(val_data, store_val_score=True, store_predict_time=True)
|
|
80
81
|
|
|
81
82
|
logger.debug(f"\tHyperparameter tune run: {model.name}")
|
|
82
83
|
logger.debug(f"\t\t{model.val_score:<7.4f}".ljust(15) + f"= Validation score ({eval_metric.name_with_sign})")
|
|
@@ -5,7 +5,7 @@ import os
|
|
|
5
5
|
import time
|
|
6
6
|
from abc import ABC, abstractmethod
|
|
7
7
|
from contextlib import nullcontext
|
|
8
|
-
from typing import Any
|
|
8
|
+
from typing import Any
|
|
9
9
|
|
|
10
10
|
from typing_extensions import Self
|
|
11
11
|
|
|
@@ -37,12 +37,12 @@ class TimeSeriesTunable(Tunable, ABC):
|
|
|
37
37
|
def hyperparameter_tune(
|
|
38
38
|
self,
|
|
39
39
|
train_data: TimeSeriesDataFrame,
|
|
40
|
-
val_data:
|
|
40
|
+
val_data: TimeSeriesDataFrame | None,
|
|
41
41
|
val_splitter: Any = None,
|
|
42
|
-
default_num_trials:
|
|
43
|
-
refit_every_n_windows:
|
|
44
|
-
hyperparameter_tune_kwargs:
|
|
45
|
-
time_limit:
|
|
42
|
+
default_num_trials: int | None = 1,
|
|
43
|
+
refit_every_n_windows: int | None = 1,
|
|
44
|
+
hyperparameter_tune_kwargs: str | dict = "auto",
|
|
45
|
+
time_limit: float | None = None,
|
|
46
46
|
) -> tuple[dict[str, Any], Any]:
|
|
47
47
|
hpo_executor = self._get_default_hpo_executor()
|
|
48
48
|
hpo_executor.initialize(
|
|
@@ -144,13 +144,13 @@ class TimeSeriesTunable(Tunable, ABC):
|
|
|
144
144
|
"""
|
|
145
145
|
return None
|
|
146
146
|
|
|
147
|
-
def get_minimum_resources(self, is_gpu_available: bool = False) -> dict[str,
|
|
147
|
+
def get_minimum_resources(self, is_gpu_available: bool = False) -> dict[str, int | float]:
|
|
148
148
|
return {
|
|
149
149
|
"num_cpus": 1,
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
def _save_with_data(
|
|
153
|
-
self, train_data: TimeSeriesDataFrame, val_data:
|
|
153
|
+
self, train_data: TimeSeriesDataFrame, val_data: TimeSeriesDataFrame | None
|
|
154
154
|
) -> tuple[str, str]:
|
|
155
155
|
self.path = os.path.abspath(self.path)
|
|
156
156
|
self.path_root = self.path.rsplit(self.name, 1)[0]
|