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.
- autogluon/timeseries/configs/__init__.py +3 -2
- autogluon/timeseries/configs/hyperparameter_presets.py +62 -0
- autogluon/timeseries/configs/predictor_presets.py +84 -0
- autogluon/timeseries/dataset/ts_dataframe.py +98 -72
- autogluon/timeseries/learner.py +19 -18
- autogluon/timeseries/metrics/__init__.py +5 -5
- autogluon/timeseries/metrics/abstract.py +17 -17
- autogluon/timeseries/metrics/point.py +1 -1
- autogluon/timeseries/metrics/quantile.py +2 -2
- autogluon/timeseries/metrics/utils.py +4 -4
- autogluon/timeseries/models/__init__.py +4 -0
- autogluon/timeseries/models/abstract/abstract_timeseries_model.py +52 -75
- autogluon/timeseries/models/abstract/tunable.py +6 -6
- autogluon/timeseries/models/autogluon_tabular/mlforecast.py +72 -76
- autogluon/timeseries/models/autogluon_tabular/per_step.py +104 -46
- autogluon/timeseries/models/autogluon_tabular/transforms.py +9 -7
- autogluon/timeseries/models/chronos/model.py +115 -78
- autogluon/timeseries/models/chronos/{pipeline/utils.py → utils.py} +76 -44
- autogluon/timeseries/models/ensemble/__init__.py +29 -2
- autogluon/timeseries/models/ensemble/abstract.py +16 -52
- autogluon/timeseries/models/ensemble/array_based/__init__.py +3 -0
- autogluon/timeseries/models/ensemble/array_based/abstract.py +247 -0
- autogluon/timeseries/models/ensemble/array_based/models.py +50 -0
- autogluon/timeseries/models/ensemble/array_based/regressor/__init__.py +10 -0
- autogluon/timeseries/models/ensemble/array_based/regressor/abstract.py +87 -0
- autogluon/timeseries/models/ensemble/array_based/regressor/per_quantile_tabular.py +133 -0
- autogluon/timeseries/models/ensemble/array_based/regressor/tabular.py +141 -0
- autogluon/timeseries/models/ensemble/weighted/__init__.py +8 -0
- autogluon/timeseries/models/ensemble/weighted/abstract.py +41 -0
- autogluon/timeseries/models/ensemble/{basic.py → weighted/basic.py} +8 -18
- autogluon/timeseries/models/ensemble/{greedy.py → weighted/greedy.py} +13 -13
- autogluon/timeseries/models/gluonts/abstract.py +26 -26
- autogluon/timeseries/models/gluonts/dataset.py +4 -4
- autogluon/timeseries/models/gluonts/models.py +27 -12
- autogluon/timeseries/models/local/abstract_local_model.py +14 -14
- autogluon/timeseries/models/local/naive.py +4 -0
- autogluon/timeseries/models/local/npts.py +1 -0
- autogluon/timeseries/models/local/statsforecast.py +30 -14
- autogluon/timeseries/models/multi_window/multi_window_model.py +34 -23
- autogluon/timeseries/models/registry.py +65 -0
- 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 +197 -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 +94 -0
- autogluon/timeseries/models/toto/_internal/backbone/scaler.py +306 -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 +119 -0
- autogluon/timeseries/models/toto/model.py +236 -0
- autogluon/timeseries/predictor.py +94 -107
- autogluon/timeseries/regressor.py +31 -27
- autogluon/timeseries/splitter.py +7 -31
- autogluon/timeseries/trainer/__init__.py +3 -0
- autogluon/timeseries/trainer/ensemble_composer.py +250 -0
- autogluon/timeseries/trainer/model_set_builder.py +256 -0
- autogluon/timeseries/trainer/prediction_cache.py +149 -0
- autogluon/timeseries/{trainer.py → trainer/trainer.py} +182 -307
- autogluon/timeseries/trainer/utils.py +18 -0
- autogluon/timeseries/transforms/covariate_scaler.py +4 -4
- autogluon/timeseries/transforms/target_scaler.py +14 -14
- autogluon/timeseries/utils/datetime/lags.py +2 -2
- autogluon/timeseries/utils/datetime/time_features.py +2 -2
- autogluon/timeseries/utils/features.py +41 -37
- autogluon/timeseries/utils/forecast.py +5 -5
- autogluon/timeseries/utils/warning_filters.py +3 -1
- autogluon/timeseries/version.py +1 -1
- autogluon.timeseries-1.4.1b20251116-py3.9-nspkg.pth +1 -0
- {autogluon.timeseries-1.3.2b20250712.dist-info → autogluon_timeseries-1.4.1b20251116.dist-info}/METADATA +32 -17
- autogluon_timeseries-1.4.1b20251116.dist-info/RECORD +96 -0
- {autogluon.timeseries-1.3.2b20250712.dist-info → autogluon_timeseries-1.4.1b20251116.dist-info}/WHEEL +1 -1
- autogluon/timeseries/configs/presets_configs.py +0 -79
- 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 -530
- autogluon/timeseries/models/presets.py +0 -358
- autogluon.timeseries-1.3.2b20250712-py3.9-nspkg.pth +0 -1
- autogluon.timeseries-1.3.2b20250712.dist-info/RECORD +0 -71
- {autogluon.timeseries-1.3.2b20250712.dist-info → autogluon_timeseries-1.4.1b20251116.dist-info/licenses}/LICENSE +0 -0
- {autogluon.timeseries-1.3.2b20250712.dist-info → autogluon_timeseries-1.4.1b20251116.dist-info/licenses}/NOTICE +0 -0
- {autogluon.timeseries-1.3.2b20250712.dist-info → autogluon_timeseries-1.4.1b20251116.dist-info}/namespace_packages.txt +0 -0
- {autogluon.timeseries-1.3.2b20250712.dist-info → autogluon_timeseries-1.4.1b20251116.dist-info}/top_level.txt +0 -0
- {autogluon.timeseries-1.3.2b20250712.dist-info → autogluon_timeseries-1.4.1b20251116.dist-info}/zip-safe +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from pprint import pformat
|
|
4
|
-
from typing import Any,
|
|
4
|
+
from typing import Any, Optional, Sequence, Type, Union
|
|
5
5
|
|
|
6
6
|
import numpy as np
|
|
7
7
|
|
|
@@ -28,7 +28,7 @@ __all__ = [
|
|
|
28
28
|
|
|
29
29
|
DEFAULT_METRIC_NAME = "WQL"
|
|
30
30
|
|
|
31
|
-
AVAILABLE_METRICS:
|
|
31
|
+
AVAILABLE_METRICS: dict[str, Type[TimeSeriesScorer]] = {
|
|
32
32
|
"MASE": MASE,
|
|
33
33
|
"MAPE": MAPE,
|
|
34
34
|
"SMAPE": SMAPE,
|
|
@@ -48,7 +48,7 @@ DEPRECATED_METRICS = {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
# Experimental metrics that are not yet user facing
|
|
51
|
-
EXPERIMENTAL_METRICS:
|
|
51
|
+
EXPERIMENTAL_METRICS: dict[str, Type[TimeSeriesScorer]] = {
|
|
52
52
|
"WCD": WCD,
|
|
53
53
|
}
|
|
54
54
|
|
|
@@ -63,7 +63,7 @@ def check_get_evaluation_metric(
|
|
|
63
63
|
|
|
64
64
|
Returns
|
|
65
65
|
-------
|
|
66
|
-
scorer
|
|
66
|
+
scorer
|
|
67
67
|
A `TimeSeriesScorer` object based on the provided `eval_metric`.
|
|
68
68
|
|
|
69
69
|
`scorer.prediction_length` is always set to the `prediction_length` provided to this method.
|
|
@@ -75,7 +75,7 @@ def check_get_evaluation_metric(
|
|
|
75
75
|
value of `horizon_weight` is kept.
|
|
76
76
|
"""
|
|
77
77
|
scorer: TimeSeriesScorer
|
|
78
|
-
metric_kwargs:
|
|
78
|
+
metric_kwargs: dict[str, Any] = dict(
|
|
79
79
|
prediction_length=prediction_length, seasonal_period=seasonal_period, horizon_weight=horizon_weight
|
|
80
80
|
)
|
|
81
81
|
if isinstance(eval_metric, TimeSeriesScorer):
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import warnings
|
|
2
|
-
from typing import Optional, Sequence,
|
|
2
|
+
from typing import Optional, Sequence, Union, overload
|
|
3
3
|
|
|
4
4
|
import numpy as np
|
|
5
|
-
import numpy.typing as npt
|
|
6
5
|
import pandas as pd
|
|
7
6
|
|
|
8
7
|
from autogluon.timeseries import TimeSeriesDataFrame
|
|
@@ -20,14 +19,14 @@ class TimeSeriesScorer:
|
|
|
20
19
|
Parameters
|
|
21
20
|
----------
|
|
22
21
|
prediction_length : int, default = 1
|
|
23
|
-
The length of the forecast horizon. The predictions provided to the
|
|
22
|
+
The length of the forecast horizon. The predictions provided to the ``TimeSeriesScorer`` are expected to contain
|
|
24
23
|
a forecast for this many time steps for each time series.
|
|
25
24
|
seasonal_period : int or None, default = None
|
|
26
25
|
Seasonal period used to compute some evaluation metrics such as mean absolute scaled error (MASE). Defaults to
|
|
27
|
-
|
|
26
|
+
``None``, in which case the seasonal period is computed based on the data frequency.
|
|
28
27
|
horizon_weight : Sequence[float], np.ndarray or None, default = None
|
|
29
28
|
Weight assigned to each time step in the forecast horizon when computing the metric. If provided, the
|
|
30
|
-
|
|
29
|
+
``horizon_weight`` will be stored as a numpy array of shape ``[1, prediction_length]``.
|
|
31
30
|
|
|
32
31
|
Attributes
|
|
33
32
|
----------
|
|
@@ -44,8 +43,9 @@ class TimeSeriesScorer:
|
|
|
44
43
|
Whether the given metric uses the quantile predictions. Some models will modify the training procedure if they
|
|
45
44
|
are trained to optimize a quantile metric.
|
|
46
45
|
equivalent_tabular_regression_metric : str
|
|
47
|
-
Name of an equivalent metric used by AutoGluon-Tabular with ``problem_type="regression"``. Used by
|
|
48
|
-
train
|
|
46
|
+
Name of an equivalent metric used by AutoGluon-Tabular with ``problem_type="regression"``. Used by forecasting
|
|
47
|
+
models that train tabular regression models under the hood. This attribute should only be specified by point
|
|
48
|
+
forecast metrics.
|
|
49
49
|
"""
|
|
50
50
|
|
|
51
51
|
greater_is_better_internal: bool = False
|
|
@@ -199,14 +199,14 @@ class TimeSeriesScorer:
|
|
|
199
199
|
@staticmethod
|
|
200
200
|
def _get_point_forecast_score_inputs(
|
|
201
201
|
data_future: TimeSeriesDataFrame, predictions: TimeSeriesDataFrame, target: str = "target"
|
|
202
|
-
) ->
|
|
202
|
+
) -> tuple[pd.Series, pd.Series]:
|
|
203
203
|
"""Get inputs necessary to compute point forecast metrics.
|
|
204
204
|
|
|
205
205
|
Returns
|
|
206
206
|
-------
|
|
207
|
-
y_true
|
|
207
|
+
y_true
|
|
208
208
|
Target time series values during the forecast horizon.
|
|
209
|
-
y_pred
|
|
209
|
+
y_pred
|
|
210
210
|
Predicted time series values during the forecast horizon.
|
|
211
211
|
"""
|
|
212
212
|
y_true = data_future[target]
|
|
@@ -216,16 +216,16 @@ class TimeSeriesScorer:
|
|
|
216
216
|
@staticmethod
|
|
217
217
|
def _get_quantile_forecast_score_inputs(
|
|
218
218
|
data_future: TimeSeriesDataFrame, predictions: TimeSeriesDataFrame, target: str = "target"
|
|
219
|
-
) ->
|
|
219
|
+
) -> tuple[pd.Series, pd.DataFrame, np.ndarray]:
|
|
220
220
|
"""Get inputs necessary to compute quantile forecast metrics.
|
|
221
221
|
|
|
222
222
|
Returns
|
|
223
223
|
-------
|
|
224
|
-
y_true
|
|
224
|
+
y_true
|
|
225
225
|
Target time series values during the forecast horizon.
|
|
226
|
-
q_pred
|
|
226
|
+
q_pred
|
|
227
227
|
Quantile forecast for each predicted quantile level. Column order corresponds to ``quantile_levels``.
|
|
228
|
-
quantile_levels
|
|
228
|
+
quantile_levels
|
|
229
229
|
Quantile levels for which the forecasts are generated (as floats).
|
|
230
230
|
"""
|
|
231
231
|
quantile_columns = [col for col in predictions.columns if col != "mean"]
|
|
@@ -241,18 +241,18 @@ class TimeSeriesScorer:
|
|
|
241
241
|
@staticmethod
|
|
242
242
|
def check_get_horizon_weight(
|
|
243
243
|
horizon_weight: Union[Sequence[float], np.ndarray], prediction_length: int
|
|
244
|
-
) ->
|
|
244
|
+
) -> np.ndarray: ...
|
|
245
245
|
|
|
246
246
|
@staticmethod
|
|
247
247
|
def check_get_horizon_weight(
|
|
248
248
|
horizon_weight: Union[Sequence[float], np.ndarray, None], prediction_length: int
|
|
249
|
-
) -> Optional[
|
|
249
|
+
) -> Optional[np.ndarray]:
|
|
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
|
|
|
253
253
|
Returns
|
|
254
254
|
-------
|
|
255
|
-
horizon_weight
|
|
255
|
+
horizon_weight
|
|
256
256
|
None if the input is None, otherwise a numpy array of shape [1, prediction_length].
|
|
257
257
|
"""
|
|
258
258
|
if horizon_weight is None:
|
|
@@ -143,7 +143,7 @@ class WAPE(TimeSeriesScorer):
|
|
|
143
143
|
- not sensitive to outliers
|
|
144
144
|
- prefers models that accurately estimate the median
|
|
145
145
|
|
|
146
|
-
If
|
|
146
|
+
If ``self.horizon_weight`` is provided, both the errors and the target time series in the denominator will be re-weighted.
|
|
147
147
|
|
|
148
148
|
References
|
|
149
149
|
----------
|
|
@@ -3,7 +3,7 @@ from typing import Optional, Sequence
|
|
|
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
|
|
@@ -25,7 +25,7 @@ class WQL(TimeSeriesScorer):
|
|
|
25
25
|
- scale-dependent (time series with large absolute value contribute more to the loss)
|
|
26
26
|
- equivalent to WAPE if ``quantile_levels = [0.5]``
|
|
27
27
|
|
|
28
|
-
If
|
|
28
|
+
If ``horizon_weight`` is provided, both the errors and the target time series in the denominator will be re-weighted.
|
|
29
29
|
|
|
30
30
|
References
|
|
31
31
|
----------
|
|
@@ -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)
|
|
@@ -27,6 +27,8 @@ from .local import (
|
|
|
27
27
|
ThetaModel,
|
|
28
28
|
ZeroModel,
|
|
29
29
|
)
|
|
30
|
+
from .registry import ModelRegistry
|
|
31
|
+
from .toto import TotoModel
|
|
30
32
|
|
|
31
33
|
__all__ = [
|
|
32
34
|
"ADIDAModel",
|
|
@@ -43,6 +45,7 @@ __all__ = [
|
|
|
43
45
|
"ETSModel",
|
|
44
46
|
"IMAPAModel",
|
|
45
47
|
"ChronosModel",
|
|
48
|
+
"ModelRegistry",
|
|
46
49
|
"NPTSModel",
|
|
47
50
|
"NaiveModel",
|
|
48
51
|
"PatchTSTModel",
|
|
@@ -54,6 +57,7 @@ __all__ = [
|
|
|
54
57
|
"TemporalFusionTransformerModel",
|
|
55
58
|
"ThetaModel",
|
|
56
59
|
"TiDEModel",
|
|
60
|
+
"TotoModel",
|
|
57
61
|
"WaveNetModel",
|
|
58
62
|
"ZeroModel",
|
|
59
63
|
]
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
1
|
import copy
|
|
4
2
|
import logging
|
|
5
3
|
import os
|
|
6
4
|
import re
|
|
7
5
|
import time
|
|
8
6
|
from abc import ABC, abstractmethod
|
|
9
|
-
from typing import Any,
|
|
7
|
+
from typing import Any, Optional, Sequence, Union
|
|
10
8
|
|
|
11
9
|
import pandas as pd
|
|
12
10
|
from typing_extensions import Self
|
|
@@ -21,6 +19,7 @@ from autogluon.core.models import ModelBase
|
|
|
21
19
|
from autogluon.core.utils.exceptions import TimeLimitExceeded
|
|
22
20
|
from autogluon.timeseries.dataset import TimeSeriesDataFrame
|
|
23
21
|
from autogluon.timeseries.metrics import TimeSeriesScorer, check_get_evaluation_metric
|
|
22
|
+
from autogluon.timeseries.models.registry import ModelRegistry
|
|
24
23
|
from autogluon.timeseries.regressor import CovariateRegressor, get_covariate_regressor
|
|
25
24
|
from autogluon.timeseries.transforms import CovariateScaler, TargetScaler, get_covariate_scaler, get_target_scaler
|
|
26
25
|
from autogluon.timeseries.utils.features import CovariateMetadata
|
|
@@ -37,27 +36,27 @@ class TimeSeriesModelBase(ModelBase, ABC):
|
|
|
37
36
|
|
|
38
37
|
Parameters
|
|
39
38
|
----------
|
|
40
|
-
path
|
|
39
|
+
path
|
|
41
40
|
Directory location to store all outputs.
|
|
42
41
|
If None, a new unique time-stamped directory is chosen.
|
|
43
|
-
freq
|
|
42
|
+
freq
|
|
44
43
|
Frequency string (cf. gluonts frequency strings) describing the frequency
|
|
45
44
|
of the time series data. For example, "h" for hourly or "D" for daily data.
|
|
46
|
-
prediction_length
|
|
45
|
+
prediction_length
|
|
47
46
|
Length of the prediction horizon, i.e., the number of time steps the model
|
|
48
47
|
is fit to forecast.
|
|
49
|
-
name
|
|
48
|
+
name
|
|
50
49
|
Name of the subdirectory inside path where model will be saved.
|
|
51
50
|
The final model directory will be os.path.join(path, name)
|
|
52
51
|
If None, defaults to the model's class name: self.__class__.__name__
|
|
53
|
-
covariate_metadata
|
|
52
|
+
covariate_metadata
|
|
54
53
|
A mapping of different covariate types known to autogluon.timeseries to column names
|
|
55
54
|
in the data set.
|
|
56
|
-
eval_metric
|
|
55
|
+
eval_metric
|
|
57
56
|
Metric by which predictions will be ultimately evaluated on future test data. This only impacts
|
|
58
57
|
``model.score()``, as eval_metric is not used during training. Available metrics can be found in
|
|
59
58
|
``autogluon.timeseries.metrics``.
|
|
60
|
-
hyperparameters
|
|
59
|
+
hyperparameters
|
|
61
60
|
Hyperparameters that will be used by the model (can be search spaces instead of fixed values).
|
|
62
61
|
If None, model defaults are used. This is identical to passing an empty dictionary.
|
|
63
62
|
"""
|
|
@@ -78,7 +77,7 @@ class TimeSeriesModelBase(ModelBase, ABC):
|
|
|
78
77
|
self,
|
|
79
78
|
path: Optional[str] = None,
|
|
80
79
|
name: Optional[str] = None,
|
|
81
|
-
hyperparameters: Optional[
|
|
80
|
+
hyperparameters: Optional[dict[str, Any]] = None,
|
|
82
81
|
freq: Optional[str] = None,
|
|
83
82
|
prediction_length: int = 1,
|
|
84
83
|
covariate_metadata: Optional[CovariateMetadata] = None,
|
|
@@ -118,7 +117,7 @@ class TimeSeriesModelBase(ModelBase, ABC):
|
|
|
118
117
|
else:
|
|
119
118
|
self.must_drop_median = False
|
|
120
119
|
|
|
121
|
-
self._oof_predictions: Optional[
|
|
120
|
+
self._oof_predictions: Optional[list[TimeSeriesDataFrame]] = None
|
|
122
121
|
|
|
123
122
|
# user provided hyperparameters and extra arguments that are used during model training
|
|
124
123
|
self._hyperparameters, self._extra_ag_args = self._check_and_split_hyperparameters(hyperparameters)
|
|
@@ -146,22 +145,21 @@ class TimeSeriesModelBase(ModelBase, ABC):
|
|
|
146
145
|
|
|
147
146
|
@classmethod
|
|
148
147
|
def _check_and_split_hyperparameters(
|
|
149
|
-
cls, hyperparameters: Optional[
|
|
150
|
-
) ->
|
|
151
|
-
"""
|
|
152
|
-
Given the user-specified hyperparameters, split into `hyperparameters` and `extra_ag_args`, intended
|
|
148
|
+
cls, hyperparameters: Optional[dict[str, Any]] = None
|
|
149
|
+
) -> tuple[dict[str, Any], dict[str, Any]]:
|
|
150
|
+
"""Given the user-specified hyperparameters, split into `hyperparameters` and `extra_ag_args`, intended
|
|
153
151
|
to be used during model initialization.
|
|
154
152
|
|
|
155
153
|
Parameters
|
|
156
154
|
----------
|
|
157
|
-
hyperparameters
|
|
155
|
+
hyperparameters
|
|
158
156
|
The model hyperparameters dictionary provided to the model constructor.
|
|
159
157
|
|
|
160
158
|
Returns
|
|
161
159
|
-------
|
|
162
|
-
hyperparameters
|
|
160
|
+
hyperparameters
|
|
163
161
|
Native model hyperparameters that are passed into the "inner model" AutoGluon wraps
|
|
164
|
-
extra_ag_args
|
|
162
|
+
extra_ag_args
|
|
165
163
|
Special auxiliary parameters that modify the model training process used by AutoGluon
|
|
166
164
|
"""
|
|
167
165
|
hyperparameters = copy.deepcopy(hyperparameters) if hyperparameters is not None else dict()
|
|
@@ -213,7 +211,7 @@ class TimeSeriesModelBase(ModelBase, ABC):
|
|
|
213
211
|
return model
|
|
214
212
|
|
|
215
213
|
@classmethod
|
|
216
|
-
def load_oof_predictions(cls, path: str, verbose: bool = True) ->
|
|
214
|
+
def load_oof_predictions(cls, path: str, verbose: bool = True) -> list[TimeSeriesDataFrame]:
|
|
217
215
|
"""Load the cached OOF predictions from disk."""
|
|
218
216
|
return load_pkl.load(path=os.path.join(path, "utils", cls._oof_filename), verbose=verbose)
|
|
219
217
|
|
|
@@ -283,7 +281,7 @@ class TimeSeriesModelBase(ModelBase, ABC):
|
|
|
283
281
|
return False
|
|
284
282
|
|
|
285
283
|
@staticmethod
|
|
286
|
-
def _get_system_resources() ->
|
|
284
|
+
def _get_system_resources() -> dict[str, Any]:
|
|
287
285
|
resource_manager = get_resource_manager()
|
|
288
286
|
system_num_cpus = resource_manager.get_cpu_count()
|
|
289
287
|
system_num_gpus = resource_manager.get_gpu_count()
|
|
@@ -305,7 +303,8 @@ class TimeSeriesModelBase(ModelBase, ABC):
|
|
|
305
303
|
def _more_tags(self) -> dict:
|
|
306
304
|
"""Encode model properties using tags, similar to sklearn & autogluon.tabular.
|
|
307
305
|
|
|
308
|
-
For more details, see `autogluon.core.models.abstract.AbstractModel._get_tags()` and
|
|
306
|
+
For more details, see `autogluon.core.models.abstract.AbstractModel._get_tags()` and
|
|
307
|
+
https://scikit-learn.org/stable/_sources/developers/develop.rst.txt.
|
|
309
308
|
|
|
310
309
|
List of currently supported tags:
|
|
311
310
|
- allow_nan: Can the model handle data with missing values represented by np.nan?
|
|
@@ -360,6 +359,10 @@ class TimeSeriesModelBase(ModelBase, ABC):
|
|
|
360
359
|
"""After calling this function, returned model should be able to be fit without `val_data`."""
|
|
361
360
|
params = copy.deepcopy(self.get_params())
|
|
362
361
|
|
|
362
|
+
# Remove 0.5 from quantile_levels so that the cloned model sets its must_drop_median correctly
|
|
363
|
+
if self.must_drop_median:
|
|
364
|
+
params["quantile_levels"].remove(0.5)
|
|
365
|
+
|
|
363
366
|
if "hyperparameters" not in params:
|
|
364
367
|
params["hyperparameters"] = dict()
|
|
365
368
|
|
|
@@ -372,16 +375,18 @@ class TimeSeriesModelBase(ModelBase, ABC):
|
|
|
372
375
|
return template
|
|
373
376
|
|
|
374
377
|
|
|
375
|
-
class AbstractTimeSeriesModel(TimeSeriesModelBase, TimeSeriesTunable,
|
|
378
|
+
class AbstractTimeSeriesModel(TimeSeriesModelBase, TimeSeriesTunable, metaclass=ModelRegistry):
|
|
376
379
|
"""Abstract base class for all time series models that take historical data as input and
|
|
377
380
|
make predictions for the forecast horizon.
|
|
378
381
|
"""
|
|
379
382
|
|
|
383
|
+
ag_priority: int = 0
|
|
384
|
+
|
|
380
385
|
def __init__(
|
|
381
386
|
self,
|
|
382
387
|
path: Optional[str] = None,
|
|
383
388
|
name: Optional[str] = None,
|
|
384
|
-
hyperparameters: Optional[
|
|
389
|
+
hyperparameters: Optional[dict[str, Any]] = None,
|
|
385
390
|
freq: Optional[str] = None,
|
|
386
391
|
prediction_length: int = 1,
|
|
387
392
|
covariate_metadata: Optional[CovariateMetadata] = None,
|
|
@@ -421,9 +426,9 @@ class AbstractTimeSeriesModel(TimeSeriesModelBase, TimeSeriesTunable, ABC):
|
|
|
421
426
|
)
|
|
422
427
|
|
|
423
428
|
@property
|
|
424
|
-
def allowed_hyperparameters(self) ->
|
|
429
|
+
def allowed_hyperparameters(self) -> list[str]:
|
|
425
430
|
"""List of hyperparameters allowed by the model."""
|
|
426
|
-
return ["target_scaler", "covariate_regressor"]
|
|
431
|
+
return ["target_scaler", "covariate_regressor", "covariate_scaler"]
|
|
427
432
|
|
|
428
433
|
def fit(
|
|
429
434
|
self,
|
|
@@ -438,32 +443,32 @@ class AbstractTimeSeriesModel(TimeSeriesModelBase, TimeSeriesTunable, ABC):
|
|
|
438
443
|
Models should not override the `fit` method, but instead override the `_fit` method which
|
|
439
444
|
has the same arguments.
|
|
440
445
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
train_data
|
|
446
|
+
Parameters
|
|
447
|
+
----------
|
|
448
|
+
train_data
|
|
444
449
|
The training data provided in the library's `autogluon.timeseries.dataset.TimeSeriesDataFrame`
|
|
445
450
|
format.
|
|
446
|
-
val_data
|
|
451
|
+
val_data
|
|
447
452
|
The validation data set in the same format as training data.
|
|
448
|
-
time_limit
|
|
453
|
+
time_limit
|
|
449
454
|
Time limit in seconds to adhere to when fitting model.
|
|
450
455
|
Ideally, model should early stop during fit to avoid going over the time limit if specified.
|
|
451
|
-
num_cpus
|
|
456
|
+
num_cpus
|
|
452
457
|
How many CPUs to use during fit.
|
|
453
458
|
This is counted in virtual cores, not in physical cores.
|
|
454
459
|
If 'auto', model decides.
|
|
455
|
-
num_gpus
|
|
460
|
+
num_gpus
|
|
456
461
|
How many GPUs to use during fit.
|
|
457
462
|
If 'auto', model decides.
|
|
458
|
-
verbosity
|
|
463
|
+
verbosity
|
|
459
464
|
Verbosity levels range from 0 to 4 and control how much information is printed.
|
|
460
465
|
Higher levels correspond to more detailed print statements (you can set verbosity = 0 to suppress warnings).
|
|
461
|
-
**kwargs
|
|
466
|
+
**kwargs
|
|
462
467
|
Any additional fit arguments a model supports.
|
|
463
468
|
|
|
464
469
|
Returns
|
|
465
470
|
-------
|
|
466
|
-
model
|
|
471
|
+
model
|
|
467
472
|
The fitted model object
|
|
468
473
|
"""
|
|
469
474
|
start_time = time.monotonic()
|
|
@@ -546,7 +551,7 @@ class AbstractTimeSeriesModel(TimeSeriesModelBase, TimeSeriesTunable, ABC):
|
|
|
546
551
|
"as hyperparameters when initializing or use `hyperparameter_tune` instead."
|
|
547
552
|
)
|
|
548
553
|
|
|
549
|
-
def _log_unused_hyperparameters(self, extra_allowed_hyperparameters: list[str]
|
|
554
|
+
def _log_unused_hyperparameters(self, extra_allowed_hyperparameters: Optional[list[str]] = None) -> None:
|
|
550
555
|
"""Log a warning if unused hyperparameters were provided to the model."""
|
|
551
556
|
allowed_hyperparameters = self.allowed_hyperparameters
|
|
552
557
|
if extra_allowed_hyperparameters is not None:
|
|
@@ -574,15 +579,15 @@ class AbstractTimeSeriesModel(TimeSeriesModelBase, TimeSeriesTunable, ABC):
|
|
|
574
579
|
|
|
575
580
|
Parameters
|
|
576
581
|
----------
|
|
577
|
-
data
|
|
582
|
+
data
|
|
578
583
|
The dataset where each time series is the "context" for predictions. For ensemble models that depend on
|
|
579
584
|
the predictions of other models, this method may accept a dictionary of previous models' predictions.
|
|
580
|
-
known_covariates
|
|
585
|
+
known_covariates
|
|
581
586
|
A TimeSeriesDataFrame containing the values of the known covariates during the forecast horizon.
|
|
582
587
|
|
|
583
588
|
Returns
|
|
584
589
|
-------
|
|
585
|
-
predictions
|
|
590
|
+
predictions
|
|
586
591
|
pandas dataframes with a timestamp index, where each input item from the input
|
|
587
592
|
data is given as a separate forecast item in the dictionary, keyed by the `item_id`s
|
|
588
593
|
of input items.
|
|
@@ -604,11 +609,13 @@ class AbstractTimeSeriesModel(TimeSeriesModelBase, TimeSeriesTunable, ABC):
|
|
|
604
609
|
predictions = self._predict(data=data, known_covariates=known_covariates, **kwargs)
|
|
605
610
|
self.covariate_regressor = covariate_regressor
|
|
606
611
|
|
|
607
|
-
|
|
612
|
+
# Ensure that 'mean' is the leading column. Trailing columns might not match quantile_levels if self is
|
|
613
|
+
# a MultiWindowBacktestingModel and base_model.must_drop_median=True
|
|
614
|
+
column_order = pd.Index(["mean"] + [col for col in predictions.columns if col != "mean"])
|
|
608
615
|
if not predictions.columns.equals(column_order):
|
|
609
616
|
predictions = predictions.reindex(columns=column_order)
|
|
610
617
|
|
|
611
|
-
# "0.5" might be missing from the quantiles if self is a
|
|
618
|
+
# "0.5" might be missing from the quantiles if self is a MultiWindowBacktestingModel
|
|
612
619
|
if "0.5" in predictions.columns:
|
|
613
620
|
if self.eval_metric.optimized_by_median:
|
|
614
621
|
predictions["mean"] = predictions["0.5"]
|
|
@@ -631,36 +638,6 @@ class AbstractTimeSeriesModel(TimeSeriesModelBase, TimeSeriesTunable, ABC):
|
|
|
631
638
|
predictions = self.target_scaler.inverse_transform(predictions)
|
|
632
639
|
return predictions
|
|
633
640
|
|
|
634
|
-
def convert_to_refit_full_via_copy(self) -> Self:
|
|
635
|
-
# save the model as a new model on disk
|
|
636
|
-
previous_name = self.name
|
|
637
|
-
self.rename(self.name + REFIT_FULL_SUFFIX)
|
|
638
|
-
refit_model_path = self.path
|
|
639
|
-
self.save(path=self.path, verbose=False)
|
|
640
|
-
|
|
641
|
-
self.rename(previous_name)
|
|
642
|
-
|
|
643
|
-
refit_model = self.load(path=refit_model_path, verbose=False)
|
|
644
|
-
refit_model.val_score = None
|
|
645
|
-
refit_model.predict_time = None
|
|
646
|
-
|
|
647
|
-
return refit_model
|
|
648
|
-
|
|
649
|
-
def convert_to_refit_full_template(self):
|
|
650
|
-
"""After calling this function, returned model should be able to be fit without `val_data`."""
|
|
651
|
-
params = copy.deepcopy(self.get_params())
|
|
652
|
-
|
|
653
|
-
if "hyperparameters" not in params:
|
|
654
|
-
params["hyperparameters"] = dict()
|
|
655
|
-
|
|
656
|
-
if AG_ARGS_FIT not in params["hyperparameters"]:
|
|
657
|
-
params["hyperparameters"][AG_ARGS_FIT] = dict()
|
|
658
|
-
|
|
659
|
-
params["name"] = params["name"] + REFIT_FULL_SUFFIX
|
|
660
|
-
template = self.__class__(**params)
|
|
661
|
-
|
|
662
|
-
return template
|
|
663
|
-
|
|
664
641
|
def get_forecast_horizon_index(self, data: TimeSeriesDataFrame) -> pd.MultiIndex:
|
|
665
642
|
"""For each item in the dataframe, get timestamps for the next `prediction_length` time steps into the future."""
|
|
666
643
|
return pd.MultiIndex.from_frame(
|
|
@@ -726,12 +703,12 @@ class AbstractTimeSeriesModel(TimeSeriesModelBase, TimeSeriesTunable, ABC):
|
|
|
726
703
|
|
|
727
704
|
Parameters
|
|
728
705
|
----------
|
|
729
|
-
data
|
|
706
|
+
data
|
|
730
707
|
Dataset used for scoring.
|
|
731
708
|
|
|
732
709
|
Returns
|
|
733
710
|
-------
|
|
734
|
-
score
|
|
711
|
+
score
|
|
735
712
|
The computed forecast evaluation score on the last `self.prediction_length`
|
|
736
713
|
time steps of each time series.
|
|
737
714
|
"""
|
|
@@ -766,6 +743,6 @@ class AbstractTimeSeriesModel(TimeSeriesModelBase, TimeSeriesTunable, ABC):
|
|
|
766
743
|
known_covariates: Optional[TimeSeriesDataFrame] = None,
|
|
767
744
|
is_train: bool = False,
|
|
768
745
|
**kwargs,
|
|
769
|
-
) ->
|
|
746
|
+
) -> tuple[TimeSeriesDataFrame, Optional[TimeSeriesDataFrame]]:
|
|
770
747
|
"""Method that implements model-specific preprocessing logic."""
|
|
771
748
|
return data, known_covariates
|
|
@@ -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, Optional, Union
|
|
9
9
|
|
|
10
10
|
from typing_extensions import Self
|
|
11
11
|
|
|
@@ -43,7 +43,7 @@ class TimeSeriesTunable(Tunable, ABC):
|
|
|
43
43
|
refit_every_n_windows: Optional[int] = 1,
|
|
44
44
|
hyperparameter_tune_kwargs: Union[str, dict] = "auto",
|
|
45
45
|
time_limit: Optional[float] = None,
|
|
46
|
-
) ->
|
|
46
|
+
) -> tuple[dict[str, Any], Any]:
|
|
47
47
|
hpo_executor = self._get_default_hpo_executor()
|
|
48
48
|
hpo_executor.initialize(
|
|
49
49
|
hyperparameter_tune_kwargs, default_num_trials=default_num_trials, time_limit=time_limit
|
|
@@ -144,14 +144,14 @@ class TimeSeriesTunable(Tunable, ABC):
|
|
|
144
144
|
"""
|
|
145
145
|
return None
|
|
146
146
|
|
|
147
|
-
def get_minimum_resources(self, is_gpu_available: bool = False) ->
|
|
147
|
+
def get_minimum_resources(self, is_gpu_available: bool = False) -> dict[str, Union[int, float]]:
|
|
148
148
|
return {
|
|
149
149
|
"num_cpus": 1,
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
def _save_with_data(
|
|
153
153
|
self, train_data: TimeSeriesDataFrame, val_data: Optional[TimeSeriesDataFrame]
|
|
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]
|
|
157
157
|
|
|
@@ -173,7 +173,7 @@ class TimeSeriesTunable(Tunable, ABC):
|
|
|
173
173
|
pass
|
|
174
174
|
|
|
175
175
|
@abstractmethod
|
|
176
|
-
def _get_search_space(self) ->
|
|
176
|
+
def _get_search_space(self) -> dict[str, Any]:
|
|
177
177
|
pass
|
|
178
178
|
|
|
179
179
|
@abstractmethod
|
|
@@ -185,5 +185,5 @@ class TimeSeriesTunable(Tunable, ABC):
|
|
|
185
185
|
|
|
186
186
|
@staticmethod
|
|
187
187
|
@abstractmethod
|
|
188
|
-
def _get_system_resources() ->
|
|
188
|
+
def _get_system_resources() -> dict[str, Any]:
|
|
189
189
|
pass
|