From 71d3f79a75a50ee4f7c92efb83970bf1dfd8ed09 Mon Sep 17 00:00:00 2001 From: rdhakan13 Date: Wed, 25 Jun 2025 20:32:31 +0100 Subject: [PATCH 1/6] added rmspe function --- src/common/stats.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/common/stats.py b/src/common/stats.py index 6799230..a42be89 100644 --- a/src/common/stats.py +++ b/src/common/stats.py @@ -1,5 +1,6 @@ import logging import pandas as pd +import numpy as np from statsmodels.tsa.stattools import adfuller, grangercausalitytests from arch.unitroot import PhillipsPerron from typing import Any @@ -109,3 +110,34 @@ def grangers_causality_test( } return results + +def root_mean_squared_percentage_error(y_true:Any, y_pred: Any) -> float: + """ + Calculate the Root Mean Squared Percentage Error (RMSPE) between actual and predicted values. + + Parameters: + y_true (pd.Series, np.ndarray, pd.DataFrame): Actual values. + y_pred (pd.Series, np.ndarray, pd.DataFrame): Predicted values. + + Returns: + float: The RMSPE value. + """ + if not isinstance(y_true, (pd.Series, np.ndarray, pd.DataFrame)): + raise TypeError("Actual values must be a pandas Series, numpy array, or DataFrame.") + if not isinstance(y_pred, (pd.Series, np.ndarray, pd.DataFrame)): + raise TypeError("Predicted values must be a pandas Series, numpy array, or DataFrame.") + if len(y_true) != len(y_pred): + raise ValueError("Actual and predicted series must have the same length.") + + y_true = np.asarray(y_true) + y_pred = np.asarray(y_pred) + + if np.any(y_true == 0): + raise ValueError("Actual values must not contain zero to avoid division by zero in percentage error calculation.") + if np.any(np.isnan(y_true)) or np.any(np.isnan(y_pred)): + raise ValueError("Actual and predicted values must not contain NaN values.") + + percentage_error = (y_true - y_pred) / y_true + + rmspe = np.sqrt(np.mean(percentage_error ** 2)) * 100 + return rmspe From 8b3ae4029964c5e3256821df4f6e567c34179889 Mon Sep 17 00:00:00 2001 From: rdhakan13 Date: Wed, 25 Jun 2025 20:34:11 +0100 Subject: [PATCH 2/6] ability to switch between numpy and xarray --- src/preprocessing/data_loader.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/preprocessing/data_loader.py b/src/preprocessing/data_loader.py index c45dfba..9ab53a6 100644 --- a/src/preprocessing/data_loader.py +++ b/src/preprocessing/data_loader.py @@ -275,7 +275,7 @@ def split_data( logger.error("Please set the train data first.") raise ValueError("Please set the train data first.") - def generate_X_y_tensors(self, df:pd.DataFrame, target_col:str="ETH_D_AvgPrc", lags:int=5, horizon:int=7, data_split:Optional[str]=None, format:str="xarray") -> tuple[np.ndarray, np.ndarray]: + def generate_X_y_tensors(self, df:pd.DataFrame, target_col:str="ETH_D_AvgPrc", lags:int=5, horizon:int=7, data_split:Optional[str]=None, tensor_format:str="xarray") -> tuple[np.ndarray, np.ndarray]: """ Generate X and y tensors for time series forecasting. @@ -341,9 +341,9 @@ def generate_X_y_tensors(self, df:pd.DataFrame, target_col:str="ETH_D_AvgPrc", l name="X" ) - if format == "xarray": + if tensor_format == "xarray": return y_xr, X_xr - elif format == "numpy": + elif tensor_format == "numpy": return np.array(y), np.array(X) else: logger.error("Invalid format specified. Use 'xarray' or 'numpy'.") @@ -356,4 +356,4 @@ def get_scalers(self) -> tuple[Optional[Any], Optional[Any]]: Returns: tuple: X scaler and y scaler. """ - return self.x_scaler, self.y_scaler \ No newline at end of file + return self.y_scaler, self.x_scaler \ No newline at end of file From 73b837e236d0575db1cfa21c10fa8c4810dd1f8a Mon Sep 17 00:00:00 2001 From: rdhakan13 Date: Thu, 10 Jul 2025 23:12:34 +0100 Subject: [PATCH 3/6] adding security step --- .github/workflows/unit-tests.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index adbc2be..31711d3 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -28,6 +28,23 @@ on: - poetry.lock jobs: + reject-ec2: + if: github.event_name == 'push' + runs-on: ubuntu-latest + steps: + - name: Check if pushed by EC2 Deploy Key + run: | + AUTHOR_NAME=$(jq -r .pusher.name "$GITHUB_EVENT_PATH") + AUTHOR_EMAIL=$(jq -r .pusher.email "$GITHUB_EVENT_PATH") + + echo "Commit by $AUTHOR_NAME <$AUTHOR_EMAIL>" + + if [[ "$AUTHOR_NAME" == "ec2-deploy-bot" ]] || [[ "$AUTHOR_EMAIL" == "ec2@myinfra.local" ]]; then + echo "Blocked deploy key push to main." + exit 1 + fi + + echo "Push allowed." unit-tests: runs-on: ubuntu-latest env: From 88b79835fdac9ab0e32a2817f1562af06dc66356 Mon Sep 17 00:00:00 2001 From: rdhakan13 Date: Thu, 10 Jul 2025 23:20:27 +0100 Subject: [PATCH 4/6] one more security change --- .github/workflows/unit-tests.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 31711d3..49f72a7 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -4,6 +4,7 @@ on: push: branches: - main + - ec2-experiments paths: - configs/** - src/** @@ -29,7 +30,7 @@ on: jobs: reject-ec2: - if: github.event_name == 'push' + if: github.event_name == 'push' && github.ref != 'refs/heads/ec2-experiments' runs-on: ubuntu-latest steps: - name: Check if pushed by EC2 Deploy Key @@ -46,6 +47,7 @@ jobs: echo "Push allowed." unit-tests: + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest env: PYTHONPATH: ${{ github.workspace }}/src From 3509a9e6d5ee7f8c2aaaaea0eee119239a7392e5 Mon Sep 17 00:00:00 2001 From: rdhakan13 Date: Thu, 10 Jul 2025 23:23:00 +0100 Subject: [PATCH 5/6] check --- .github/workflows/unit-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 49f72a7..59caeaf 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -47,7 +47,7 @@ jobs: echo "Push allowed." unit-tests: - if: github.ref == 'refs/heads/main' + if: (github.event_name == 'push' || github.event_name == 'pull_request') && github.ref == 'refs/heads/main' runs-on: ubuntu-latest env: PYTHONPATH: ${{ github.workspace }}/src From db9d78f773eb015a737e41a428d236a25f991e14 Mon Sep 17 00:00:00 2001 From: rdhakan13 Date: Thu, 10 Jul 2025 23:23:46 +0100 Subject: [PATCH 6/6] anotther --- .github/workflows/unit-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 59caeaf..89bbd01 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -47,7 +47,7 @@ jobs: echo "Push allowed." unit-tests: - if: (github.event_name == 'push' || github.event_name == 'pull_request') && github.ref == 'refs/heads/main' + # if: (github.event_name == 'push' || github.event_name == 'pull_request') && github.ref == 'refs/heads/main' runs-on: ubuntu-latest env: PYTHONPATH: ${{ github.workspace }}/src