spotforecast2 0.0.1__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 (46) hide show
  1. spotforecast2/.DS_Store +0 -0
  2. spotforecast2/__init__.py +2 -0
  3. spotforecast2/data/__init__.py +0 -0
  4. spotforecast2/data/data.py +130 -0
  5. spotforecast2/data/fetch_data.py +209 -0
  6. spotforecast2/exceptions.py +681 -0
  7. spotforecast2/forecaster/.DS_Store +0 -0
  8. spotforecast2/forecaster/__init__.py +7 -0
  9. spotforecast2/forecaster/base.py +448 -0
  10. spotforecast2/forecaster/metrics.py +527 -0
  11. spotforecast2/forecaster/recursive/__init__.py +4 -0
  12. spotforecast2/forecaster/recursive/_forecaster_equivalent_date.py +1075 -0
  13. spotforecast2/forecaster/recursive/_forecaster_recursive.py +939 -0
  14. spotforecast2/forecaster/recursive/_warnings.py +15 -0
  15. spotforecast2/forecaster/utils.py +954 -0
  16. spotforecast2/model_selection/__init__.py +5 -0
  17. spotforecast2/model_selection/bayesian_search.py +453 -0
  18. spotforecast2/model_selection/grid_search.py +314 -0
  19. spotforecast2/model_selection/random_search.py +151 -0
  20. spotforecast2/model_selection/split_base.py +357 -0
  21. spotforecast2/model_selection/split_one_step.py +245 -0
  22. spotforecast2/model_selection/split_ts_cv.py +634 -0
  23. spotforecast2/model_selection/utils_common.py +718 -0
  24. spotforecast2/model_selection/utils_metrics.py +103 -0
  25. spotforecast2/model_selection/validation.py +685 -0
  26. spotforecast2/preprocessing/__init__.py +30 -0
  27. spotforecast2/preprocessing/_binner.py +378 -0
  28. spotforecast2/preprocessing/_common.py +123 -0
  29. spotforecast2/preprocessing/_differentiator.py +123 -0
  30. spotforecast2/preprocessing/_rolling.py +136 -0
  31. spotforecast2/preprocessing/curate_data.py +254 -0
  32. spotforecast2/preprocessing/imputation.py +92 -0
  33. spotforecast2/preprocessing/outlier.py +114 -0
  34. spotforecast2/preprocessing/split.py +139 -0
  35. spotforecast2/py.typed +0 -0
  36. spotforecast2/utils/__init__.py +43 -0
  37. spotforecast2/utils/convert_to_utc.py +44 -0
  38. spotforecast2/utils/data_transform.py +208 -0
  39. spotforecast2/utils/forecaster_config.py +344 -0
  40. spotforecast2/utils/generate_holiday.py +70 -0
  41. spotforecast2/utils/validation.py +569 -0
  42. spotforecast2/weather/__init__.py +0 -0
  43. spotforecast2/weather/weather_client.py +288 -0
  44. spotforecast2-0.0.1.dist-info/METADATA +47 -0
  45. spotforecast2-0.0.1.dist-info/RECORD +46 -0
  46. spotforecast2-0.0.1.dist-info/WHEEL +4 -0
@@ -0,0 +1,448 @@
1
+ """ForecasterBase class.
2
+
3
+ This module contains the base class for all forecasters in spotforecast2.
4
+ All forecasters should specify all the parameters that can be set at the
5
+ class level in their __init__.
6
+
7
+ Examples:
8
+ Create a custom forecaster inheriting from ForecasterBase:
9
+
10
+ >>> from spotforecast2.forecaster.base import ForecasterBase
11
+ >>> import pandas as pd
12
+ >>> import numpy as np
13
+ >>> class MyForecaster(ForecasterBase):
14
+ ... def __init__(self, estimator):
15
+ ... self.estimator = estimator
16
+ ... self.__spotforecast_tags__ = {'hide_lags': True}
17
+ ... def create_train_X_y(self, y, exog=None):
18
+ ... return pd.DataFrame(), pd.Series(dtype=float)
19
+ ... def fit(self, y, exog=None):
20
+ ... pass
21
+ ... def predict(self, steps, last_window=None, exog=None):
22
+ ... return pd.Series(np.zeros(steps))
23
+ ... def set_params(self, params):
24
+ ... pass
25
+ >>> from sklearn.linear_model import Ridge
26
+ >>> forecaster = MyForecaster(estimator=Ridge())
27
+ >>> forecaster
28
+ MyForecaster(estimator=Ridge())
29
+ """
30
+
31
+ from __future__ import annotations
32
+ from abc import ABC, abstractmethod
33
+ from typing import Any
34
+ import textwrap
35
+ import warnings
36
+ import numpy as np
37
+ import pandas as pd
38
+ from sklearn.pipeline import Pipeline
39
+
40
+
41
+ class ForecasterBase(ABC):
42
+ """Base class for all forecasters in spotforecast2.
43
+
44
+ All forecasters should specify all the parameters that can be set at
45
+ the class level in their __init__.
46
+
47
+ Attributes:
48
+ __spotforecast_tags__: Dictionary with forecaster tags that characterize
49
+ the behavior of the forecaster.
50
+
51
+ Examples:
52
+ To see all abstract methods that need to be implemented:
53
+
54
+ >>> import inspect
55
+ >>> from spotforecast2.forecaster.base import ForecasterBase
56
+ >>> [m[0] for m in inspect.getmembers(ForecasterBase, predicate=inspect.isabstract)]
57
+ ['create_train_X_y', 'fit', 'predict', 'set_params']
58
+ """
59
+
60
+ def _preprocess_repr(
61
+ self,
62
+ estimator: object | None = None,
63
+ training_range_: dict[str, str] | None = None,
64
+ series_names_in_: list[str] | None = None,
65
+ exog_names_in_: list[str] | None = None,
66
+ transformer_series: object | dict[str, object] | None = None,
67
+ ) -> tuple[str, str | None, str | None, str | None, str | None]:
68
+ """Prepare the information to be displayed when a Forecaster object is printed.
69
+
70
+ Args:
71
+ estimator: Estimator object. Default is None.
72
+ training_range_: Training range. Only used for ForecasterRecursiveMultiSeries.
73
+ Default is None.
74
+ series_names_in_: Names of the series used in the forecaster.
75
+ Only used for ForecasterRecursiveMultiSeries. Default is None.
76
+ exog_names_in_: Names of the exogenous variables used in the forecaster.
77
+ Default is None.
78
+ transformer_series: Transformer used in the series.
79
+ Only used for ForecasterRecursiveMultiSeries. Default is None.
80
+
81
+ Returns:
82
+ Tuple containing params (estimator parameters string), training_range_
83
+ (training range string representation), series_names_in_ (series names
84
+ string representation), exog_names_in_ (exogenous variable names string
85
+ representation), and transformer_series (transformer string representation).
86
+
87
+ Examples:
88
+ >>> from spotforecast2.forecaster.recursive import ForecasterRecursive
89
+ >>> from sklearn.linear_model import Ridge
90
+ >>> estimator = Ridge(alpha=0.5)
91
+ >>> forecaster = ForecasterRecursive(estimator=estimator, lags=3)
92
+ >>> params, tr, sn, en, ts = forecaster._preprocess_repr(estimator=estimator)
93
+ >>> params
94
+ "{'alpha': 0.5, 'copy_X': True, 'fit_intercept': True, 'max_iter': None, 'positive': False, 'random_state': None, 'solver': 'auto', 'tol': 0.0001}"
95
+ """
96
+
97
+ if estimator is not None:
98
+ if isinstance(estimator, Pipeline):
99
+ name_pipe_steps = tuple(
100
+ name + "__" for name in estimator.named_steps.keys()
101
+ )
102
+ params = {
103
+ key: value
104
+ for key, value in estimator.get_params().items()
105
+ if key.startswith(name_pipe_steps)
106
+ }
107
+ else:
108
+ params = estimator.get_params()
109
+ params = str(params)
110
+ else:
111
+ params = None
112
+
113
+ if training_range_ is not None:
114
+ training_range_ = [
115
+ f"'{k}': {v.astype(str).to_list()}" for k, v in training_range_.items()
116
+ ]
117
+ if len(training_range_) > 10:
118
+ training_range_ = training_range_[:5] + ["..."] + training_range_[-5:]
119
+ training_range_ = ", ".join(training_range_)
120
+
121
+ if series_names_in_ is not None:
122
+ if len(series_names_in_) > 50:
123
+ series_names_in_ = (
124
+ series_names_in_[:25] + ["..."] + series_names_in_[-25:]
125
+ )
126
+ series_names_in_ = ", ".join(series_names_in_)
127
+
128
+ if exog_names_in_ is not None:
129
+ if len(exog_names_in_) > 50:
130
+ exog_names_in_ = exog_names_in_[:25] + ["..."] + exog_names_in_[-25:]
131
+ exog_names_in_ = ", ".join(exog_names_in_)
132
+
133
+ if transformer_series is not None:
134
+ if isinstance(transformer_series, dict):
135
+ transformer_series = [
136
+ f"'{k}': {v}" for k, v in transformer_series.items()
137
+ ]
138
+ if len(transformer_series) > 10:
139
+ transformer_series = (
140
+ transformer_series[:5] + ["..."] + transformer_series[-5:]
141
+ )
142
+ transformer_series = ", ".join(transformer_series)
143
+ else:
144
+ transformer_series = str(transformer_series)
145
+
146
+ return (
147
+ params,
148
+ training_range_,
149
+ series_names_in_,
150
+ exog_names_in_,
151
+ transformer_series,
152
+ )
153
+
154
+ def _format_text_repr(
155
+ self,
156
+ text: str,
157
+ max_text_length: int = 58,
158
+ width: int = 80,
159
+ indent: str = " ",
160
+ ) -> str:
161
+ """Format text for __repr__ method.
162
+
163
+ Args:
164
+ text: Text to format.
165
+ max_text_length: Maximum length of the text before wrapping. Default is 58.
166
+ width: Maximum width of the text. Default is 80.
167
+ indent: Indentation of the text. Default is four spaces.
168
+
169
+ Returns:
170
+ Formatted text string with proper wrapping and indentation.
171
+
172
+ Examples:
173
+ >>> from spotforecast2.forecaster.recursive import ForecasterRecursive
174
+ >>> from sklearn.linear_model import Ridge
175
+ >>> forecaster = ForecasterRecursive(estimator=Ridge(), lags=3)
176
+ >>> forecaster._format_text_repr("Short text")
177
+ 'Short text'
178
+ """
179
+
180
+ if text is not None and len(text) > max_text_length:
181
+ text = "\n " + textwrap.fill(
182
+ str(text), width=width, subsequent_indent=indent
183
+ )
184
+
185
+ return text
186
+
187
+ @abstractmethod
188
+ def create_train_X_y(
189
+ self, y: pd.Series, exog: pd.Series | pd.DataFrame | None = None
190
+ ) -> tuple[pd.DataFrame, pd.Series]:
191
+ """Create training matrices from univariate time series and exogenous variables.
192
+
193
+ Args:
194
+ y: Training time series.
195
+ exog: Exogenous variable(s) included as predictor(s). Must have the same
196
+ number of observations as y and their indexes must be aligned.
197
+ Default is None.
198
+
199
+ Returns:
200
+ Tuple containing X_train (training values/predictors with shape
201
+ (len(y) - max_lag, len(lags))) and y_train (target values of the
202
+ time series related to each row of X_train with shape (len(y) - max_lag,)).
203
+
204
+ Examples:
205
+ >>> from spotforecast2.forecaster.recursive import ForecasterRecursive
206
+ >>> from sklearn.linear_model import Ridge
207
+ >>> import pandas as pd
208
+ >>> import numpy as np
209
+ >>> forecaster = ForecasterRecursive(estimator=Ridge(), lags=3)
210
+ >>> y = pd.Series(np.arange(10), name='y')
211
+ >>> X_train, y_train = forecaster.create_train_X_y(y)
212
+ >>> X_train.head(2)
213
+ lag_1 lag_2 lag_3
214
+ 3 2.0 1.0 0.0
215
+ 4 3.0 2.0 1.0
216
+ >>> y_train.head(2)
217
+ 3 3
218
+ 4 4
219
+ Name: y, dtype: int64
220
+ """
221
+
222
+ pass
223
+
224
+ @abstractmethod
225
+ def fit(self, y: pd.Series, exog: pd.Series | pd.DataFrame | None = None) -> None:
226
+ """Training Forecaster.
227
+
228
+ Args:
229
+ y: Training time series.
230
+ exog: Exogenous variable(s) included as predictor(s). Must have the same
231
+ number of observations as y and their indexes must be aligned so
232
+ that y[i] is regressed on exog[i]. Default is None.
233
+
234
+ Returns:
235
+ None
236
+
237
+ Examples:
238
+ >>> from spotforecast2.forecaster.recursive import ForecasterRecursive
239
+ >>> from sklearn.linear_model import Ridge
240
+ >>> import pandas as pd
241
+ >>> import numpy as np
242
+ >>> forecaster = ForecasterRecursive(estimator=Ridge(), lags=3)
243
+ >>> y = pd.Series(np.arange(10), name='y')
244
+ >>> forecaster.fit(y)
245
+ >>> forecaster.is_fitted
246
+ True
247
+ """
248
+
249
+ pass
250
+
251
+ @abstractmethod
252
+ def predict(
253
+ self,
254
+ steps: int,
255
+ last_window: pd.Series | pd.DataFrame | None = None,
256
+ exog: pd.Series | pd.DataFrame | None = None,
257
+ ) -> pd.Series:
258
+ """Predict n steps ahead.
259
+
260
+ Args:
261
+ steps: Number of steps to predict.
262
+ last_window: Series values used to create the predictors (lags) needed in the
263
+ first iteration of the prediction (t + 1). If None, the values stored in
264
+ last_window are used to calculate the initial predictors, and the
265
+ predictions start right after training data. Default is None.
266
+ exog: Exogenous variable(s) included as predictor(s). Default is None.
267
+
268
+ Returns:
269
+ Predicted values as a pandas Series.
270
+
271
+ Examples:
272
+ >>> from spotforecast2.forecaster.recursive import ForecasterRecursive
273
+ >>> from sklearn.linear_model import Ridge
274
+ >>> import pandas as pd
275
+ >>> import numpy as np
276
+ >>> forecaster = ForecasterRecursive(estimator=Ridge(), lags=3)
277
+ >>> y = pd.Series(np.arange(10), name='y')
278
+ >>> forecaster.fit(y)
279
+ >>> forecaster.predict(steps=3)
280
+ 10 9.5
281
+ 11 9.0
282
+ 12 8.5
283
+ Name: pred, dtype: float64
284
+ """
285
+
286
+ pass
287
+
288
+ @abstractmethod
289
+ def set_params(self, params: dict[str, object]) -> None:
290
+ """Set new values to the parameters of the scikit-learn model stored in the forecaster.
291
+
292
+ Args:
293
+ params: Parameters values dictionary.
294
+
295
+ Returns:
296
+ None
297
+
298
+ Examples:
299
+ >>> from spotforecast2.forecaster.recursive import ForecasterRecursive
300
+ >>> from sklearn.linear_model import Ridge
301
+ >>> forecaster = ForecasterRecursive(estimator=Ridge(alpha=1.0), lags=3)
302
+ >>> forecaster.set_params({'estimator__alpha': 0.5})
303
+ >>> forecaster.estimator.alpha
304
+ 0.5
305
+ """
306
+
307
+ pass
308
+
309
+ def set_lags(
310
+ self, lags: int | list[int] | np.ndarray[int] | range[int] | None = None
311
+ ) -> None:
312
+ """Set new value to the attribute lags.
313
+
314
+ Attributes max_lag and window_size are also updated.
315
+
316
+ Args:
317
+ lags: Lags used as predictors. Index starts at 1, so lag 1 is equal to t-1.
318
+ If int: include lags from 1 to lags (included). If list, 1d numpy ndarray,
319
+ or range: include only lags present in lags, all elements must be int.
320
+ If None: no lags are included as predictors. Default is None.
321
+
322
+ Returns:
323
+ None
324
+
325
+ Examples:
326
+ >>> from spotforecast2.forecaster.recursive import ForecasterRecursive
327
+ >>> from sklearn.linear_model import Ridge
328
+ >>> forecaster = ForecasterRecursive(estimator=Ridge(), lags=3)
329
+ >>> forecaster.set_lags(lags=5)
330
+ >>> forecaster.lags
331
+ array([1, 2, 3, 4, 5])
332
+ """
333
+
334
+ pass
335
+
336
+ def set_window_features(
337
+ self, window_features: object | list[object] | None = None
338
+ ) -> None:
339
+ """Set new value to the attribute window_features.
340
+
341
+ Attributes max_size_window_features, window_features_names,
342
+ window_features_class_names and window_size are also updated.
343
+
344
+ Args:
345
+ window_features: Instance or list of instances used to create window features.
346
+ Window features are created from the original time series and are
347
+ included as predictors. Default is None.
348
+
349
+ Returns:
350
+ None
351
+
352
+ Examples:
353
+ >>> from spotforecast2.forecaster.recursive import ForecasterRecursive
354
+ >>> from spotforecast2.forecaster.preprocessing import RollingFeatures
355
+ >>> from sklearn.linear_model import Ridge
356
+ >>> forecaster = ForecasterRecursive(estimator=Ridge(), lags=3)
357
+ >>> window_feat = RollingFeatures(stats='mean', window_sizes=3)
358
+ >>> forecaster.set_window_features(window_features=window_feat)
359
+ >>> forecaster.window_features
360
+ [RollingFeatures(stats=['mean'], window_sizes=[3])]
361
+ """
362
+
363
+ pass
364
+
365
+ def get_tags(self) -> dict[str, Any]:
366
+ """Return the tags that characterize the behavior of the forecaster.
367
+
368
+ Returns:
369
+ Dictionary with forecaster tags describing behavior and capabilities.
370
+
371
+ Examples:
372
+ >>> from spotforecast2.forecaster.recursive import ForecasterRecursive
373
+ >>> from sklearn.linear_model import Ridge
374
+ >>> forecaster = ForecasterRecursive(estimator=Ridge(), lags=3)
375
+ >>> tags = forecaster.get_tags()
376
+ >>> tags['forecaster_task']
377
+ 'regression'
378
+ """
379
+
380
+ return self.__spotforecast_tags__
381
+
382
+ def summary(self) -> None:
383
+ """Show forecaster information.
384
+
385
+ Returns:
386
+ None
387
+
388
+ Examples:
389
+ >>> from spotforecast2.forecaster.recursive import ForecasterRecursive
390
+ >>> from sklearn.linear_model import Ridge
391
+ >>> forecaster = ForecasterRecursive(estimator=Ridge(), lags=3)
392
+ >>> forecaster.summary()
393
+ ForecasterRecursive
394
+ ===================
395
+ Estimator: Ridge()
396
+ Lags: [1 2 3]
397
+ ...
398
+ """
399
+
400
+ print(self.__repr__())
401
+
402
+ def __setstate__(self, state: dict) -> None:
403
+ """Custom __setstate__ to ensure backward compatibility when unpickling.
404
+
405
+ This method is called when an object is unpickled (deserialized).
406
+ It handles the migration of deprecated attributes to their new names.
407
+
408
+ Args:
409
+ state: The state dictionary from the pickled object.
410
+
411
+ Returns:
412
+ None
413
+
414
+ Examples:
415
+ >>> from spotforecast2.forecaster.recursive import ForecasterRecursive
416
+ >>> from sklearn.linear_model import Ridge
417
+ >>> import pickle
418
+ >>> forecaster = ForecasterRecursive(estimator=Ridge(), lags=3)
419
+ >>> pickled_forecaster = pickle.dumps(forecaster)
420
+ >>> unpickled_forecaster = pickle.loads(pickled_forecaster)
421
+ """
422
+
423
+ # Migration: 'regressor' renamed to 'estimator' in version 0.18.0
424
+ if "regressor" in state and "estimator" not in state:
425
+ state["estimator"] = state.pop("regressor")
426
+
427
+ self.__dict__.update(state)
428
+
429
+ @property
430
+ def regressor(self):
431
+ """Deprecated property. Use estimator instead.
432
+
433
+ Returns:
434
+ The estimator object.
435
+
436
+ Examples:
437
+ >>> from spotforecast2.forecaster.recursive import ForecasterRecursive
438
+ >>> from sklearn.linear_model import Ridge
439
+ >>> forecaster = ForecasterRecursive(estimator=Ridge(), lags=3)
440
+ >>> forecaster.regressor # Raises FutureWarning
441
+ Ridge()
442
+ """
443
+ warnings.warn(
444
+ "The `regressor` attribute is deprecated and will be removed in future "
445
+ "versions. Use `estimator` instead.",
446
+ FutureWarning,
447
+ )
448
+ return self.estimator