From 08b748c867381b2dc5bf2447da1195194dd2d707 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Sun, 31 Jan 2021 18:50:24 +0100 Subject: [PATCH] Move `decomposition` module into `methods` sub-package - move the module - unify the corresponding tests in `tests.forecasts.methods` sub-package - make all `predict()` and the `stl()` function round results - streamline documentation --- setup.cfg | 2 +- src/urban_meal_delivery/forecasts/__init__.py | 1 - .../forecasts/methods/__init__.py | 1 + .../forecasts/methods/arima.py | 4 ++-- .../forecasts/{ => methods}/decomposition.py | 15 +++++++++------ src/urban_meal_delivery/forecasts/methods/ets.py | 4 ++-- tests/forecasts/methods/__init__.py | 1 + .../forecasts/{ => methods}/test_decomposition.py | 2 +- .../test_ts_methods.py} | 5 ++++- 9 files changed, 21 insertions(+), 14 deletions(-) rename src/urban_meal_delivery/forecasts/{ => methods}/decomposition.py (96%) create mode 100644 tests/forecasts/methods/__init__.py rename tests/forecasts/{ => methods}/test_decomposition.py (99%) rename tests/forecasts/{test_methods.py => methods/test_ts_methods.py} (96%) diff --git a/setup.cfg b/setup.cfg index 1e46f21..46e2db8 100644 --- a/setup.cfg +++ b/setup.cfg @@ -147,7 +147,7 @@ per-file-ignores = src/urban_meal_delivery/db/restaurants.py: # The module is not too complex. WPS232, - src/urban_meal_delivery/forecasts/decomposition.py: + src/urban_meal_delivery/forecasts/methods/decomposition.py: # The module is not too complex. WPS232, src/urban_meal_delivery/forecasts/timify.py: diff --git a/src/urban_meal_delivery/forecasts/__init__.py b/src/urban_meal_delivery/forecasts/__init__.py index 86dcac6..5ecdd1e 100644 --- a/src/urban_meal_delivery/forecasts/__init__.py +++ b/src/urban_meal_delivery/forecasts/__init__.py @@ -1,5 +1,4 @@ """Demand forecasting utilities.""" -from urban_meal_delivery.forecasts import decomposition from urban_meal_delivery.forecasts import methods from urban_meal_delivery.forecasts import timify diff --git a/src/urban_meal_delivery/forecasts/methods/__init__.py b/src/urban_meal_delivery/forecasts/methods/__init__.py index 316ae69..9b88926 100644 --- a/src/urban_meal_delivery/forecasts/methods/__init__.py +++ b/src/urban_meal_delivery/forecasts/methods/__init__.py @@ -1,4 +1,5 @@ """Various forecasting methods implemented as functions.""" from urban_meal_delivery.forecasts.methods import arima +from urban_meal_delivery.forecasts.methods import decomposition from urban_meal_delivery.forecasts.methods import ets diff --git a/src/urban_meal_delivery/forecasts/methods/arima.py b/src/urban_meal_delivery/forecasts/methods/arima.py index 976df3e..3abd60e 100644 --- a/src/urban_meal_delivery/forecasts/methods/arima.py +++ b/src/urban_meal_delivery/forecasts/methods/arima.py @@ -14,7 +14,7 @@ def predict( ) -> pd.DataFrame: """Predict with an automatically chosen ARIMA model. - Note: The function does not check if the `forecast` interval + Note: The function does not check if the `forecast_interval` extends the `training_ts`'s interval without a gap! Args: @@ -65,7 +65,7 @@ def predict( forecasts = pandas2ri.rpy2py(result) forecasts.index = forecast_interval - return forecasts.rename( + return forecasts.round(5).rename( columns={ 'Point Forecast': 'prediction', 'Lo 80': 'low80', diff --git a/src/urban_meal_delivery/forecasts/decomposition.py b/src/urban_meal_delivery/forecasts/methods/decomposition.py similarity index 96% rename from src/urban_meal_delivery/forecasts/decomposition.py rename to src/urban_meal_delivery/forecasts/methods/decomposition.py index a0762d5..3be8582 100644 --- a/src/urban_meal_delivery/forecasts/decomposition.py +++ b/src/urban_meal_delivery/forecasts/methods/decomposition.py @@ -169,10 +169,13 @@ def stl( # noqa:C901,WPS210,WPS211,WPS231 # Unpack the result to a `pd.DataFrame`. result = pandas2ri.rpy2py(result[0]) - result = { - 'seasonal': pd.Series(result[:, 0], index=time_series.index), - 'trend': pd.Series(result[:, 1], index=time_series.index), - 'residual': pd.Series(result[:, 2], index=time_series.index), - } + result = pd.DataFrame( + data={ + 'seasonal': result[:, 0], + 'trend': result[:, 1], + 'residual': result[:, 2], + }, + index=time_series.index, + ) - return pd.DataFrame(result) + return result.round(5) diff --git a/src/urban_meal_delivery/forecasts/methods/ets.py b/src/urban_meal_delivery/forecasts/methods/ets.py index 020e4a4..5b70aef 100644 --- a/src/urban_meal_delivery/forecasts/methods/ets.py +++ b/src/urban_meal_delivery/forecasts/methods/ets.py @@ -14,7 +14,7 @@ def predict( ) -> pd.DataFrame: """Predict with an automatically calibrated ETS model. - Note: The function does not check if the `forecast` interval + Note: The function does not check if the `forecast_interval` extends the `training_ts`'s interval without a gap! Args: @@ -66,7 +66,7 @@ def predict( forecasts = pandas2ri.rpy2py(result) forecasts.index = forecast_interval - return forecasts.rename( + return forecasts.round(5).rename( columns={ 'Point Forecast': 'prediction', 'Lo 80': 'low80', diff --git a/tests/forecasts/methods/__init__.py b/tests/forecasts/methods/__init__.py new file mode 100644 index 0000000..e767595 --- /dev/null +++ b/tests/forecasts/methods/__init__.py @@ -0,0 +1 @@ +"""Tests for the `urban_meal_delivery.forecasts.methods` sub-package.""" diff --git a/tests/forecasts/test_decomposition.py b/tests/forecasts/methods/test_decomposition.py similarity index 99% rename from tests/forecasts/test_decomposition.py rename to tests/forecasts/methods/test_decomposition.py index 1f20535..0687d9c 100644 --- a/tests/forecasts/test_decomposition.py +++ b/tests/forecasts/methods/test_decomposition.py @@ -7,7 +7,7 @@ import pytest from tests.forecasts.conftest import NS from tests.forecasts.conftest import VERTICAL_FREQUENCY -from urban_meal_delivery.forecasts import decomposition +from urban_meal_delivery.forecasts.methods import decomposition class TestInvalidArguments: diff --git a/tests/forecasts/test_methods.py b/tests/forecasts/methods/test_ts_methods.py similarity index 96% rename from tests/forecasts/test_methods.py rename to tests/forecasts/methods/test_ts_methods.py index 9b2f0f8..11691c7 100644 --- a/tests/forecasts/test_methods.py +++ b/tests/forecasts/methods/test_ts_methods.py @@ -1,4 +1,7 @@ -"""Test the `arima.predict()` and `ets.predict()` functions.""" +"""Test the `arima.predict()` and `ets.predict()` functions. + +We consider both "classical" time series prediction models. +""" import datetime as dt