openstef 3.4.43__tar.gz → 3.4.45__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {openstef-3.4.43 → openstef-3.4.45}/PKG-INFO +1 -1
- {openstef-3.4.43 → openstef-3.4.45}/openstef/data_classes/prediction_job.py +3 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/feature_engineering/apply_features.py +11 -0
- openstef-3.4.45/openstef/feature_engineering/cyclic_features.py +102 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/tasks/train_model.py +32 -1
- {openstef-3.4.43 → openstef-3.4.45}/openstef.egg-info/PKG-INFO +1 -1
- {openstef-3.4.43 → openstef-3.4.45}/openstef.egg-info/SOURCES.txt +1 -0
- {openstef-3.4.43 → openstef-3.4.45}/setup.py +1 -1
- {openstef-3.4.43 → openstef-3.4.45}/LICENSE +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/README.md +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/__init__.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/__main__.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/app_settings.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/data/dazls_model_3.4.24/dazls_stored_3.4.24_baseline_model.z +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/data/dazls_model_3.4.24/dazls_stored_3.4.24_baseline_model.z.license +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/data/dazls_model_3.4.24/dazls_stored_3.4.24_model_card.md +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/data/dazls_model_3.4.24/dazls_stored_3.4.24_model_card.md.license +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/data/dutch_holidays.csv +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/data/dutch_holidays.csv.license +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/data/pv_single_coefs.csv +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/data/pv_single_coefs.csv.license +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/data_classes/__init__.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/data_classes/data_prep.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/data_classes/model_specifications.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/data_classes/split_function.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/enums.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/exceptions.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/feature_engineering/__init__.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/feature_engineering/bidding_zone_to_country_mapping.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/feature_engineering/data_preparation.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/feature_engineering/feature_adder.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/feature_engineering/feature_applicator.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/feature_engineering/general.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/feature_engineering/holiday_features.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/feature_engineering/lag_features.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/feature_engineering/missing_values_transformer.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/feature_engineering/weather_features.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/metrics/__init__.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/metrics/figure.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/metrics/metrics.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/metrics/reporter.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/model/__init__.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/model/basecase.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/model/confidence_interval_applicator.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/model/fallback.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/model/metamodels/__init__.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/model/metamodels/grouped_regressor.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/model/metamodels/missing_values_handler.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/model/model_creator.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/model/objective.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/model/objective_creator.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/model/regressors/__init__.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/model/regressors/arima.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/model/regressors/custom_regressor.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/model/regressors/dazls.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/model/regressors/flatliner.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/model/regressors/lgbm.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/model/regressors/linear.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/model/regressors/linear_quantile.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/model/regressors/regressor.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/model/regressors/xgb.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/model/regressors/xgb_multioutput_quantile.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/model/regressors/xgb_quantile.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/model/serializer.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/model/standard_deviation_generator.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/model_selection/__init__.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/model_selection/model_selection.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/monitoring/__init__.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/monitoring/performance_meter.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/monitoring/teams.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/pipeline/__init__.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/pipeline/create_basecase_forecast.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/pipeline/create_component_forecast.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/pipeline/create_forecast.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/pipeline/optimize_hyperparameters.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/pipeline/train_create_forecast_backtest.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/pipeline/train_model.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/pipeline/utils.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/postprocessing/__init__.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/postprocessing/postprocessing.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/preprocessing/__init__.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/preprocessing/preprocessing.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/settings.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/tasks/__init__.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/tasks/calculate_kpi.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/tasks/create_basecase_forecast.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/tasks/create_components_forecast.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/tasks/create_forecast.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/tasks/create_solar_forecast.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/tasks/create_wind_forecast.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/tasks/optimize_hyperparameters.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/tasks/split_forecast.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/tasks/utils/__init__.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/tasks/utils/dependencies.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/tasks/utils/predictionjobloop.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/tasks/utils/taskcontext.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/validation/__init__.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef/validation/validation.py +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef.egg-info/dependency_links.txt +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef.egg-info/requires.txt +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/openstef.egg-info/top_level.txt +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/pyproject.toml +0 -0
- {openstef-3.4.43 → openstef-3.4.45}/setup.cfg +0 -0
@@ -79,6 +79,9 @@ class PredictionJobDataClass(BaseModel):
|
|
79
79
|
"""Minimum length (in rows) of the forecast input for making a regular forecast."""
|
80
80
|
flatliner_threshold_minutes: int = 1440
|
81
81
|
"""Number of minutes that the load has to be constant to detect a flatliner. """
|
82
|
+
data_balancing_ratio: Optional[float] = None
|
83
|
+
"""If data balancing is enabled, the data will be balanced with data from 1 year
|
84
|
+
ago in the future."""
|
82
85
|
depends_on: Optional[list[Union[int, str]]]
|
83
86
|
"""Link to another prediction job on which this prediction job might depend."""
|
84
87
|
sid: Optional[str]
|
@@ -28,6 +28,11 @@ from openstef.feature_engineering.weather_features import (
|
|
28
28
|
add_humidity_features,
|
29
29
|
)
|
30
30
|
|
31
|
+
from openstef.feature_engineering.cyclic_features import (
|
32
|
+
add_seasonal_cyclic_features,
|
33
|
+
add_time_cyclic_features,
|
34
|
+
)
|
35
|
+
|
31
36
|
|
32
37
|
def apply_features(
|
33
38
|
data: pd.DataFrame,
|
@@ -113,5 +118,11 @@ def apply_features(
|
|
113
118
|
# Add solar features; when pj is unavailable a default location is used.
|
114
119
|
data = add_additional_solar_features(data, pj, feature_names)
|
115
120
|
|
121
|
+
# Adds cyclical features to capture seasonal and periodic patterns in time-based data.
|
122
|
+
data = add_seasonal_cyclic_features(data)
|
123
|
+
|
124
|
+
# Adds polar time features (sine and cosine) to capture periodic patterns based on the timestamp index.
|
125
|
+
data = add_time_cyclic_features(data)
|
126
|
+
|
116
127
|
# Return dataframe including all requested features
|
117
128
|
return data
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# SPDX-FileCopyrightText: 2017-2023 Contributors to the OpenSTEF project <korte.termijn.prognoses@alliander.com> # noqa E501>
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MPL-2.0
|
4
|
+
|
5
|
+
# Module for adding temporal cyclic features to time-based data for capturing seasonality and periodic patterns.
|
6
|
+
# Features include yearly, weekly, and monthly seasonality, as well as time-of-day periodicity.
|
7
|
+
|
8
|
+
|
9
|
+
import numpy as np
|
10
|
+
import pandas as pd
|
11
|
+
|
12
|
+
import structlog
|
13
|
+
import logging
|
14
|
+
|
15
|
+
from openstef.settings import Settings
|
16
|
+
|
17
|
+
structlog.configure(
|
18
|
+
wrapper_class=structlog.make_filtering_bound_logger(
|
19
|
+
logging.getLevelName(Settings.log_level)
|
20
|
+
)
|
21
|
+
)
|
22
|
+
logger = structlog.get_logger(__name__)
|
23
|
+
|
24
|
+
|
25
|
+
NUM_SECONDS_IN_A_DAY = 24 * 60 * 60
|
26
|
+
|
27
|
+
|
28
|
+
def add_time_cyclic_features(
|
29
|
+
data: pd.DataFrame,
|
30
|
+
) -> pd.DataFrame:
|
31
|
+
"""Adds time of the day features cyclically encoded using sine and cosine to the input data.
|
32
|
+
|
33
|
+
Args:
|
34
|
+
data: Dataframe indexed by datetime.
|
35
|
+
|
36
|
+
Returns:
|
37
|
+
DataFrame that is the same as input dataframe with extra columns for the added time of the day features.
|
38
|
+
"""
|
39
|
+
# Ensure the index is a DatetimeIndex
|
40
|
+
if not isinstance(data.index, pd.DatetimeIndex):
|
41
|
+
raise ValueError("Index should be a pandas DatetimeIndex")
|
42
|
+
|
43
|
+
# Make a copy of the DataFrame to avoid modifying the original
|
44
|
+
data = data.copy()
|
45
|
+
|
46
|
+
second_of_the_day = (
|
47
|
+
data.index.second + data.index.minute * 60 + data.index.hour * 60 * 60
|
48
|
+
)
|
49
|
+
period_of_the_day = 2 * np.pi * second_of_the_day / NUM_SECONDS_IN_A_DAY
|
50
|
+
|
51
|
+
data["time0fday_sine"] = np.sin(period_of_the_day)
|
52
|
+
data["time0fday_cosine"] = np.cos(period_of_the_day)
|
53
|
+
|
54
|
+
return data
|
55
|
+
|
56
|
+
|
57
|
+
def add_seasonal_cyclic_features(
|
58
|
+
data: pd.DataFrame, compute_features: list = None
|
59
|
+
) -> pd.DataFrame:
|
60
|
+
"""Adds cyclical features to capture seasonal and periodic patterns in time-based data.
|
61
|
+
|
62
|
+
Args:
|
63
|
+
- data (pd.DataFrame): DataFrame with a DatetimeIndex.
|
64
|
+
- compute_features (list): Optional. List of features to compute. Options are:
|
65
|
+
['season', 'dayofweek', 'month']. Default is all features.
|
66
|
+
|
67
|
+
Returns:
|
68
|
+
- pd.DataFrame: DataFrame with added cyclical features.
|
69
|
+
|
70
|
+
Example:
|
71
|
+
>>> data = pd.DataFrame(index=pd.date_range(start='2023-01-01', periods=365, freq='D'))
|
72
|
+
>>> data_with_features = add_cyclical_features(data)
|
73
|
+
>>> print(data_with_features.head())
|
74
|
+
"""
|
75
|
+
# Ensure the index is a DatetimeIndex
|
76
|
+
if not isinstance(data.index, pd.DatetimeIndex):
|
77
|
+
raise ValueError("The DataFrame index must be a DatetimeIndex.")
|
78
|
+
|
79
|
+
# Make a copy of the DataFrame to avoid modifying the original
|
80
|
+
data = data.copy()
|
81
|
+
|
82
|
+
# Default to all features if none specified
|
83
|
+
compute_features = compute_features or ["season", "dayofweek", "month"]
|
84
|
+
|
85
|
+
days_in_year = 365.25 # Account for leap years
|
86
|
+
|
87
|
+
# Add seasonality features (day of year)
|
88
|
+
if "season" in compute_features:
|
89
|
+
data["season_sine"] = np.sin(2 * np.pi * data.index.dayofyear / days_in_year)
|
90
|
+
data["season_cosine"] = np.cos(2 * np.pi * data.index.dayofyear / days_in_year)
|
91
|
+
|
92
|
+
# Add weekly features (day of the week)
|
93
|
+
if "dayofweek" in compute_features:
|
94
|
+
data["day0fweek_sine"] = np.sin(2 * np.pi * data.index.day_of_week / 7)
|
95
|
+
data["day0fweek_cosine"] = np.cos(2 * np.pi * data.index.day_of_week / 7)
|
96
|
+
|
97
|
+
# Add monthly features (month of the year)
|
98
|
+
if "month" in compute_features:
|
99
|
+
data["month_sine"] = np.sin(2 * np.pi * data.index.month / 12)
|
100
|
+
data["month_cosine"] = np.cos(2 * np.pi * data.index.month / 12)
|
101
|
+
|
102
|
+
return data
|
@@ -22,6 +22,8 @@ Example:
|
|
22
22
|
from datetime import datetime, timedelta
|
23
23
|
from pathlib import Path
|
24
24
|
|
25
|
+
import pandas as pd
|
26
|
+
|
25
27
|
from openstef.data_classes.prediction_job import PredictionJobDataClass
|
26
28
|
from openstef.enums import ModelType, PipelineType
|
27
29
|
from openstef.exceptions import (
|
@@ -114,10 +116,16 @@ def train_model_task(
|
|
114
116
|
return
|
115
117
|
|
116
118
|
# Define start and end of the training input data
|
119
|
+
training_period_days_to_fetch = (
|
120
|
+
TRAINING_PERIOD_DAYS
|
121
|
+
if pj.data_balancing_ratio is None
|
122
|
+
else int(pj.data_balancing_ratio * TRAINING_PERIOD_DAYS)
|
123
|
+
)
|
124
|
+
|
117
125
|
if datetime_end is None:
|
118
126
|
datetime_end = datetime.utcnow()
|
119
127
|
if datetime_start is None:
|
120
|
-
datetime_start = datetime_end - timedelta(days=
|
128
|
+
datetime_start = datetime_end - timedelta(days=training_period_days_to_fetch)
|
121
129
|
|
122
130
|
# Get training input data from database
|
123
131
|
input_data = context.database.get_model_input(
|
@@ -127,6 +135,29 @@ def train_model_task(
|
|
127
135
|
datetime_end=datetime_end,
|
128
136
|
)
|
129
137
|
|
138
|
+
# If data balancing is enabled, fetch data from 1 year ago and combine it with the
|
139
|
+
# current data
|
140
|
+
if pj.data_balancing_ratio is not None:
|
141
|
+
# Because the data is from the past, we can use the data from the "future"
|
142
|
+
balanced_datetime_start = datetime_end - timedelta(days=365)
|
143
|
+
balanced_datetime_end = balanced_datetime_start + timedelta(
|
144
|
+
days=training_period_days_to_fetch
|
145
|
+
)
|
146
|
+
|
147
|
+
balanced_input_data = context.database.get_model_input(
|
148
|
+
pid=pj["id"],
|
149
|
+
location=[pj["lat"], pj["lon"]],
|
150
|
+
datetime_start=balanced_datetime_start,
|
151
|
+
datetime_end=balanced_datetime_end,
|
152
|
+
)
|
153
|
+
|
154
|
+
input_data = pd.concat(
|
155
|
+
[
|
156
|
+
balanced_input_data,
|
157
|
+
input_data,
|
158
|
+
]
|
159
|
+
)
|
160
|
+
|
130
161
|
context.perf_meter.checkpoint("Retrieved timeseries input")
|
131
162
|
|
132
163
|
# Excecute the model training pipeline
|
@@ -30,6 +30,7 @@ openstef/data_classes/split_function.py
|
|
30
30
|
openstef/feature_engineering/__init__.py
|
31
31
|
openstef/feature_engineering/apply_features.py
|
32
32
|
openstef/feature_engineering/bidding_zone_to_country_mapping.py
|
33
|
+
openstef/feature_engineering/cyclic_features.py
|
33
34
|
openstef/feature_engineering/data_preparation.py
|
34
35
|
openstef/feature_engineering/feature_adder.py
|
35
36
|
openstef/feature_engineering/feature_applicator.py
|
@@ -29,7 +29,7 @@ def read_long_description_from_readme():
|
|
29
29
|
|
30
30
|
setup(
|
31
31
|
name="openstef",
|
32
|
-
version="3.4.
|
32
|
+
version="3.4.45",
|
33
33
|
packages=find_packages(include=["openstef", "openstef.*"]),
|
34
34
|
description="Open short term energy forecaster",
|
35
35
|
long_description=read_long_description_from_readme(),
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{openstef-3.4.43 → openstef-3.4.45}/openstef/feature_engineering/bidding_zone_to_country_mapping.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{openstef-3.4.43 → openstef-3.4.45}/openstef/feature_engineering/missing_values_transformer.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|