diff --git a/aeon/forecasting/__init__.py b/aeon/forecasting/__init__.py index de203a0bcd..7d3c90b947 100644 --- a/aeon/forecasting/__init__.py +++ b/aeon/forecasting/__init__.py @@ -10,4 +10,4 @@ from aeon.forecasting._dummy import DummyForecaster from aeon.forecasting._ets import ETSForecaster from aeon.forecasting._regression import RegressionForecaster -from aeon.forecasting.base import BaseForecaster +from aeon.forecasting.base import BaseForecaster \ No newline at end of file diff --git a/aeon/forecasting/_dummy.py b/aeon/forecasting/_dummy.py index 7525b6ccd0..a42bec7376 100644 --- a/aeon/forecasting/_dummy.py +++ b/aeon/forecasting/_dummy.py @@ -24,4 +24,4 @@ def _predict(self, y=None, exog=None): def _forecast(self, y, exog=None): """Forecast using dummy forecaster.""" y = y.squeeze() - return y[-1] + return y[-1] \ No newline at end of file diff --git a/aeon/forecasting/_ets.py b/aeon/forecasting/_ets.py index 2635b83457..6d9efda7ce 100644 --- a/aeon/forecasting/_ets.py +++ b/aeon/forecasting/_ets.py @@ -2,10 +2,11 @@ An implementation of the exponential smoothing statistics forecasting algorithm. Implements additive and multiplicative error models, -None, additive and multiplicative (including damped) trend and -None, additive and multiplicative seasonality +``None``, additive, and multiplicative (including damped) trend, and +``None``, additive, and multiplicative seasonality. """ + __maintainer__ = [] __all__ = ["ETSForecaster", "NONE", "ADDITIVE", "MULTIPLICATIVE"] @@ -26,30 +27,30 @@ class ETSForecaster(BaseForecaster): """Exponential Smoothing forecaster. An implementation of the exponential smoothing forecasting algorithm. - Implements additive and multiplicative error models, None, additive and - multiplicative (including damped) trend and None, additive and mutliplicative + Implements additive and multiplicative error models, ``None``, additive, and + multiplicative (including damped) trend, and ``None``, additive, and multiplicative seasonality. See [1]_ for a description. Parameters ---------- error_type : int, default = 1 - Either NONE (0), ADDITIVE (1) or MULTIPLICATIVE (2). + Either ``NONE`` (0), ``ADDITIVE`` (1) or ``MULTIPLICATIVE`` (2). trend_type : int, default = 0 - Either NONE (0), ADDITIVE (1) or MULTIPLICATIVE (2). + Either ``NONE`` (0), ``ADDITIVE`` (1) or ``MULTIPLICATIVE`` (2). seasonality_type : int, default = 0 - Either NONE (0), ADDITIVE (1) or MULTIPLICATIVE (2). + Either ``NONE`` (0), ``ADDITIVE`` (1) or ``MULTIPLICATIVE`` (2). seasonal_period : int, default=1 - Length of seasonality period. If seasonality_type is NONE, this is assumed to - be 1 + Length of seasonality period. If ``seasonality_type`` is ``NONE``, this is assumed to + be ``1``. alpha : float, default = 0.1 Level smoothing parameter. beta : float, default = 0.01 - Trend smoothing parameter. If trend_type is NONE, this is assumed to be 0.0. + Trend smoothing parameter. If ``trend_type`` is ``NONE``, this is assumed to be ``0.0``. gamma : float, default = 0.01 - Seasonal smoothing parameter. If seasonality is NONE, this is assumed to be - 0.0. + Seasonal smoothing parameter. If ``seasonality`` is ``NONE``, this is assumed to be + ``0.0``. phi : float, default = 0.99 - Trend damping smoothing parameters + Trend damping smoothing parameter. horizon : int, default = 1 The horizon to forecast to. @@ -79,7 +80,8 @@ class ETSForecaster(BaseForecaster): ETSForecaster(alpha=0.4, beta=0.2, gamma=0.5, phi=0.8) >>> forecaster.predict() 449.9435566831507 - """ +""" + def __init__( self, @@ -108,22 +110,23 @@ def __init__( super().__init__(horizon=horizon, axis=1) def _fit(self, y, exog=None): - """Fit Exponential Smoothing forecaster to series y. + """Fit Exponential Smoothing forecaster to series ``y``. - Fit a forecaster to predict self.horizon steps ahead using y. + Fit a forecaster to predict ``self.horizon`` steps ahead using ``y``. Parameters ---------- - y : np.ndarray - A time series on which to learn a forecaster to predict horizon ahead - exog : np.ndarray, default =None - Optional exogenous time series data assumed to be aligned with y + y : ``np.ndarray`` + A time series on which to learn a forecaster to predict ``horizon`` ahead. + exog : ``np.ndarray``, default = ``None`` + Optional exogenous time series data assumed to be aligned with ``y``. Returns ------- self - Fitted BaseForecaster. + Fitted ``BaseForecaster``. """ + self.n_timepoints_ = len(y) if self.error_type != MULTIPLICATIVE and self.error_type != ADDITIVE: raise ValueError("Error must be either additive or multiplicative") @@ -159,21 +162,22 @@ def _fit(self, y, exog=None): def _predict(self, y=None, exog=None): """ - Predict the next horizon steps ahead. + Predict the next ``horizon`` steps ahead. Parameters ---------- - y : np.ndarray, default = None - A time series to predict the next horizon value for. If None, - predict the next horizon value after series seen in fit. - exog : np.ndarray, default = None - Optional exogenous time series data assumed to be aligned with y + y : ``np.ndarray``, default = ``None`` + A time series to predict the next ``horizon`` value for. If ``None``, + predict the next ``horizon`` value after series seen in ``fit``. + exog : ``np.ndarray``, default = ``None`` + Optional exogenous time series data assumed to be aligned with ``y``. Returns ------- float - single prediction self.horizon steps ahead of y. + Single prediction ``self.horizon`` steps ahead of ``y``. """ + return _predict_numba( self.trend_type, self.seasonality_type, @@ -266,14 +270,22 @@ def _predict_numba( @njit(nogil=NOGIL, cache=CACHE) def _initialise(trend_type, seasonality_type, seasonal_period, data): """ - Initialize level, trend, and seasonality values for the ETS model. + Predict the next ``horizon`` steps ahead. + + Parameters + ---------- + y : ``np.ndarray``, default = ``None`` + A time series to predict the next ``horizon`` value for. If ``None``, + predict the next ``horizon`` value after series seen in ``fit``. + exog : ``np.ndarray``, default = ``None`` + Optional exogenous time series data assumed to be aligned with ``y``. + + Returns + ------- + float + Single prediction ``self.horizon`` steps ahead of ``y``. + """ - Parameters - ---------- - data : array-like - The time series data - (should contain at least two full seasons if seasonality is specified) - """ # Initial Level: Mean of the first season level = np.mean(data[:seasonal_period]) # Initial Trend @@ -326,11 +338,12 @@ def _update_states( Parameters ---------- - data_item: float + data_item : ``float`` The current value of the time series. - seasonal_index: int + seasonal_index : ``int`` The index to update the seasonal component. """ + # Retrieve the current state values curr_level = level curr_seasonality = seasonality @@ -376,29 +389,29 @@ def _update_states( @njit(nogil=NOGIL, cache=CACHE) def _predict_value(trend_type, seasonality_type, level, trend, seasonality, phi): """ - Generate various useful values, including the next fitted value. Parameters ---------- - trend : float - The current trend value for the model - level : float - The current level value for the model - seasonality : float - The current seasonality value for the model - phi : float - The damping parameter for the model + trend : ``float`` + The current trend value for the model. + level : ``float`` + The current level value for the model. + seasonality : ``float`` + The current seasonality value for the model. + phi : ``float`` + The damping parameter for the model. Returns ------- - fitted_value : float - single prediction based on the current state variables. - damped_trend : float - The damping parameter combined with the trend dependant on the model type - trend_level_combination : float + fitted_value : ``float`` + Single prediction based on the current state variables. + damped_trend : ``float`` + The damping parameter combined with the trend, dependent on the model type. + trend_level_combination : ``float`` Combination of the trend and level based on the model type. """ + # Apply damping parameter and # calculate commonly used combination of trend and level components if trend_type == MULTIPLICATIVE: @@ -413,4 +426,4 @@ def _predict_value(trend_type, seasonality_type, level, trend, seasonality, phi) fitted_value = trend_level_combination * seasonality else: # Additive seasonality, if no seasonality, then seasonality = 0 fitted_value = trend_level_combination + seasonality - return fitted_value, damped_trend, trend_level_combination + return fitted_value, damped_trend, trend_level_combination \ No newline at end of file diff --git a/aeon/forecasting/_regression.py b/aeon/forecasting/_regression.py index bf15e231dd..6f606e3540 100644 --- a/aeon/forecasting/_regression.py +++ b/aeon/forecasting/_regression.py @@ -1,10 +1,11 @@ """Window-based regression forecaster. -General purpose forecaster to use with any scikit learn or aeon compatible +General-purpose forecaster to use with any ``scikit-learn`` or ``aeon`` compatible regressor. Simply forms a collection of windows from the time series and trains to -predict the next +predict the next. """ + import numpy as np from sklearn.linear_model import LinearRegression @@ -13,30 +14,30 @@ class RegressionForecaster(BaseForecaster): """ - Regression based forecasting. - - Container for forecaster that reduces forecasting to regression through a - window. Form a collection of sub series of length `window` through a sliding - winodw to form X, take `horizon` points ahead to form `y`, then apply an aeon or - sklearn regressor. + Regression-based forecasting. + Container for a forecaster that reduces forecasting to regression through a + window. Forms a collection of sub-series of length ``window`` through a sliding + window to form ``X``, takes ``horizon`` points ahead to form ``y``, then applies an ``aeon`` or + ``scikit-learn`` regressor. Parameters ---------- - window : int + window : ``int`` The window prior to the current time point to use in forecasting. So if - horizon is one, forecaster will train using points $i$ to $window+i-1$ to - predict value $window+i$. If horizon is 4, forecaster will used points $i$ - to $window+i-1$ to predict value $window+i+3$. If None, the algorithm will - internally determine what data to use to predict `horizon` steps ahead. - horizon : int, default =1 - The number of time steps ahead to forecast. If horizon is one, the forecaster - will learn to predict one point ahead - regressor : object, default =None - Regression estimator that implements BaseRegressor or is otherwise compatible - with sklearn regressors. + ``horizon`` is one, the forecaster will train using points ``i`` to ``window + i - 1`` to + predict value ``window + i``. If ``horizon`` is 4, the forecaster will use points ``i`` + to ``window + i - 1`` to predict value ``window + i + 3``. If ``None``, the algorithm will + internally determine what data to use to predict ``horizon`` steps ahead. + horizon : ``int``, default = ``1`` + The number of time steps ahead to forecast. If ``horizon`` is one, the forecaster + will learn to predict one point ahead. + regressor : ``object``, default = ``None`` + Regression estimator that implements ``BaseRegressor`` or is otherwise compatible + with ``scikit-learn`` regressors. """ + def __init__(self, window, horizon=1, regressor=None): self.window = window self.regressor = regressor @@ -45,22 +46,23 @@ def __init__(self, window, horizon=1, regressor=None): def _fit(self, y, exog=None): """Fit forecaster to time series. - Split X into windows of length window and train the forecaster on each window - to predict the horizon ahead. + Split ``X`` into windows of length ``window`` and train the forecaster on each window + to predict the ``horizon`` ahead. Parameters ---------- - y : np.ndarray - A time series on which to learn a forecaster to predict horizon ahead. - exog : np.ndarray, default=None + y : ``np.ndarray`` + A time series on which to learn a forecaster to predict ``horizon`` ahead. + exog : ``np.ndarray``, default=``None`` Optional exogenous time series data. Included for interface compatibility but ignored in this estimator. Returns ------- self - Fitted estimator - """ + Fitted estimator. + """ + # Window data if self.regressor is None: self.regressor_ = LinearRegression() @@ -79,22 +81,23 @@ def _fit(self, y, exog=None): def _predict(self, y=None, exog=None): """ - Predict the next horizon steps ahead. + Predict the next ``horizon`` steps ahead. Parameters ---------- - y : np.ndarray, default = None - A time series to predict the next horizon value for. If None, - predict the next horizon value after series seen in fit. - exog : np.ndarray, default=None + y : ``np.ndarray``, default=``None`` + A time series to predict the next ``horizon`` value for. If ``None``, + predict the next ``horizon`` value after the series seen in ``fit``. + exog : ``np.ndarray``, default=``None`` Optional exogenous time series data. Included for interface compatibility but ignored in this estimator. Returns ------- - np.ndarray - single prediction self.horizon steps ahead of y. + ``np.ndarray`` + Single prediction ``self.horizon`` steps ahead of ``y``. """ + if y is None: return self.regressor_.predict(self.last_) last = y[:, -self.window :] @@ -102,38 +105,43 @@ def _predict(self, y=None, exog=None): def _forecast(self, y, exog=None): """ - Forecast the next horizon steps ahead. + Forecast the next ``horizon`` steps ahead. Parameters ---------- - y : np.ndarray - A time series to predict the next horizon value for. - exog : np.ndarray, default=None + y : ``np.ndarray`` + A time series to predict the next ``horizon`` value for. + exog : ``np.ndarray``, default=``None`` Optional exogenous time series data. Included for interface compatibility but ignored in this estimator. Returns ------- - np.ndarray - single prediction self.horizon steps ahead of y. + ``np.ndarray`` + Single prediction ``self.horizon`` steps ahead of ``y``. + + Note + ---- + Ensure proper handling of different ``horizon`` values. + """ - NOTE: deal with horizons - """ self.fit(y, exog) return self.predict() @classmethod def _get_test_params(cls, parameter_set="default"): - """Return testing parameter settings for the estimator. + """ + Return testing parameter settings for the estimator. Parameters ---------- - parameter_set : str, default='default' + parameter_set : ``str``, default=``'default'`` Name of the parameter set to return. Returns ------- - dict + ``dict`` Dictionary of testing parameter settings. """ - return {"window": 4} + + return {"window": 4} \ No newline at end of file diff --git a/aeon/forecasting/base.py b/aeon/forecasting/base.py index e67712c58a..cacc602413 100644 --- a/aeon/forecasting/base.py +++ b/aeon/forecasting/base.py @@ -1,9 +1,10 @@ -"""BaseForecaster class. +""" +``BaseForecaster`` class. A simplified first base class for forecasting models. - """ + from abc import abstractmethod import numpy as np @@ -19,15 +20,16 @@ class BaseForecaster(BaseSeriesEstimator): The base forecaster specifies the methods and method signatures that all forecasters have to implement. Attributes with an underscore suffix are set in the - method fit. + method ``fit``. Parameters ---------- - horizon : int, default =1 - The number of time steps ahead to forecast. If horizon is one, the forecaster + horizon : ``int``, default=``1`` + The number of time steps ahead to forecast. If ``horizon`` is one, the forecaster will learn to predict one point ahead. """ + _tags = { "capability:univariate": True, "capability:multivariate": False, @@ -42,22 +44,24 @@ def __init__(self, horizon, axis): super().__init__(axis) def fit(self, y, exog=None): - """Fit forecaster to series y. + """ + Fit forecaster to series ``y``. - Fit a forecaster to predict self.horizon steps ahead using y. + Fit a forecaster to predict ``self.horizon`` steps ahead using ``y``. Parameters ---------- - y : np.ndarray - A time series on which to learn a forecaster to predict horizon ahead. - exog : np.ndarray, default =None - Optional exogenous time series data assumed to be aligned with y. + y : ``np.ndarray`` + A time series on which to learn a forecaster to predict ``horizon`` ahead. + exog : ``np.ndarray``, default=``None`` + Optional exogenous time series data assumed to be aligned with ``y``. Returns ------- self - Fitted BaseForecaster. + Fitted ``BaseForecaster``. """ + if self.get_tag("fit_is_empty"): self.is_fitted = True return self @@ -73,21 +77,23 @@ def fit(self, y, exog=None): def _fit(self, y, exog=None): ... def predict(self, y=None, exog=None): - """Predict the next horizon steps ahead. + """ + Predict the next ``horizon`` steps ahead. Parameters ---------- - y : np.ndarray, default = None - A time series to predict the next horizon value for. If None, - predict the next horizon value after series seen in fit. - exog : np.ndarray, default =None - Optional exogenous time series data assumed to be aligned with y. + y : ``np.ndarray``, default=``None`` + A time series to predict the next ``horizon`` value for. If ``None``, + predict the next ``horizon`` value after the series seen in ``fit``. + exog : ``np.ndarray``, default=``None`` + Optional exogenous time series data assumed to be aligned with ``y``. Returns ------- - float - single prediction self.horizon steps ahead of y. + ``float`` + Single prediction ``self.horizon`` steps ahead of ``y``. """ + self._check_is_fitted() if y is not None: self._check_X(y, self.axis) @@ -100,34 +106,36 @@ def predict(self, y=None, exog=None): def _predict(self, y=None, exog=None): ... def forecast(self, y, exog=None): - """Forecast the next horizon steps ahead. + """ + Forecast the next ``horizon`` steps ahead. - By default this is simply fit followed by predict. + By default, this is simply ``fit`` followed by ``predict``. Parameters ---------- - y : np.ndarray, default = None - A time series to predict the next horizon value for. If None, - predict the next horizon value after series seen in fit. - exog : np.ndarray, default =None - Optional exogenous time series data assumed to be aligned with y. + y : ``np.ndarray``, default=``None`` + A time series to predict the next ``horizon`` value for. If ``None``, + predict the next ``horizon`` value after the series seen in ``fit``. + exog : ``np.ndarray``, default=``None`` + Optional exogenous time series data assumed to be aligned with ``y``. Returns ------- - float - single prediction self.horizon steps ahead of y. + ``float`` + Single prediction ``self.horizon`` steps ahead of ``y``. """ + self._check_X(y, self.axis) y = self._convert_y(y, self.axis) return self._forecast(y, exog) def _forecast(self, y, exog=None): - """Forecast values for time series X.""" + """Forecast values for time series ``X``.""" self.fit(y, exog) return self._predict(y, exog) def _convert_y(self, y: VALID_SERIES_INNER_TYPES, axis: int): - """Convert y to self.get_tag("y_inner_type").""" + """Convert ``y`` to ``self.get_tag("y_inner_type")``.""" if axis > 1 or axis < 0: raise ValueError(f"Input axis should be 0 or 1, saw {axis}") @@ -156,4 +164,4 @@ def _convert_y(self, y: VALID_SERIES_INNER_TYPES, axis: int): y = y.T elif y.ndim == 1 and isinstance(y, np.ndarray): y = y[np.newaxis, :] if self.axis == 1 else y[:, np.newaxis] - return y + return y \ No newline at end of file