autogluon.timeseries 1.4.1b20250820__py3-none-any.whl → 1.4.1b20250902__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 +9 -9
- autogluon/timeseries/learner.py +14 -14
- autogluon/timeseries/metrics/__init__.py +5 -5
- autogluon/timeseries/metrics/abstract.py +11 -12
- autogluon/timeseries/models/__init__.py +2 -0
- autogluon/timeseries/models/abstract/abstract_timeseries_model.py +39 -41
- autogluon/timeseries/models/abstract/tunable.py +6 -6
- autogluon/timeseries/models/autogluon_tabular/mlforecast.py +30 -30
- autogluon/timeseries/models/autogluon_tabular/per_step.py +12 -12
- autogluon/timeseries/models/chronos/model.py +10 -10
- autogluon/timeseries/models/chronos/pipeline/base.py +8 -8
- autogluon/timeseries/models/chronos/pipeline/chronos.py +12 -12
- autogluon/timeseries/models/chronos/pipeline/chronos_bolt.py +12 -12
- autogluon/timeseries/models/chronos/pipeline/utils.py +12 -12
- autogluon/timeseries/models/ensemble/abstract.py +19 -19
- autogluon/timeseries/models/ensemble/basic.py +8 -8
- autogluon/timeseries/models/ensemble/greedy.py +13 -13
- autogluon/timeseries/models/gluonts/abstract.py +24 -24
- autogluon/timeseries/models/gluonts/dataset.py +2 -2
- autogluon/timeseries/models/gluonts/models.py +7 -7
- autogluon/timeseries/models/local/abstract_local_model.py +12 -12
- autogluon/timeseries/models/local/statsforecast.py +11 -11
- autogluon/timeseries/models/multi_window/multi_window_model.py +33 -22
- autogluon/timeseries/models/registry.py +3 -3
- autogluon/timeseries/predictor.py +37 -37
- autogluon/timeseries/regressor.py +13 -13
- autogluon/timeseries/splitter.py +6 -6
- autogluon/timeseries/trainer/__init__.py +3 -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} +72 -128
- autogluon/timeseries/transforms/covariate_scaler.py +3 -3
- autogluon/timeseries/transforms/target_scaler.py +7 -7
- autogluon/timeseries/utils/datetime/lags.py +2 -2
- autogluon/timeseries/utils/datetime/time_features.py +2 -2
- autogluon/timeseries/utils/features.py +32 -32
- autogluon/timeseries/version.py +1 -1
- {autogluon.timeseries-1.4.1b20250820.dist-info → autogluon.timeseries-1.4.1b20250902.dist-info}/METADATA +5 -5
- autogluon.timeseries-1.4.1b20250902.dist-info/RECORD +75 -0
- autogluon/timeseries/configs/presets_configs.py +0 -79
- autogluon/timeseries/models/presets.py +0 -280
- autogluon.timeseries-1.4.1b20250820.dist-info/RECORD +0 -72
- /autogluon.timeseries-1.4.1b20250820-py3.9-nspkg.pth → /autogluon.timeseries-1.4.1b20250902-py3.9-nspkg.pth +0 -0
- {autogluon.timeseries-1.4.1b20250820.dist-info → autogluon.timeseries-1.4.1b20250902.dist-info}/LICENSE +0 -0
- {autogluon.timeseries-1.4.1b20250820.dist-info → autogluon.timeseries-1.4.1b20250902.dist-info}/NOTICE +0 -0
- {autogluon.timeseries-1.4.1b20250820.dist-info → autogluon.timeseries-1.4.1b20250902.dist-info}/WHEEL +0 -0
- {autogluon.timeseries-1.4.1b20250820.dist-info → autogluon.timeseries-1.4.1b20250902.dist-info}/namespace_packages.txt +0 -0
- {autogluon.timeseries-1.4.1b20250820.dist-info → autogluon.timeseries-1.4.1b20250902.dist-info}/top_level.txt +0 -0
- {autogluon.timeseries-1.4.1b20250820.dist-info → autogluon.timeseries-1.4.1b20250902.dist-info}/zip-safe +0 -0
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
from enum import Enum
|
4
4
|
from pathlib import Path
|
5
|
-
from typing import TYPE_CHECKING,
|
5
|
+
from typing import TYPE_CHECKING, Optional, Union
|
6
6
|
|
7
7
|
import torch
|
8
8
|
|
@@ -18,7 +18,7 @@ class ForecastType(Enum):
|
|
18
18
|
|
19
19
|
|
20
20
|
class PipelineRegistry(type):
|
21
|
-
REGISTRY:
|
21
|
+
REGISTRY: dict[str, "PipelineRegistry"] = {}
|
22
22
|
|
23
23
|
def __new__(cls, name, bases, attrs):
|
24
24
|
"""See, https://github.com/faif/python-patterns."""
|
@@ -43,13 +43,13 @@ class BaseChronosPipeline(metaclass=PipelineRegistry):
|
|
43
43
|
"""
|
44
44
|
Parameters
|
45
45
|
----------
|
46
|
-
inner_model
|
46
|
+
inner_model
|
47
47
|
A hugging-face transformers PreTrainedModel, e.g., T5ForConditionalGeneration
|
48
48
|
"""
|
49
49
|
# for easy access to the inner HF-style model
|
50
50
|
self.inner_model = inner_model
|
51
51
|
|
52
|
-
def _prepare_and_validate_context(self, context: Union[torch.Tensor,
|
52
|
+
def _prepare_and_validate_context(self, context: Union[torch.Tensor, list[torch.Tensor]]):
|
53
53
|
if isinstance(context, list):
|
54
54
|
context = left_pad_and_stack_1D(context)
|
55
55
|
assert isinstance(context, torch.Tensor)
|
@@ -61,7 +61,7 @@ class BaseChronosPipeline(metaclass=PipelineRegistry):
|
|
61
61
|
|
62
62
|
def predict(
|
63
63
|
self,
|
64
|
-
context: Union[torch.Tensor,
|
64
|
+
context: Union[torch.Tensor, list[torch.Tensor]],
|
65
65
|
prediction_length: Optional[int] = None,
|
66
66
|
**kwargs,
|
67
67
|
):
|
@@ -88,8 +88,8 @@ class BaseChronosPipeline(metaclass=PipelineRegistry):
|
|
88
88
|
raise NotImplementedError()
|
89
89
|
|
90
90
|
def predict_quantiles(
|
91
|
-
self, context: torch.Tensor, prediction_length: int, quantile_levels:
|
92
|
-
) ->
|
91
|
+
self, context: torch.Tensor, prediction_length: int, quantile_levels: list[float], **kwargs
|
92
|
+
) -> tuple[torch.Tensor, torch.Tensor]:
|
93
93
|
"""
|
94
94
|
Get quantile and mean forecasts for given time series. All
|
95
95
|
predictions are returned on the CPU.
|
@@ -104,7 +104,7 @@ class BaseChronosPipeline(metaclass=PipelineRegistry):
|
|
104
104
|
prediction_length
|
105
105
|
Time steps to predict. Defaults to a model-dependent
|
106
106
|
value if not given.
|
107
|
-
quantile_levels
|
107
|
+
quantile_levels
|
108
108
|
Quantile levels to compute
|
109
109
|
|
110
110
|
Returns
|
@@ -7,7 +7,7 @@
|
|
7
7
|
import logging
|
8
8
|
import warnings
|
9
9
|
from dataclasses import dataclass
|
10
|
-
from typing import Any,
|
10
|
+
from typing import Any, Literal, Optional, Union
|
11
11
|
|
12
12
|
import torch
|
13
13
|
import torch.nn as nn
|
@@ -29,7 +29,7 @@ class ChronosConfig:
|
|
29
29
|
"""
|
30
30
|
|
31
31
|
tokenizer_class: str
|
32
|
-
tokenizer_kwargs:
|
32
|
+
tokenizer_kwargs: dict[str, Any]
|
33
33
|
n_tokens: int
|
34
34
|
n_special_tokens: int
|
35
35
|
pad_token_id: int
|
@@ -66,7 +66,7 @@ class ChronosTokenizer:
|
|
66
66
|
def context_input_transform(
|
67
67
|
self,
|
68
68
|
context: torch.Tensor,
|
69
|
-
) ->
|
69
|
+
) -> tuple:
|
70
70
|
"""
|
71
71
|
Turn a batch of time series into token IDs, attention mask, and tokenizer_state.
|
72
72
|
|
@@ -95,7 +95,7 @@ class ChronosTokenizer:
|
|
95
95
|
"""
|
96
96
|
raise NotImplementedError()
|
97
97
|
|
98
|
-
def label_input_transform(self, label: torch.Tensor, tokenizer_state: Any) ->
|
98
|
+
def label_input_transform(self, label: torch.Tensor, tokenizer_state: Any) -> tuple:
|
99
99
|
"""
|
100
100
|
Turn a batch of label slices of time series into token IDs and attention mask
|
101
101
|
using the ``tokenizer_state`` provided by ``context_input_transform``.
|
@@ -171,7 +171,7 @@ class MeanScaleUniformBins(ChronosTokenizer):
|
|
171
171
|
|
172
172
|
def _input_transform(
|
173
173
|
self, context: torch.Tensor, scale: Optional[torch.Tensor] = None
|
174
|
-
) ->
|
174
|
+
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
|
175
175
|
attention_mask = ~torch.isnan(context)
|
176
176
|
|
177
177
|
if scale is None:
|
@@ -196,7 +196,7 @@ class MeanScaleUniformBins(ChronosTokenizer):
|
|
196
196
|
|
197
197
|
def _append_eos_token(
|
198
198
|
self, token_ids: torch.Tensor, attention_mask: torch.Tensor
|
199
|
-
) ->
|
199
|
+
) -> tuple[torch.Tensor, torch.Tensor]:
|
200
200
|
batch_size = token_ids.shape[0]
|
201
201
|
eos_tokens = torch.full((batch_size, 1), fill_value=self.config.eos_token_id)
|
202
202
|
token_ids = torch.concat((token_ids, eos_tokens), dim=1)
|
@@ -205,7 +205,7 @@ class MeanScaleUniformBins(ChronosTokenizer):
|
|
205
205
|
|
206
206
|
return token_ids, attention_mask
|
207
207
|
|
208
|
-
def context_input_transform(self, context: torch.Tensor) ->
|
208
|
+
def context_input_transform(self, context: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
|
209
209
|
length = context.shape[-1]
|
210
210
|
|
211
211
|
if length > self.config.context_length:
|
@@ -218,7 +218,7 @@ class MeanScaleUniformBins(ChronosTokenizer):
|
|
218
218
|
|
219
219
|
return token_ids, attention_mask, scale
|
220
220
|
|
221
|
-
def label_input_transform(self, label: torch.Tensor, scale: torch.Tensor) ->
|
221
|
+
def label_input_transform(self, label: torch.Tensor, scale: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:
|
222
222
|
token_ids, attention_mask, _ = self._input_transform(context=label, scale=scale)
|
223
223
|
|
224
224
|
if self.config.use_eos_token:
|
@@ -371,7 +371,7 @@ class ChronosPipeline(BaseChronosPipeline):
|
|
371
371
|
self.model = model
|
372
372
|
|
373
373
|
@torch.no_grad()
|
374
|
-
def embed(self, context: Union[torch.Tensor,
|
374
|
+
def embed(self, context: Union[torch.Tensor, list[torch.Tensor]]) -> tuple[torch.Tensor, Any]:
|
375
375
|
"""
|
376
376
|
Get encoder embeddings for the given time series.
|
377
377
|
|
@@ -404,7 +404,7 @@ class ChronosPipeline(BaseChronosPipeline):
|
|
404
404
|
|
405
405
|
def predict(
|
406
406
|
self,
|
407
|
-
context: Union[torch.Tensor,
|
407
|
+
context: Union[torch.Tensor, list[torch.Tensor]],
|
408
408
|
prediction_length: Optional[int] = None,
|
409
409
|
num_samples: Optional[int] = None,
|
410
410
|
temperature: Optional[float] = None,
|
@@ -494,10 +494,10 @@ class ChronosPipeline(BaseChronosPipeline):
|
|
494
494
|
self,
|
495
495
|
context: torch.Tensor,
|
496
496
|
prediction_length: int,
|
497
|
-
quantile_levels:
|
497
|
+
quantile_levels: list[float],
|
498
498
|
num_samples: Optional[int] = None,
|
499
499
|
**kwargs,
|
500
|
-
) ->
|
500
|
+
) -> tuple[torch.Tensor, torch.Tensor]:
|
501
501
|
num_samples = num_samples or self.model.config.num_samples
|
502
502
|
prediction_samples = (
|
503
503
|
self.predict(
|
@@ -7,7 +7,7 @@ import copy
|
|
7
7
|
import logging
|
8
8
|
import warnings
|
9
9
|
from dataclasses import dataclass, fields
|
10
|
-
from typing import
|
10
|
+
from typing import Optional, Union
|
11
11
|
|
12
12
|
import torch
|
13
13
|
import torch.nn as nn
|
@@ -32,7 +32,7 @@ class ChronosBoltConfig:
|
|
32
32
|
prediction_length: int
|
33
33
|
input_patch_size: int
|
34
34
|
input_patch_stride: int
|
35
|
-
quantiles:
|
35
|
+
quantiles: list[float]
|
36
36
|
use_reg_token: bool = False
|
37
37
|
|
38
38
|
|
@@ -77,8 +77,8 @@ class InstanceNorm(nn.Module):
|
|
77
77
|
def forward(
|
78
78
|
self,
|
79
79
|
x: torch.Tensor,
|
80
|
-
loc_scale: Optional[
|
81
|
-
) ->
|
80
|
+
loc_scale: Optional[tuple[torch.Tensor, torch.Tensor]] = None,
|
81
|
+
) -> tuple[torch.Tensor, tuple[torch.Tensor, torch.Tensor]]:
|
82
82
|
if loc_scale is None:
|
83
83
|
loc = torch.nan_to_num(torch.nanmean(x, dim=-1, keepdim=True), nan=0.0)
|
84
84
|
scale = torch.nan_to_num((x - loc).square().nanmean(dim=-1, keepdim=True).sqrt(), nan=1.0)
|
@@ -88,7 +88,7 @@ class InstanceNorm(nn.Module):
|
|
88
88
|
|
89
89
|
return (x - loc) / scale, (loc, scale)
|
90
90
|
|
91
|
-
def inverse(self, x: torch.Tensor, loc_scale:
|
91
|
+
def inverse(self, x: torch.Tensor, loc_scale: tuple[torch.Tensor, torch.Tensor]) -> torch.Tensor:
|
92
92
|
loc, scale = loc_scale
|
93
93
|
return x * scale + loc
|
94
94
|
|
@@ -343,11 +343,11 @@ class ChronosBoltModelForForecasting(T5PreTrainedModel):
|
|
343
343
|
"""
|
344
344
|
Parameters
|
345
345
|
----------
|
346
|
-
input_embeds
|
346
|
+
input_embeds
|
347
347
|
Patched and embedded inputs. Shape (batch_size, patched_context_length, d_model)
|
348
|
-
attention_mask
|
348
|
+
attention_mask
|
349
349
|
Attention mask for the patched context. Shape (batch_size, patched_context_length), type: torch.int64
|
350
|
-
hidden_states
|
350
|
+
hidden_states
|
351
351
|
Hidden states returned by the encoder. Shape (batch_size, patched_context_length, d_model)
|
352
352
|
|
353
353
|
Returns
|
@@ -385,12 +385,12 @@ class ChronosBoltPipeline(BaseChronosPipeline):
|
|
385
385
|
self.model_prediction_length: int = self.model.config.chronos_config["prediction_length"]
|
386
386
|
|
387
387
|
@property
|
388
|
-
def quantiles(self) ->
|
388
|
+
def quantiles(self) -> list[float]:
|
389
389
|
return self.model.config.chronos_config["quantiles"]
|
390
390
|
|
391
391
|
def predict( # type: ignore[override]
|
392
392
|
self,
|
393
|
-
context: Union[torch.Tensor,
|
393
|
+
context: Union[torch.Tensor, list[torch.Tensor]],
|
394
394
|
prediction_length: Optional[int] = None,
|
395
395
|
limit_prediction_length: bool = False,
|
396
396
|
):
|
@@ -458,8 +458,8 @@ class ChronosBoltPipeline(BaseChronosPipeline):
|
|
458
458
|
return torch.cat(predictions, dim=-1)[..., :prediction_length]
|
459
459
|
|
460
460
|
def predict_quantiles(
|
461
|
-
self, context: torch.Tensor, prediction_length: int, quantile_levels:
|
462
|
-
) ->
|
461
|
+
self, context: torch.Tensor, prediction_length: int, quantile_levels: list[float], **kwargs
|
462
|
+
) -> tuple[torch.Tensor, torch.Tensor]:
|
463
463
|
# shape (batch_size, prediction_length, len(training_quantile_levels))
|
464
464
|
predictions = (
|
465
465
|
self.predict(
|
@@ -4,7 +4,7 @@ import re
|
|
4
4
|
import time
|
5
5
|
from itertools import chain, cycle
|
6
6
|
from pathlib import Path
|
7
|
-
from typing import TYPE_CHECKING, Callable, Iterable, Iterator,
|
7
|
+
from typing import TYPE_CHECKING, Callable, Iterable, Iterator, Literal, Optional
|
8
8
|
|
9
9
|
import numpy as np
|
10
10
|
import torch
|
@@ -73,19 +73,19 @@ class ChronosFineTuningDataset(IterableDataset):
|
|
73
73
|
|
74
74
|
Parameters
|
75
75
|
----------
|
76
|
-
target_df
|
76
|
+
target_df
|
77
77
|
The ``TimeSeriesDataFrame`` to be converted
|
78
|
-
target_column
|
78
|
+
target_column
|
79
79
|
The name of the column which contains the target time series, by default "target"
|
80
|
-
context_length
|
80
|
+
context_length
|
81
81
|
The length of the historical context
|
82
|
-
prediction_length
|
82
|
+
prediction_length
|
83
83
|
The prediction_length, i.e., length of label or target
|
84
|
-
tokenizer
|
84
|
+
tokenizer
|
85
85
|
When a ``ChronosTokenizer`` object is provided, data will be converted into the
|
86
86
|
HuggingFace format accepted by the original Chronos models using this ``ChronosTokenizer``.
|
87
87
|
If None, data will be converted into the format accepted by ChronosBolt models.
|
88
|
-
mode
|
88
|
+
mode
|
89
89
|
When ``training``, random slices from the time series will be returned for training purposes.
|
90
90
|
If ``validation``, the last slice of each time series returned in the original order.
|
91
91
|
"""
|
@@ -145,7 +145,7 @@ class ChronosFineTuningDataset(IterableDataset):
|
|
145
145
|
|
146
146
|
Parameters
|
147
147
|
----------
|
148
|
-
entry
|
148
|
+
entry
|
149
149
|
time series data entry in GluonTS format with ``past_target`` and ``future_target`` keys
|
150
150
|
|
151
151
|
Returns
|
@@ -172,7 +172,7 @@ class ChronosFineTuningDataset(IterableDataset):
|
|
172
172
|
|
173
173
|
Parameters
|
174
174
|
----------
|
175
|
-
entry
|
175
|
+
entry
|
176
176
|
time series data entry in GluonTS format with ``past_target`` and ``future_target`` keys
|
177
177
|
|
178
178
|
Returns
|
@@ -200,7 +200,7 @@ class ChronosFineTuningDataset(IterableDataset):
|
|
200
200
|
|
201
201
|
Parameters
|
202
202
|
----------
|
203
|
-
shuffle_buffer_size
|
203
|
+
shuffle_buffer_size
|
204
204
|
The shuffle buffer size used for pseudo shuffling
|
205
205
|
"""
|
206
206
|
assert shuffle_buffer_size is None or shuffle_buffer_size >= 0
|
@@ -209,7 +209,7 @@ class ChronosFineTuningDataset(IterableDataset):
|
|
209
209
|
return PseudoShuffledIterableDataset(self, shuffle_buffer_size)
|
210
210
|
|
211
211
|
|
212
|
-
def left_pad_and_stack_1D(tensors:
|
212
|
+
def left_pad_and_stack_1D(tensors: list[torch.Tensor]) -> torch.Tensor:
|
213
213
|
max_len = max(len(c) for c in tensors)
|
214
214
|
padded = []
|
215
215
|
for c in tensors:
|
@@ -303,7 +303,7 @@ class TimeLimitCallback(TrainerCallback):
|
|
303
303
|
|
304
304
|
Parameters
|
305
305
|
----------
|
306
|
-
time_limit
|
306
|
+
time_limit
|
307
307
|
maximum time allowed for training in seconds.
|
308
308
|
"""
|
309
309
|
self.time_limit = time_limit
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import functools
|
2
2
|
import logging
|
3
3
|
from abc import ABC, abstractmethod
|
4
|
-
from typing import
|
4
|
+
from typing import Optional
|
5
5
|
|
6
6
|
import numpy as np
|
7
7
|
from typing_extensions import final
|
@@ -18,32 +18,32 @@ class AbstractTimeSeriesEnsembleModel(TimeSeriesModelBase, ABC):
|
|
18
18
|
|
19
19
|
@property
|
20
20
|
@abstractmethod
|
21
|
-
def model_names(self) ->
|
21
|
+
def model_names(self) -> list[str]:
|
22
22
|
"""Names of base models included in the ensemble."""
|
23
23
|
pass
|
24
24
|
|
25
25
|
@final
|
26
26
|
def fit(
|
27
27
|
self,
|
28
|
-
predictions_per_window:
|
29
|
-
data_per_window:
|
30
|
-
model_scores: Optional[
|
28
|
+
predictions_per_window: dict[str, list[TimeSeriesDataFrame]],
|
29
|
+
data_per_window: list[TimeSeriesDataFrame],
|
30
|
+
model_scores: Optional[dict[str, float]] = None,
|
31
31
|
time_limit: Optional[float] = None,
|
32
32
|
):
|
33
33
|
"""Fit ensemble model given predictions of candidate base models and the true data.
|
34
34
|
|
35
35
|
Parameters
|
36
36
|
----------
|
37
|
-
predictions_per_window
|
37
|
+
predictions_per_window
|
38
38
|
Dictionary that maps the names of component models to their respective predictions for each validation
|
39
39
|
window.
|
40
|
-
data_per_window
|
40
|
+
data_per_window
|
41
41
|
Observed ground truth data used to train the ensemble for each validation window. Each entry in the list
|
42
42
|
includes both the forecast horizon (for which the predictions are given in ``predictions``), as well as the
|
43
43
|
"history".
|
44
|
-
model_scores
|
44
|
+
model_scores
|
45
45
|
Scores (higher is better) for the models that will constitute the ensemble.
|
46
|
-
time_limit
|
46
|
+
time_limit
|
47
47
|
Maximum allowed time for training in seconds.
|
48
48
|
"""
|
49
49
|
if time_limit is not None and time_limit <= 0:
|
@@ -67,9 +67,9 @@ class AbstractTimeSeriesEnsembleModel(TimeSeriesModelBase, ABC):
|
|
67
67
|
|
68
68
|
def _fit(
|
69
69
|
self,
|
70
|
-
predictions_per_window:
|
71
|
-
data_per_window:
|
72
|
-
model_scores: Optional[
|
70
|
+
predictions_per_window: dict[str, list[TimeSeriesDataFrame]],
|
71
|
+
data_per_window: list[TimeSeriesDataFrame],
|
72
|
+
model_scores: Optional[dict[str, float]] = None,
|
73
73
|
time_limit: Optional[float] = None,
|
74
74
|
):
|
75
75
|
"""Private method for `fit`. See `fit` for documentation of arguments. Apart from the model
|
@@ -78,7 +78,7 @@ class AbstractTimeSeriesEnsembleModel(TimeSeriesModelBase, ABC):
|
|
78
78
|
raise NotImplementedError
|
79
79
|
|
80
80
|
@final
|
81
|
-
def predict(self, data:
|
81
|
+
def predict(self, data: dict[str, TimeSeriesDataFrame], **kwargs) -> TimeSeriesDataFrame:
|
82
82
|
if not set(self.model_names).issubset(set(data.keys())):
|
83
83
|
raise ValueError(
|
84
84
|
f"Set of models given for prediction in {self.name} differ from those provided during initialization."
|
@@ -93,11 +93,11 @@ class AbstractTimeSeriesEnsembleModel(TimeSeriesModelBase, ABC):
|
|
93
93
|
return self._predict(data=data, **kwargs)
|
94
94
|
|
95
95
|
@abstractmethod
|
96
|
-
def _predict(self, data:
|
96
|
+
def _predict(self, data: dict[str, TimeSeriesDataFrame], **kwargs) -> TimeSeriesDataFrame:
|
97
97
|
pass
|
98
98
|
|
99
99
|
@abstractmethod
|
100
|
-
def remap_base_models(self, model_refit_map:
|
100
|
+
def remap_base_models(self, model_refit_map: dict[str, str]) -> None:
|
101
101
|
"""Update names of the base models based on the mapping in model_refit_map.
|
102
102
|
|
103
103
|
This method should be called after performing refit_full to point to the refitted base models, if necessary.
|
@@ -112,17 +112,17 @@ class AbstractWeightedTimeSeriesEnsembleModel(AbstractTimeSeriesEnsembleModel, A
|
|
112
112
|
if name is None:
|
113
113
|
name = "WeightedEnsemble"
|
114
114
|
super().__init__(name=name, **kwargs)
|
115
|
-
self.model_to_weight:
|
115
|
+
self.model_to_weight: dict[str, float] = {}
|
116
116
|
|
117
117
|
@property
|
118
|
-
def model_names(self) ->
|
118
|
+
def model_names(self) -> list[str]:
|
119
119
|
return list(self.model_to_weight.keys())
|
120
120
|
|
121
121
|
@property
|
122
122
|
def model_weights(self) -> np.ndarray:
|
123
123
|
return np.array(list(self.model_to_weight.values()), dtype=np.float64)
|
124
124
|
|
125
|
-
def _predict(self, data:
|
125
|
+
def _predict(self, data: dict[str, TimeSeriesDataFrame], **kwargs) -> TimeSeriesDataFrame:
|
126
126
|
weighted_predictions = [data[model_name] * weight for model_name, weight in self.model_to_weight.items()]
|
127
127
|
return functools.reduce(lambda x, y: x + y, weighted_predictions)
|
128
128
|
|
@@ -131,7 +131,7 @@ class AbstractWeightedTimeSeriesEnsembleModel(AbstractTimeSeriesEnsembleModel, A
|
|
131
131
|
info["model_weights"] = self.model_to_weight.copy()
|
132
132
|
return info
|
133
133
|
|
134
|
-
def remap_base_models(self, model_refit_map:
|
134
|
+
def remap_base_models(self, model_refit_map: dict[str, str]) -> None:
|
135
135
|
updated_weights = {}
|
136
136
|
for model, weight in self.model_to_weight.items():
|
137
137
|
model_full_name = model_refit_map.get(model, model)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import
|
1
|
+
from typing import Any, Optional
|
2
2
|
|
3
3
|
import numpy as np
|
4
4
|
|
@@ -17,9 +17,9 @@ class SimpleAverageEnsemble(AbstractWeightedTimeSeriesEnsembleModel):
|
|
17
17
|
|
18
18
|
def _fit(
|
19
19
|
self,
|
20
|
-
predictions_per_window:
|
21
|
-
data_per_window:
|
22
|
-
model_scores: Optional[
|
20
|
+
predictions_per_window: dict[str, list[TimeSeriesDataFrame]],
|
21
|
+
data_per_window: list[TimeSeriesDataFrame],
|
22
|
+
model_scores: Optional[dict[str, float]] = None,
|
23
23
|
time_limit: Optional[float] = None,
|
24
24
|
):
|
25
25
|
self.model_to_weight = {}
|
@@ -52,14 +52,14 @@ class PerformanceWeightedEnsemble(AbstractWeightedTimeSeriesEnsembleModel):
|
|
52
52
|
name = "PerformanceWeightedEnsemble"
|
53
53
|
super().__init__(name=name, **kwargs)
|
54
54
|
|
55
|
-
def _get_default_hyperparameters(self) ->
|
55
|
+
def _get_default_hyperparameters(self) -> dict[str, Any]:
|
56
56
|
return {"weight_scheme": "sqrt"}
|
57
57
|
|
58
58
|
def _fit(
|
59
59
|
self,
|
60
|
-
predictions_per_window:
|
61
|
-
data_per_window:
|
62
|
-
model_scores: Optional[
|
60
|
+
predictions_per_window: dict[str, list[TimeSeriesDataFrame]],
|
61
|
+
data_per_window: list[TimeSeriesDataFrame],
|
62
|
+
model_scores: Optional[dict[str, float]] = None,
|
63
63
|
time_limit: Optional[float] = None,
|
64
64
|
):
|
65
65
|
assert model_scores is not None
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import copy
|
2
2
|
import logging
|
3
3
|
import pprint
|
4
|
-
from typing import
|
4
|
+
from typing import Any, Optional
|
5
5
|
|
6
6
|
import numpy as np
|
7
7
|
|
@@ -47,14 +47,14 @@ class TimeSeriesEnsembleSelection(EnsembleSelection):
|
|
47
47
|
self.dummy_pred_per_window = []
|
48
48
|
self.scorer_per_window = []
|
49
49
|
|
50
|
-
self.dummy_pred_per_window: Optional[
|
51
|
-
self.scorer_per_window: Optional[
|
52
|
-
self.data_future_per_window: Optional[
|
50
|
+
self.dummy_pred_per_window: Optional[list[TimeSeriesDataFrame]]
|
51
|
+
self.scorer_per_window: Optional[list[TimeSeriesScorer]]
|
52
|
+
self.data_future_per_window: Optional[list[TimeSeriesDataFrame]]
|
53
53
|
|
54
54
|
def fit( # type: ignore
|
55
55
|
self,
|
56
|
-
predictions:
|
57
|
-
labels:
|
56
|
+
predictions: list[list[TimeSeriesDataFrame]],
|
57
|
+
labels: list[TimeSeriesDataFrame],
|
58
58
|
time_limit: Optional[float] = None,
|
59
59
|
):
|
60
60
|
return super().fit(
|
@@ -65,10 +65,10 @@ class TimeSeriesEnsembleSelection(EnsembleSelection):
|
|
65
65
|
|
66
66
|
def _fit( # type: ignore
|
67
67
|
self,
|
68
|
-
predictions:
|
69
|
-
labels:
|
68
|
+
predictions: list[list[TimeSeriesDataFrame]],
|
69
|
+
labels: list[TimeSeriesDataFrame],
|
70
70
|
time_limit: Optional[float] = None,
|
71
|
-
sample_weight: Optional[
|
71
|
+
sample_weight: Optional[list[float]] = None,
|
72
72
|
):
|
73
73
|
# Stack predictions for each model into a 3d tensor of shape [num_val_windows, num_rows, num_cols]
|
74
74
|
stacked_predictions = [np.stack(preds) for preds in predictions]
|
@@ -157,14 +157,14 @@ class GreedyEnsemble(AbstractWeightedTimeSeriesEnsembleModel):
|
|
157
157
|
name = "WeightedEnsemble"
|
158
158
|
super().__init__(name=name, **kwargs)
|
159
159
|
|
160
|
-
def _get_default_hyperparameters(self) ->
|
160
|
+
def _get_default_hyperparameters(self) -> dict[str, Any]:
|
161
161
|
return {"ensemble_size": 100}
|
162
162
|
|
163
163
|
def _fit(
|
164
164
|
self,
|
165
|
-
predictions_per_window:
|
166
|
-
data_per_window:
|
167
|
-
model_scores: Optional[
|
165
|
+
predictions_per_window: dict[str, list[TimeSeriesDataFrame]],
|
166
|
+
data_per_window: list[TimeSeriesDataFrame],
|
167
|
+
model_scores: Optional[dict[str, float]] = None,
|
168
168
|
time_limit: Optional[float] = None,
|
169
169
|
):
|
170
170
|
ensemble_selection = TimeSeriesEnsembleSelection(
|