Skip to content
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

Forecast base class refactor and extension template #912

Merged
merged 61 commits into from Jun 12, 2021
Merged
Show file tree
Hide file tree
Changes from 56 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
f05c5bd
working on base class refactor
fkiraly May 29, 2021
e7b3da8
BaseForecaster refactor: prediction intervals and docstrings
fkiraly May 29, 2021
55e9f8c
BaseForecaster refactor: gutting _SktimeForecaster but keeping it for…
fkiraly May 29, 2021
a13ff1a
base class refactor: _BaseWindowForecaster inherits from BaseForecaster
fkiraly May 29, 2021
cb8fe2d
base class refactor: _update, docstrings, minor changes
fkiraly May 29, 2021
a654efe
forecasters extension template
fkiraly May 30, 2021
8d3ad5b
linting
fkiraly May 30, 2021
28d8997
syntax error in extension template example
fkiraly May 30, 2021
369e91c
baseforecaster did not have _format_moving_cutoff_predictions, added
fkiraly May 30, 2021
dc22d47
baseforecaster refactor: remove unused imports
fkiraly May 30, 2021
d5fca4c
flake8 linting extension template
fkiraly May 30, 2021
ccd6dda
flake8 linting _base.py
fkiraly May 30, 2021
8d7d944
flake8 linting _sktime.py
fkiraly May 30, 2021
7f29380
black linting extension template
fkiraly May 30, 2021
59c88fd
pydocstyle linting _base
fkiraly May 30, 2021
e09d0e3
pydocstyle linting extension template
fkiraly May 30, 2021
67c0f45
pydocstyle linting _sktime
fkiraly May 30, 2021
f103a7b
added back mixins for compatibility
fkiraly May 30, 2021
5374a44
merge remote/local
fkiraly May 30, 2021
1cc0ffe
merge remote/local
fkiraly May 30, 2021
2330524
pydocstyle linting _sktime.py
fkiraly May 30, 2021
79523de
pydocstyle linting
fkiraly May 30, 2021
d55f99a
... linting
fkiraly May 30, 2021
213da64
resolving circular import
fkiraly May 30, 2021
810473d
import still circular, resolved
fkiraly May 30, 2021
35496c5
fixing inheritance in cleaned base classes and _tags
fkiraly May 30, 2021
e4b1b13
cleaning up erroneous _set_fh logic
fkiraly May 30, 2021
b42a511
flake linting
fkiraly May 30, 2021
27b574d
cleaned fh logic
fkiraly May 30, 2021
440a5c8
some fixing inheritance through hacky fh mixins
fkiraly May 30, 2021
47c39eb
made mixin workaround less invasive
fkiraly May 30, 2021
27411b4
cleaner _is_fitted handling in case fit is called twice
fkiraly May 30, 2021
006b0f0
Merge branch 'main' into forecast-base-refactor
fkiraly May 31, 2021
2cc5e91
removing alpha check from predict since it breaks ARIMA
fkiraly Jun 10, 2021
d03d13c
Merge branch 'main' into forecast-base-refactor
fkiraly Jun 10, 2021
94484e1
Merge branch 'bugfix-reducer-isfitted' into forecast-base-refactor
fkiraly Jun 10, 2021
0c3679d
some linting
fkiraly Jun 10, 2021
66c76bc
Merge branch 'bugfix-reducer-isfitted' into forecast-base-refactor
fkiraly Jun 10, 2021
05d89a1
Merge branch 'bugfix-reducer-isfitted' into forecast-base-refactor
fkiraly Jun 10, 2021
a922db2
loopthrough of _compute_pred_int to _compute_pred_err
fkiraly Jun 10, 2021
049180a
bugfix compute_pred_err
fkiraly Jun 10, 2021
22782c7
linting
fkiraly Jun 10, 2021
ee9cae5
typo on extension template
fkiraly Jun 10, 2021
2e03c11
default_alpha path in extension template
fkiraly Jun 10, 2021
4da724a
linting
fkiraly Jun 10, 2021
fdac037
Merge branch 'bugfix-reducer-isfitted' into forecast-base-refactor
fkiraly Jun 10, 2021
6697af4
Merge branch 'bugfix-reducer-isfitted' into forecast-base-refactor
fkiraly Jun 10, 2021
3317c1e
Merge branch 'bugfix-reducer-isfitted' into forecast-base-refactor
fkiraly Jun 10, 2021
639bc87
Merge branch 'bugfix-reducer-isfitted' into forecast-base-refactor
fkiraly Jun 10, 2021
34bd6f0
problematic behaviour with optional fh when passed in fit and differe…
fkiraly Jun 11, 2021
0cffd6f
fixing _set_fh logic
fkiraly Jun 11, 2021
7fa7365
looping default _update to fit not _fit to avoid interface breakage
fkiraly Jun 11, 2021
b5988ae
added fhmixinflag to VALID_ESTIMATOR_TAGS
fkiraly Jun 11, 2021
88a855e
check_estimator_tag should also allow string valued tags
fkiraly Jun 11, 2021
9324828
fixing wrong name to fh flag in tests._config
fkiraly Jun 11, 2021
700295e
updating all-contributors :smiley:
fkiraly Jun 11, 2021
a20fc77
updated extension template
fkiraly Jun 12, 2021
26655dd
linting
fkiraly Jun 12, 2021
99f7b0e
linting
fkiraly Jun 12, 2021
5429d77
Merge branch 'main' into forecast-base-refactor
fkiraly Jun 12, 2021
febbf42
Suggested changes (#950)
mloning Jun 12, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions .all-contributorsrc
Expand Up @@ -15,14 +15,17 @@
"profile": "https://github.com/fkiraly",
"contributions": [
"business",
"code",
"doc",
"design",
"eventOrganizing",
"financial",
"fundingFinding",
"ideas",
"mentoring",
"projectManagement",
"question",
"research",
"review",
"talk"
]
Expand Down
244 changes: 244 additions & 0 deletions extension_templates/forecasting.py
@@ -0,0 +1,244 @@
# -*- coding: utf-8 -*-
"""
mloning marked this conversation as resolved.
Show resolved Hide resolved
Extension template for forecasters.

How to use this:
- this is meant as a "fill in" template for easy extension
- do NOT import this file directly - it will break
- work through all the "todo" comments below
- fill in code for mandatory methods, and optionally for optional methods
- you can add more private methods, but do not override BaseEstimator's private methods
an easy way to be safe is to prefix your methods with "_custom"
- change docstrings for functions and the file
- ensure interface compatibility by testing forecasting/tests/test_all_forecasters
and forecasting/tests/test_sktime_forecasters
- once complete: use as a local library, or contribute to sktime via PR

Mandatory implements:
fitting - _fit(self, y, X=None, fh=None)
forecasting - _predict(self, fh=None, X=None, return_pred_int=False,
alpha=DEFAULT_ALPHA)

Optional implements:
updating - _update(self, y, X=None, update_params=True):
fitted parameter inspection - get_fitted_params()

State:
fitted model/strategy - by convention, any attributes ending in "_"
fitted state flag - check_is_fitted()

copyright: sktime developers, BSD-3-Clause License (see LICENSE file)
"""

from sktime.forecasting.base import BaseForecaster
from sktime.forecasting.base._base import DEFAULT_ALPHA

# todo: add any necessary imports here


class MyForecaster(BaseForecaster):
"""Custom forecaster. todo: write docstring.

todo: describe your custom forecaster here

Hyper-parameters
----------------
parama : int
descriptive explanation of parama
paramb : string, optional (default='default')
descriptive explanation of paramb
paramc : boolean, optional (default= whether paramb is not the default)
descriptive explanation of paramc
and so on

Components
----------
est : sktime.estimator, BaseEstimator descendant
descriptive explanation of est
est2: another estimator
descriptive explanation of est2
and so on
"""

# todo: add any hyper-parameters and components to constructor
def __init__(self, parama, paramb="default", paramc=None):

# todo: write any hyper-parameters and components to self
self.parama = parama
self.paramb = paramb
self.paramc = paramc

# todo: initialize None parameters, where necessary
if paramc is None:
mloning marked this conversation as resolved.
Show resolved Hide resolved
self.paramc = "42"

# todo: uncomment if forecast horizon is needed only in predict
# self._tags["fh_in_fit"] = "optional"

# todo: change "MyForecaster" to the name of the class
super(MyForecaster, self).__init__()

# todo: implement this, mandatory
def _fit(self, y, X=None, fh=None):
"""Fit forecaster to training data.

core logic

Parameters
----------
y : pd.Series
Target time series to which to fit the forecaster.
fh : int, list, np.array or ForecastingHorizon, optional (default=None)
The forecasters horizon with the steps ahead to to predict.
X : pd.DataFrame, optional (default=None)

Returns
-------
self : returns an instance of self.
"""

# implement here
# IMPORTANT: avoid side effects to y, X, fh

# todo: implement this, mandatory
def _predict(self, fh, X=None, return_pred_int=False, alpha=DEFAULT_ALPHA):
"""Forecast time series at future horizon.

core logic

Parameters
----------
fh : int, list, np.array or ForecastingHorizon
Forecasting horizon
X : pd.DataFrame, optional (default=None)
Exogenous time series
return_pred_int : bool, optional (default=False)
If True, returns prediction intervals for given alpha values.
alpha : float or list, optional (default=0.95)

Returns
-------
y_pred : pd.Series
Point predictions
y_pred_int : pd.DataFrame - only if return_pred_int=True
Prediction intervals
"""

# implement here
# IMPORTANT: avoid side effects to X, fh

# todo: consider implementing this, optional
# if not implementing, delete the _update method
def _update(self, y, X=None, update_params=True):
"""Update time series to incremental training data.

core logic

Parameters
----------
fh : int, list, np.array or ForecastingHorizon
Forecasting horizon
X : pd.DataFrame, optional (default=None)
Exogenous time series
return_pred_int : bool, optional (default=False)
If True, returns prediction intervals for given alpha values.
alpha : float or list, optional (default=0.95)

Returns
-------
y_pred : pd.Series
Point predictions
y_pred_int : pd.DataFrame - only if return_pred_int=True
Prediction intervals

State change
------------
updates self._X and self._y with new data
updates self.cutoff to most recent time in y
if update_params=True, updates model (attributes ending in "_")
"""

# implement here
# IMPORTANT: avoid side effects to X, fh

# todo: consider implementing this, optional
# if not implementing, delete the method
def _update_predict_single(
self,
y,
fh,
X=None,
update_params=True,
return_pred_int=False,
alpha=DEFAULT_ALPHA,
):
"""Update forecaster and then make forecasts.

Implements default behaviour of calling update and predict
sequentially, but can be overwritten by subclasses
to implement more efficient updating algorithms when available.
"""
self.update(y, X, update_params=update_params)
return self.predict(fh, X, return_pred_int=return_pred_int, alpha=alpha)

# implement here
# IMPORTANT: avoid side effects to y, X, fh

# todo: consider implementing this, optional
# if not implementing, delete the method
def _compute_pred_int(self, alphas):
"""Calculate the prediction errors for each point.

Parameters
----------
alpha : float or list, optional (default=0.95)
A significance level or list of significance levels.

Returns
-------
errors : list of pd.Series
Each series in the list will contain the errors for each point in
the forecast for the corresponding alpha.
"""
# implement here

# todo: consider implementing this, optional
# if not implementing, delete the method
def _predict_moving_cutoff(
self,
y,
cv,
X=None,
update_params=True,
return_pred_int=False,
alpha=DEFAULT_ALPHA,
):
"""Make single-step or multi-step moving cutoff predictions.

Parameters
----------
y : pd.Series
cv : temporal cross-validation generator
X : pd.DataFrame
update_params : bool
return_pred_int : bool
alpha : float or array-like

Returns
-------
y_pred = pd.Series
"""

# implement here
# IMPORTANT: avoid side effects to y, X, cv

# todo: consider implementing this, optional
# if not implementing, delete the method
def get_fitted_params(self):
"""Get fitted parameters.

Returns
-------
fitted_params : dict
"""
# implement here