Skip to content

Commit

Permalink
fix_last_window_and_copies
Browse files Browse the repository at this point in the history
  • Loading branch information
JavierEscobarOrtiz committed Nov 15, 2023
1 parent f2541d4 commit 819726c
Show file tree
Hide file tree
Showing 15 changed files with 296 additions and 306 deletions.
27 changes: 7 additions & 20 deletions skforecast/ForecasterAutoreg/ForecasterAutoreg.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import sklearn
import sklearn.pipeline
from sklearn.base import clone
from copy import copy
import inspect

import skforecast
Expand Down Expand Up @@ -639,12 +638,7 @@ def predict(
"""

if last_window is None:
if self.fitted:
last_window = self.last_window.copy()
else:
last_window = copy(self.last_window)
else:
last_window = last_window.copy()
last_window = self.last_window

check_predict_input(
forecaster_name = type(self).__name__,
Expand All @@ -666,8 +660,7 @@ def predict(
series_col_names = None
)

if last_window is not None:
last_window = last_window.iloc[-self.window_size:]
last_window = last_window.iloc[-self.window_size:].copy()

if exog is not None:
if isinstance(exog, pd.DataFrame):
Expand Down Expand Up @@ -703,8 +696,8 @@ def predict(

predictions = self._recursive_predict(
steps = steps,
last_window = copy(last_window_values),
exog = copy(exog_values)
last_window = last_window_values,
exog = exog_values
)

if self.differentiation is not None:
Expand Down Expand Up @@ -789,14 +782,9 @@ def predict_bootstrapping(
"before `predict_interval()`, `predict_bootstrapping()`, "
"`predict_quantiles()` or `predict_dist()`.")
)

if last_window is None:
if self.fitted:
last_window = self.last_window.copy()
else:
last_window = copy(self.last_window)
else:
last_window = last_window.copy()
last_window = self.last_window

check_predict_input(
forecaster_name = type(self).__name__,
Expand All @@ -818,8 +806,7 @@ def predict_bootstrapping(
series_col_names = None
)

if last_window is not None:
last_window = last_window.iloc[-self.window_size:]
last_window = last_window.iloc[-self.window_size:]

if exog is not None:
if isinstance(exog, pd.DataFrame):
Expand Down
27 changes: 7 additions & 20 deletions skforecast/ForecasterAutoregCustom/ForecasterAutoregCustom.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import sklearn
import sklearn.pipeline
from sklearn.base import clone
from copy import copy
import inspect

import skforecast
Expand Down Expand Up @@ -662,12 +661,7 @@ def predict(
"""

if last_window is None:
if self.fitted:
last_window = self.last_window.copy()
else:
last_window = copy(self.last_window)
else:
last_window = last_window.copy()
last_window = self.last_window

check_predict_input(
forecaster_name = type(self).__name__,
Expand All @@ -689,8 +683,7 @@ def predict(
series_col_names = None
)

if last_window is not None:
last_window = last_window.iloc[-self.window_size:]
last_window = last_window.iloc[-self.window_size:].copy()

if exog is not None:
if isinstance(exog, pd.DataFrame):
Expand Down Expand Up @@ -726,8 +719,8 @@ def predict(

predictions = self._recursive_predict(
steps = steps,
last_window = copy(last_window_values),
exog = copy(exog_values)
last_window = last_window_values,
exog = exog_values
)

if self.differentiation is not None:
Expand Down Expand Up @@ -812,14 +805,9 @@ def predict_bootstrapping(
"before `predict_interval()`, `predict_bootstrapping()`, "
"`predict_quantiles()` or `predict_dist()`.")
)

if last_window is None:
if self.fitted:
last_window = self.last_window.copy()
else:
last_window = copy(self.last_window)
else:
last_window = last_window.copy()
last_window = self.last_window

check_predict_input(
forecaster_name = type(self).__name__,
Expand All @@ -841,8 +829,7 @@ def predict_bootstrapping(
series_col_names = None
)

if last_window is not None:
last_window = last_window.iloc[-self.window_size:]
last_window = last_window.iloc[-self.window_size:].copy()

if exog is not None:
if isinstance(exog, pd.DataFrame):
Expand Down
109 changes: 52 additions & 57 deletions skforecast/ForecasterAutoregDirect/ForecasterAutoregDirect.py
Original file line number Diff line number Diff line change
Expand Up @@ -694,11 +694,11 @@ def fit_forecaster(regressor, X_train, y_train, step, store_in_sample_residuals)
Parallel(n_jobs=self.n_jobs)
(delayed(fit_forecaster)
(
regressor=copy(self.regressor),
X_train=X_train,
y_train=y_train,
step=step,
store_in_sample_residuals=store_in_sample_residuals
regressor = copy(self.regressor),
X_train = X_train,
y_train = y_train,
step = step,
store_in_sample_residuals = store_in_sample_residuals
)
for step in range(1, self.steps + 1))
)
Expand Down Expand Up @@ -773,12 +773,7 @@ def predict(
)

if last_window is None:
if self.fitted:
last_window = self.last_window.copy()
else:
last_window = copy(self.last_window)
else:
last_window = last_window.copy()
last_window = self.last_window

check_predict_input(
forecaster_name = type(self).__name__,
Expand All @@ -800,8 +795,7 @@ def predict(
series_col_names = None
)

if last_window is not None:
last_window = last_window.iloc[-self.window_size:]
last_window = last_window.iloc[-self.window_size:].copy()

if exog is not None:
if isinstance(exog, pd.DataFrame):
Expand Down Expand Up @@ -932,53 +926,54 @@ def predict_bootstrapping(
Forecasting: Principles and Practice (3nd ed) Rob J Hyndman and George Athanasopoulos.
"""

if isinstance(steps, int):
steps = list(np.arange(steps) + 1)
elif steps is None:
steps = list(np.arange(self.steps) + 1)
elif isinstance(steps, list):
steps = list(np.array(steps))

if in_sample_residuals:
if not set(steps).issubset(set(self.in_sample_residuals.keys())):
raise ValueError(
(f"Not `forecaster.in_sample_residuals` for steps: "
f"{set(steps) - set(self.in_sample_residuals.keys())}.")
)
residuals = self.in_sample_residuals
else:
if self.out_sample_residuals is None:
raise ValueError(
("`forecaster.out_sample_residuals` is `None`. Use "
"`in_sample_residuals=True` or method `set_out_sample_residuals()` "
"before `predict_interval()`, `predict_bootstrapping()`, "
"`predict_quantiles()` or `predict_dist()`.")
)

if self.fitted:
if isinstance(steps, int):
steps = list(np.arange(steps) + 1)
elif steps is None:
steps = list(np.arange(self.steps) + 1)
elif isinstance(steps, list):
steps = list(np.array(steps))

if in_sample_residuals:
if not set(steps).issubset(set(self.in_sample_residuals.keys())):
raise ValueError(
(f"Not `forecaster.in_sample_residuals` for steps: "
f"{set(steps) - set(self.in_sample_residuals.keys())}.")
)
residuals = self.in_sample_residuals
else:
if not set(steps).issubset(set(self.out_sample_residuals.keys())):
if self.out_sample_residuals is None:
raise ValueError(
(f"Not `forecaster.out_sample_residuals` for steps: "
f"{set(steps) - set(self.out_sample_residuals.keys())}. "
f"Use method `set_out_sample_residuals()`.")
("`forecaster.out_sample_residuals` is `None`. Use "
"`in_sample_residuals=True` or method `set_out_sample_residuals()` "
"before `predict_interval()`, `predict_bootstrapping()`, "
"`predict_quantiles()` or `predict_dist()`.")
)
else:
if not set(steps).issubset(set(self.out_sample_residuals.keys())):
raise ValueError(
(f"Not `forecaster.out_sample_residuals` for steps: "
f"{set(steps) - set(self.out_sample_residuals.keys())}. "
f"Use method `set_out_sample_residuals()`.")
)
residuals = self.out_sample_residuals

check_residuals = (
"forecaster.in_sample_residuals" if in_sample_residuals
else "forecaster.out_sample_residuals"
)
for step in steps:
if residuals[step] is None:
raise ValueError(
(f"forecaster residuals for step {step} are `None`. "
f"Check {check_residuals}.")
)
elif (residuals[step] == None).any():
raise ValueError(
(f"forecaster residuals for step {step} contains `None` values. "
f"Check {check_residuals}.")
)
residuals = self.out_sample_residuals

check_residuals = (
"forecaster.in_sample_residuals" if in_sample_residuals
else "forecaster.out_sample_residuals"
)
for step in steps:
if residuals[step] is None:
raise ValueError(
(f"forecaster residuals for step {step} are `None`. "
f"Check {check_residuals}.")
)
elif (residuals[step] == None).any():
raise ValueError(
(f"forecaster residuals for step {step} contains `None` values. "
f"Check {check_residuals}.")
)

predictions = self.predict(
steps = steps,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import pytest
import numpy as np
import pandas as pd
from sklearn.exceptions import NotFittedError
from skforecast.ForecasterAutoregDirect import ForecasterAutoregDirect
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import StandardScaler
Expand All @@ -14,6 +15,20 @@
from .fixtures_ForecasterAutoregDirect import exog_predict


def test_predict_NotFittedError_when_fitted_is_False():
"""
Test NotFittedError is raised when fitted is False.
"""
forecaster = ForecasterAutoregDirect(LinearRegression(), lags=3, steps=5)

err_msg = re.escape(
('This Forecaster instance is not fitted yet. Call `fit` with '
'appropriate arguments before using predict.')
)
with pytest.raises(NotFittedError, match = err_msg):
forecaster.predict_bootstrapping(steps=5)


def test_predict_bootstrapping_ValueError_when_not_in_sample_residuals_for_some_step():
"""
Test ValueError is raised when in_sample_residuals=True but there is no
Expand Down
Loading

0 comments on commit 819726c

Please sign in to comment.