Skip to content

[ENH] Auto naive forecaster #2926

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions aeon/forecasting/_auto_naive.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
"""Naive forecaster with parameters set on the training data."""

"""Naive forecaster with multiple strategies."""

__maintainer__ = ["TonyBagnall"]
__all__ = ["AutoNaiveForecaster"]


import numpy as np
from enum import Enum
from aeon.forecasting.base import BaseForecaster


class AutoNaiveForecaster(BaseForecaster):
"""
Naive forecaster with strategy set based on minimising error.

Searches options, "last", "mean", and "seasonal_last", with season in range [2,max_season].
If max_season is not passed to the constructor, it will be set to series length/2.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be length/4


Simple first implementation, splits the train series into 70% train and 30% validation split
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe it does this, it simply minimises RMSE over the whole series passed in _fit

and minimises RMSE on the validation set.

Parameters
----------
max_season : int or None, default=None
The maximum season to consider in the parameter search. In None, set as quarter the length of the series
passed in `fit`.

Examples
--------
>>> import aeon as ae
"""

def __init__(self, max_season=None, horizon=1):
self.max_season = max_season
self.strategy_ = "last"
super().__init__(horizon=horizon, axis=1)

def _fit(self, y, exog=None):
y = y.squeeze()
self._y = y
# last strategy
mse_last = np.mean((y[1:] - y[:-1]) ** 2)

# series mean strategy, in sample
mse_mean = np.mean((y - np.mean(y)) ** 2)

# seasonal strategy, in sample
max_season = self.max_season
if self.max_season is None:
max_season = len(y)/4
best_s = None
best_seasonal = np.inf
for s in range(1, max_season + 1):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be 2 surely? - as the interval is [2, max_season]

# Predict y[t] = y[t - s]
y_true = y[s:]
y_pred = y[:-s]
mse = np.mean((y_true - y_pred) ** 2)

if mse < best_seasonal:
best_seasonal = mse
best_s = s
self.best_mse_ = mse_last
self._fitted_scalar_value = y[:-1]

if mse_mean < mse_last:
self.strategy_ = "mean"
self.best_mse_ = mse_mean
self._fitted_scalar_value = np.mean(y)

if self.best_mse_ < best_seasonal:
self.strategy_ = "seasonal"
self.season_ = best_s
self.best_mse_ = best_seasonal

return self

def _predict(self, y, exog=None):
if self.strategy_ == "last" or self.strategy_ == "mean":
return self._fitted_scalar_value
# For "seasonal_last" strategy
prediction_index = (self.horizon - 1) % self.season_
return self.self._y [prediction_index]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this should be self.y[-self.season - 1 + prediction_index)] that way it is predicting the last seasonal value in the series, rather than the corresponding seasonal value at the start of the series



2 changes: 1 addition & 1 deletion aeon/forecasting/_naive.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Naive forecaster with multiple strategies."""

__maintainer__ = []
__maintainer__ = ["TonyBagnall"]
__all__ = ["NaiveForecaster"]


Expand Down
Loading