From 0e13ea1e248cda0fa80895f8a86ff55f24fb0f4c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 14:25:35 +0000 Subject: [PATCH 1/5] Bump skforecast from 0.13.0 to 0.14.0 Bumps [skforecast](https://github.com/skforecast/skforecast) from 0.13.0 to 0.14.0. - [Release notes](https://github.com/skforecast/skforecast/releases) - [Changelog](https://github.com/skforecast/skforecast/blob/master/changelog.md) - [Commits](https://github.com/skforecast/skforecast/compare/v0.13.0...v0.14.0) --- updated-dependencies: - dependency-name: skforecast dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- docs/requirements.txt | 2 +- requirements.txt | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 1cc2e689..ab80f5e1 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -10,7 +10,7 @@ beautifulsoup4>=4.9.3 pulp>=2.4 pyyaml>=5.4.1 tables==3.9.1 -skforecast==0.13.0 +skforecast==0.14.0 markupsafe==3.0.2 Jinja2<3.2 plotly>=5.6.0 diff --git a/requirements.txt b/requirements.txt index 32cd7336..d0e4c049 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,7 @@ h5py==3.12.1 pulp>=2.4 pyyaml>=5.4.1 tables<=3.9.1 -skforecast==0.13.0 +skforecast==0.14.0 # web server packages flask>=2.0.3 waitress>=2.1.1 diff --git a/setup.py b/setup.py index b00062e9..1bf978be 100644 --- a/setup.py +++ b/setup.py @@ -52,7 +52,7 @@ 'pulp>=2.4', 'pyyaml>=5.4.1', 'tables<=3.9.1', - 'skforecast==0.13.0', + 'skforecast==0.14.0', 'flask>=2.0.3', 'waitress>=2.1.1', 'plotly>=5.6.0' From a4d20e6c96f16f765e828c3d16929d1922b38781 Mon Sep 17 00:00:00 2001 From: davidusb-geek Date: Wed, 27 Nov 2024 22:24:36 +0100 Subject: [PATCH 2/5] Fix skforecast breaking changes --- src/emhass/machine_learning_forecaster.py | 4 ++-- tests/test_machine_learning_forecaster.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/emhass/machine_learning_forecaster.py b/src/emhass/machine_learning_forecaster.py index 3691ead6..76032ff9 100644 --- a/src/emhass/machine_learning_forecaster.py +++ b/src/emhass/machine_learning_forecaster.py @@ -13,7 +13,7 @@ from sklearn.neighbors import KNeighborsRegressor from sklearn.metrics import r2_score -from skforecast.ForecasterAutoreg import ForecasterAutoreg +from skforecast.recursive import ForecasterRecursive from skforecast.model_selection import bayesian_search_forecaster from skforecast.model_selection import backtesting_forecaster @@ -144,7 +144,7 @@ def fit(self, split_date_delta: Optional[str] = '48h', perform_backtest: Optiona self.logger.error("Passed sklearn model "+self.sklearn_model+" is not valid. Defaulting to KNeighborsRegressor") base_model = KNeighborsRegressor() # Define the forecaster object - self.forecaster = ForecasterAutoreg( + self.forecaster = ForecasterRecursive( regressor = base_model, lags = self.num_lags ) diff --git a/tests/test_machine_learning_forecaster.py b/tests/test_machine_learning_forecaster.py index 78e7a3d0..3cb7775d 100644 --- a/tests/test_machine_learning_forecaster.py +++ b/tests/test_machine_learning_forecaster.py @@ -10,7 +10,7 @@ import pandas as pd import numpy as np -from skforecast.ForecasterAutoreg import ForecasterAutoreg +from skforecast.recursive import ForecasterRecursive from emhass.command_line import set_input_data_dict from emhass.retrieve_hass import RetrieveHass @@ -82,12 +82,12 @@ def setUp(self): def test_fit(self): df_pred, df_pred_backtest = self.mlf.fit() - self.assertIsInstance(self.mlf.forecaster, ForecasterAutoreg) + self.assertIsInstance(self.mlf.forecaster, ForecasterRecursive) self.assertIsInstance(df_pred, pd.DataFrame) self.assertTrue(df_pred_backtest == None) # Refit with backtest evaluation df_pred, df_pred_backtest = self.mlf.fit(perform_backtest=True) - self.assertIsInstance(self.mlf.forecaster, ForecasterAutoreg) + self.assertIsInstance(self.mlf.forecaster, ForecasterRecursive) self.assertIsInstance(df_pred, pd.DataFrame) self.assertIsInstance(df_pred_backtest, pd.DataFrame) From 3dc99dce8b75088ae5fc629366b6d400551e303a Mon Sep 17 00:00:00 2001 From: davidusb-geek Date: Wed, 27 Nov 2024 22:48:52 +0100 Subject: [PATCH 3/5] Fixing bayesian optimization method --- src/emhass/machine_learning_forecaster.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/emhass/machine_learning_forecaster.py b/src/emhass/machine_learning_forecaster.py index 76032ff9..86980ccc 100644 --- a/src/emhass/machine_learning_forecaster.py +++ b/src/emhass/machine_learning_forecaster.py @@ -13,9 +13,8 @@ from sklearn.neighbors import KNeighborsRegressor from sklearn.metrics import r2_score -from skforecast.recursive import ForecasterRecursive -from skforecast.model_selection import bayesian_search_forecaster -from skforecast.model_selection import backtesting_forecaster +from skforecast.ForecasterAutoreg import ForecasterAutoreg +from skforecast.model_selection import bayesian_search_forecaster, backtesting_forecaster, TimeSeriesFold import warnings warnings.filterwarnings("ignore", category=DeprecationWarning) @@ -144,7 +143,7 @@ def fit(self, split_date_delta: Optional[str] = '48h', perform_backtest: Optiona self.logger.error("Passed sklearn model "+self.sklearn_model+" is not valid. Defaulting to KNeighborsRegressor") base_model = KNeighborsRegressor() # Define the forecaster object - self.forecaster = ForecasterRecursive( + self.forecaster = ForecasterAutoreg( regressor = base_model, lags = self.num_lags ) @@ -271,20 +270,26 @@ def search_space(trial): # The optimization routine call self.logger.info("Bayesian hyperparameter optimization with backtesting") start_time = time.time() + cv = TimeSeriesFold( + steps = num_lags, + initial_train_size = len(self.data_exo.loc[:self.date_train]), + fixed_train_size = True, + gap = 0, + skip_folds = None, + allow_incomplete_fold = True, + refit = False + ) self.optimize_results, self.optimize_results_object = bayesian_search_forecaster( forecaster = self.forecaster, y = self.data_train[self.var_model], exog = self.data_train.drop(self.var_model, axis=1), + cv = cv, search_space = search_space, - steps = num_lags, metric = MLForecaster.neg_r2_score, refit = refit, - initial_train_size = len(self.data_exo.loc[:self.date_train]), - fixed_train_size = True, n_trials = 10, random_state = 123, return_best = True, - verbose = False, engine = 'optuna' ) self.logger.info(f"Elapsed time: {time.time() - start_time}") From 5518913d680a03f415dfe5db7926e8be946f3883 Mon Sep 17 00:00:00 2001 From: davidusb-geek Date: Wed, 27 Nov 2024 22:53:05 +0100 Subject: [PATCH 4/5] Fixing reverted change on skforecast --- src/emhass/machine_learning_forecaster.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/emhass/machine_learning_forecaster.py b/src/emhass/machine_learning_forecaster.py index 86980ccc..b4a36ca3 100644 --- a/src/emhass/machine_learning_forecaster.py +++ b/src/emhass/machine_learning_forecaster.py @@ -13,7 +13,7 @@ from sklearn.neighbors import KNeighborsRegressor from sklearn.metrics import r2_score -from skforecast.ForecasterAutoreg import ForecasterAutoreg +from skforecast.recursive import ForecasterRecursive from skforecast.model_selection import bayesian_search_forecaster, backtesting_forecaster, TimeSeriesFold import warnings @@ -143,7 +143,7 @@ def fit(self, split_date_delta: Optional[str] = '48h', perform_backtest: Optiona self.logger.error("Passed sklearn model "+self.sklearn_model+" is not valid. Defaulting to KNeighborsRegressor") base_model = KNeighborsRegressor() # Define the forecaster object - self.forecaster = ForecasterAutoreg( + self.forecaster = ForecasterRecursive( regressor = base_model, lags = self.num_lags ) From 7dbbc2960ea5f1c42c10914c7fe296534dc38667 Mon Sep 17 00:00:00 2001 From: davidusb-geek Date: Fri, 20 Dec 2024 16:15:46 +0100 Subject: [PATCH 5/5] Fixed skforecast migration to 0.14 and fixed the pyproject.toml file --- pyproject.toml | 43 +++++++++++++---------- src/emhass/machine_learning_forecaster.py | 22 +++++++----- 2 files changed, 38 insertions(+), 27 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index bd130025..c2133743 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,7 +14,6 @@ authors = [ {name = "David HERNANDEZ", email = "davidusb@gmail.com"}, ] license = {text = "MIT"} -homepage = "https://github.com/davidusb-geek/emhass" keywords = ["energy", "management", "optimization", "hass"] classifiers = [ "Development Status :: 5 - Production/Stable", @@ -25,23 +24,28 @@ classifiers = [ "Operating System :: OS Independent", ] -[project.dependencies] -numpy = "==1.26.4" -scipy = "==1.12.0" -pandas = "<=2.0.3" -pvlib = ">=0.10.2" -protobuf = ">=3.0.0" -pytz = ">=2021.1" -requests = ">=2.25.1" -beautifulsoup4 = ">=4.9.3" -h5py = "==3.12.1" -pulp = ">=2.4" -pyyaml = ">=5.4.1" -tables = "<=3.9.1" -skforecast = "==0.13.0" -flask = ">=2.0.3" -waitress = ">=2.1.1" -plotly = ">=5.6.0" +dependencies = [ + "numpy==1.26.4", + "scipy==1.12.0", + "pandas<=2.0.3", + "pvlib>=0.10.2", + "protobuf>=3.0.0", + "pytz>=2021.1", + "requests>=2.25.1", + "beautifulsoup4>=4.9.3", + "h5py==3.12.1", + "pulp>=2.4", + "pyyaml>=5.4.1", + "tables<=3.9.1", + "skforecast==0.14.0", + "flask>=2.0.3", + "waitress>=2.1.1", + "plotly>=5.6.0" +] + +[project.optional-dependencies] +docs = ["sphinx", "sphinx-rtd-theme", "myst-parser"] +test = ["requests_mock","pytest","coverage","snakeviz","ruff"] [tool.setuptools.packages] find = {where = ["src"]} @@ -69,3 +73,6 @@ emhass = [ [project.scripts] emhass = "emhass.command_line:main" + +[project.urls] +Homepage = "https://github.com/davidusb-geek/emhass" \ No newline at end of file diff --git a/src/emhass/machine_learning_forecaster.py b/src/emhass/machine_learning_forecaster.py index b4a36ca3..1863f495 100644 --- a/src/emhass/machine_learning_forecaster.py +++ b/src/emhass/machine_learning_forecaster.py @@ -167,16 +167,22 @@ def fit(self, split_date_delta: Optional[str] = '48h', perform_backtest: Optiona # Using backtesting tool to evaluate the model self.logger.info("Performing simple backtesting of fitted model") start_time = time.time() + cv = TimeSeriesFold( + steps = self.num_lags, + initial_train_size = None, + fixed_train_size = False, + gap = 0, + allow_incomplete_fold = True, + refit = False + ) metric, predictions_backtest = backtesting_forecaster( forecaster = self.forecaster, y = self.data_train[self.var_model], exog = self.data_train.drop(self.var_model, axis=1), - initial_train_size = None, - fixed_train_size = False, - steps = self.num_lags, + cv = cv, metric = MLForecaster.neg_r2_score, - refit = False, - verbose = False + verbose = False, + show_progress = True ) self.logger.info(f"Elapsed backtesting time: {time.time() - start_time}") self.logger.info(f"Backtest R2 score: {-metric}") @@ -277,7 +283,7 @@ def search_space(trial): gap = 0, skip_folds = None, allow_incomplete_fold = True, - refit = False + refit = refit ) self.optimize_results, self.optimize_results_object = bayesian_search_forecaster( forecaster = self.forecaster, @@ -286,11 +292,9 @@ def search_space(trial): cv = cv, search_space = search_space, metric = MLForecaster.neg_r2_score, - refit = refit, n_trials = 10, random_state = 123, - return_best = True, - engine = 'optuna' + return_best = True ) self.logger.info(f"Elapsed time: {time.time() - start_time}") self.is_tuned = True