eb-features 0.2.4__tar.gz → 0.2.7__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.
Files changed (24) hide show
  1. {eb_features-0.2.4 → eb_features-0.2.7}/LICENSE +1 -1
  2. {eb_features-0.2.4/src/eb_features.egg-info → eb_features-0.2.7}/PKG-INFO +27 -36
  3. eb_features-0.2.7/README.md +83 -0
  4. {eb_features-0.2.4 → eb_features-0.2.7}/pyproject.toml +18 -5
  5. eb_features-0.2.7/src/eb_features/__init__.py +46 -0
  6. {eb_features-0.2.4 → eb_features-0.2.7}/src/eb_features/panel/__init__.py +25 -3
  7. {eb_features-0.2.4 → eb_features-0.2.7}/src/eb_features/panel/calendar.py +44 -25
  8. {eb_features-0.2.4 → eb_features-0.2.7}/src/eb_features/panel/config.py +20 -13
  9. {eb_features-0.2.4 → eb_features-0.2.7}/src/eb_features/panel/constants.py +11 -15
  10. {eb_features-0.2.4 → eb_features-0.2.7}/src/eb_features/panel/encoders.py +5 -5
  11. eb_features-0.2.7/src/eb_features/panel/engineering.py +250 -0
  12. {eb_features-0.2.4 → eb_features-0.2.7}/src/eb_features/panel/lags.py +31 -11
  13. {eb_features-0.2.4 → eb_features-0.2.7}/src/eb_features/panel/rolling.py +59 -39
  14. {eb_features-0.2.4 → eb_features-0.2.7}/src/eb_features/panel/validation.py +65 -11
  15. eb_features-0.2.7/src/eb_features/py.typed +0 -0
  16. {eb_features-0.2.4 → eb_features-0.2.7/src/eb_features.egg-info}/PKG-INFO +27 -36
  17. {eb_features-0.2.4 → eb_features-0.2.7}/src/eb_features.egg-info/SOURCES.txt +1 -0
  18. {eb_features-0.2.4 → eb_features-0.2.7}/src/eb_features.egg-info/requires.txt +7 -0
  19. eb_features-0.2.4/README.md +0 -96
  20. eb_features-0.2.4/src/eb_features/__init__.py +0 -20
  21. eb_features-0.2.4/src/eb_features/panel/engineering.py +0 -304
  22. {eb_features-0.2.4 → eb_features-0.2.7}/setup.cfg +0 -0
  23. {eb_features-0.2.4 → eb_features-0.2.7}/src/eb_features.egg-info/dependency_links.txt +0 -0
  24. {eb_features-0.2.4 → eb_features-0.2.7}/src/eb_features.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  BSD 3-Clause License
2
2
 
3
- Copyright (c) 2025, Kyle Corrie
3
+ Copyright (c) 2026, Kyle Corrie
4
4
 
5
5
  Redistribution and use in source and binary forms, with or without
6
6
  modification, are permitted provided that the following conditions are met:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: eb-features
3
- Version: 0.2.4
3
+ Version: 0.2.7
4
4
  Summary: Feature engineering utilities for panel time-series data in the Electric Barometer ecosystem.
5
5
  Author-email: "Kyle Corrie (Economistician)" <kcorrie@economistician.com>
6
6
  License-Expression: BSD-3-Clause
@@ -9,25 +9,29 @@ Project-URL: Repository, https://github.com/Economistician/eb-features
9
9
  Project-URL: Issues, https://github.com/Economistician/eb-features/issues
10
10
  Project-URL: Documentation, https://economistician.github.io/eb-docs/
11
11
  Keywords: forecasting,features,feature-engineering,time-series,panel-data,operations-research
12
- Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Development Status :: 5 - Production/Stable
13
13
  Classifier: Intended Audience :: Science/Research
14
14
  Classifier: Intended Audience :: Developers
15
15
  Classifier: Programming Language :: Python :: 3
16
16
  Classifier: Programming Language :: Python :: 3 :: Only
17
- Classifier: Programming Language :: Python :: 3.10
18
17
  Classifier: Programming Language :: Python :: 3.11
19
18
  Classifier: Programming Language :: Python :: 3.12
20
19
  Classifier: Programming Language :: Python :: 3.13
21
20
  Classifier: Operating System :: OS Independent
22
21
  Classifier: Topic :: Scientific/Engineering
23
- Requires-Python: >=3.10
22
+ Requires-Python: >=3.11
24
23
  Description-Content-Type: text/markdown
25
24
  License-File: LICENSE
26
25
  Requires-Dist: numpy>=1.24
27
26
  Requires-Dist: pandas>=2.0
27
+ Provides-Extra: test
28
+ Requires-Dist: pytest>=8.0; extra == "test"
28
29
  Provides-Extra: dev
29
30
  Requires-Dist: pytest>=8.0; extra == "dev"
30
31
  Requires-Dist: pytest-cov>=5.0; extra == "dev"
32
+ Provides-Extra: all
33
+ Requires-Dist: pytest>=8.0; extra == "all"
34
+ Requires-Dist: pytest-cov>=5.0; extra == "all"
31
35
  Dynamic: license-file
32
36
 
33
37
  # Electric Barometer · Features (`eb-features`)
@@ -43,19 +47,7 @@ Feature engineering primitives for panel-based forecasting systems, designed to
43
47
 
44
48
  ## Overview
45
49
 
46
- `eb-features` is a modular feature engineering library for panel-based forecasting systems. It provides reusable, deterministic transformations for constructing time-aware features across entities observed over time.
47
-
48
- Within the Electric Barometer ecosystem, `eb-features` serves as the upstream feature construction layer, producing standardized inputs for downstream evaluation and metric components. While designed to integrate seamlessly with Electric Barometer, the package remains framework-agnostic and can be used independently in other forecasting workflows.
49
-
50
- ---
51
-
52
- ## Role in the Electric Barometer Ecosystem
53
-
54
- `eb-features` defines the feature engineering primitives used throughout the Electric Barometer ecosystem. It is responsible for constructing deterministic, panel-aware input features—such as lags, rolling aggregations, and calendar encodings—that serve as the foundational inputs to forecasting and evaluation workflows.
55
-
56
- This package focuses exclusively on feature construction and validation. It does not perform model training, forecast generation, metric evaluation, or decision logic. Those responsibilities are handled by downstream layers in the ecosystem that consume engineered features for modeling, selection, and operational assessment.
57
-
58
- By separating feature semantics from modeling and evaluation concerns, `eb-features` provides a stable, reusable foundation that ensures consistency and reproducibility across forecasting pipelines operating on heterogeneous panel data.
50
+ `eb-features` builds deterministic, panel-aware forecasting features (lags, rolling aggregates, calendar encodings) with explicit entity and time boundaries. It does not train models or evaluate forecasts.
59
51
 
60
52
  ---
61
53
 
@@ -67,7 +59,7 @@ By separating feature semantics from modeling and evaluation concerns, `eb-featu
67
59
  pip install eb-features
68
60
  ```
69
61
 
70
- The package supports Python 3.10 and later.
62
+ The package supports Python 3.11 and later.
71
63
 
72
64
  ---
73
65
 
@@ -87,34 +79,33 @@ The example below shows how to construct lagged and rolling features for panel d
87
79
 
88
80
  ```python
89
81
  import pandas as pd
90
- from eb_features.panel.lags import add_lag_features
91
- from eb_features.panel.rolling import add_rolling_features
82
+ from eb_features import add_lag_features, add_rolling_features
92
83
 
93
- # Example panel data
94
84
  df = pd.DataFrame({
95
- "entity_id": ["A", "A", "A", "B", "B"],
96
- "date": pd.date_range("2024-01-01", periods=5, freq="D"),
97
- "y": [10, 12, 11, 7, 9],
85
+ "entity_id": ["A", "A", "A", "A", "B", "B", "B", "B"],
86
+ "date": pd.to_datetime(
87
+ ["2024-01-01", "2024-01-02", "2024-01-03", "2024-01-04"] * 2
88
+ ),
89
+ "y": [10, 12, 11, 13, 7, 9, 8, 10],
98
90
  })
91
+ df = df.sort_values(["entity_id", "date"], kind="mergesort")
99
92
 
100
- # Add lagged features
101
- df = add_lag_features(
93
+ df, lag_cols = add_lag_features(
102
94
  df,
103
- value_col="y",
104
- lags=[1, 2],
105
95
  entity_col="entity_id",
106
- time_col="date",
96
+ target_col="y",
97
+ lag_steps=[1, 2],
107
98
  )
108
99
 
109
- # Add rolling features
110
- df = add_rolling_features(
100
+ df, roll_cols = add_rolling_features(
111
101
  df,
112
- value_col="y",
113
- windows=[3],
114
102
  entity_col="entity_id",
115
- time_col="date",
103
+ target_col="y",
104
+ rolling_windows=[3],
105
+ rolling_stats=["mean"],
116
106
  )
117
107
 
108
+ print(lag_cols, roll_cols)
118
109
  print(df)
119
110
  ```
120
111
 
@@ -122,7 +113,7 @@ print(df)
122
113
 
123
114
  ## License
124
115
 
125
- BSD 3-Clause License.
126
- © 2025 Kyle Corrie.
116
+ BSD 3-Clause License.
117
+ © 2026 Kyle Corrie.
127
118
 
128
119
  <!-- Trusted publishing verification -->
@@ -0,0 +1,83 @@
1
+ # Electric Barometer · Features (`eb-features`)
2
+
3
+ [![CI](https://github.com/Economistician/eb-features/actions/workflows/ci.yml/badge.svg)](https://github.com/Economistician/eb-features/actions/workflows/ci.yml)
4
+ ![License: BSD-3-Clause](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)
5
+ ![Python Versions](https://img.shields.io/pypi/pyversions/eb-features)
6
+ ![PyPI](https://img.shields.io/pypi/v/eb-features)
7
+
8
+ Feature engineering primitives for panel-based forecasting systems, designed to integrate seamlessly with the Electric Barometer ecosystem.
9
+
10
+ ---
11
+
12
+ ## Overview
13
+
14
+ `eb-features` builds deterministic, panel-aware forecasting features (lags, rolling aggregates, calendar encodings) with explicit entity and time boundaries. It does not train models or evaluate forecasts.
15
+
16
+ ---
17
+
18
+ ## Installation
19
+
20
+ `eb-features` is distributed as a standard Python package.
21
+
22
+ ```bash
23
+ pip install eb-features
24
+ ```
25
+
26
+ The package supports Python 3.11 and later.
27
+
28
+ ---
29
+
30
+ ## Core Concepts
31
+
32
+ - **Panel-aware feature construction** — Features are constructed with explicit awareness of entity boundaries and temporal ordering, ensuring correctness in multi-entity forecasting settings.
33
+ - **Deterministic transformations** — Feature generation is designed to be reproducible and free of stochastic behavior, supporting auditability and consistent downstream evaluation.
34
+ - **Temporal causality** — All features respect time directionality, preventing information leakage from future observations into historical feature sets.
35
+ - **Rolling and lag semantics** — Common forecasting features such as lags and rolling aggregates are treated as first-class primitives with clear, well-defined behavior.
36
+ - **Validation by construction** — Feature pipelines include explicit checks and constraints to ensure structural validity before model training or evaluation.
37
+
38
+ ---
39
+
40
+ ## Minimal Example
41
+
42
+ The example below shows how to construct lagged and rolling features for panel data while preserving entity boundaries and temporal ordering.
43
+
44
+ ```python
45
+ import pandas as pd
46
+ from eb_features import add_lag_features, add_rolling_features
47
+
48
+ df = pd.DataFrame({
49
+ "entity_id": ["A", "A", "A", "A", "B", "B", "B", "B"],
50
+ "date": pd.to_datetime(
51
+ ["2024-01-01", "2024-01-02", "2024-01-03", "2024-01-04"] * 2
52
+ ),
53
+ "y": [10, 12, 11, 13, 7, 9, 8, 10],
54
+ })
55
+ df = df.sort_values(["entity_id", "date"], kind="mergesort")
56
+
57
+ df, lag_cols = add_lag_features(
58
+ df,
59
+ entity_col="entity_id",
60
+ target_col="y",
61
+ lag_steps=[1, 2],
62
+ )
63
+
64
+ df, roll_cols = add_rolling_features(
65
+ df,
66
+ entity_col="entity_id",
67
+ target_col="y",
68
+ rolling_windows=[3],
69
+ rolling_stats=["mean"],
70
+ )
71
+
72
+ print(lag_cols, roll_cols)
73
+ print(df)
74
+ ```
75
+
76
+ ---
77
+
78
+ ## License
79
+
80
+ BSD 3-Clause License.
81
+ © 2026 Kyle Corrie.
82
+
83
+ <!-- Trusted publishing verification -->
@@ -3,10 +3,10 @@
3
3
  ######################################
4
4
  [project]
5
5
  name = "eb-features"
6
- version = "0.2.4"
6
+ version = "0.2.7"
7
7
  description = "Feature engineering utilities for panel time-series data in the Electric Barometer ecosystem."
8
8
  readme = "README.md"
9
- requires-python = ">=3.10"
9
+ requires-python = ">=3.11"
10
10
  license = "BSD-3-Clause"
11
11
  license-files = ["LICENSE*"]
12
12
 
@@ -17,12 +17,11 @@ authors = [
17
17
  keywords = ["forecasting", "features", "feature-engineering", "time-series", "panel-data", "operations-research"]
18
18
 
19
19
  classifiers = [
20
- "Development Status :: 3 - Alpha",
20
+ "Development Status :: 5 - Production/Stable",
21
21
  "Intended Audience :: Science/Research",
22
22
  "Intended Audience :: Developers",
23
23
  "Programming Language :: Python :: 3",
24
24
  "Programming Language :: Python :: 3 :: Only",
25
- "Programming Language :: Python :: 3.10",
26
25
  "Programming Language :: Python :: 3.11",
27
26
  "Programming Language :: Python :: 3.12",
28
27
  "Programming Language :: Python :: 3.13",
@@ -52,11 +51,22 @@ Documentation = "https://economistician.github.io/eb-docs/"
52
51
  ######################################
53
52
  [project.optional-dependencies]
54
53
 
54
+ test = [
55
+ "pytest>=8.0",
56
+ ]
57
+
55
58
  dev = [
56
59
  "pytest>=8.0",
57
60
  "pytest-cov>=5.0",
58
61
  ]
59
62
 
63
+ # Standardized anchor to satisfy the "extras: all" CI contract.
64
+ # Aggregates dev and test dependencies for the Hub runner.
65
+ all = [
66
+ "pytest>=8.0",
67
+ "pytest-cov>=5.0",
68
+ ]
69
+
60
70
  ######################################
61
71
  # Build system
62
72
  ######################################
@@ -73,10 +83,13 @@ package-dir = {"" = "src"}
73
83
  [tool.setuptools.packages.find]
74
84
  where = ["src"]
75
85
 
86
+ [tool.setuptools.package-data]
87
+ eb_features = ["py.typed"]
88
+
76
89
  ######################################
77
90
  # Pytest configuration
78
91
  ######################################
79
92
  [tool.pytest.ini_options]
80
93
  pythonpath = ["src"]
81
94
  addopts = "-ra"
82
- testpaths = ["tests"]
95
+ testpaths = ["tests"]
@@ -0,0 +1,46 @@
1
+ """
2
+ Feature engineering utilities for the Electric Barometer ecosystem.
3
+
4
+ This package provides modular, domain-agnostic feature engineering components
5
+ used across forecasting, evaluation, and operational modeling workflows.
6
+
7
+ The recommended import path is the package root, for example
8
+ ``from eb_features import FeatureConfig, FeatureEngineer, add_lag_features``.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from importlib.metadata import PackageNotFoundError, version
14
+
15
+ from eb_features.panel.calendar import add_calendar_features
16
+ from eb_features.panel.engineering import FeatureConfig, FeatureEngineer
17
+ from eb_features.panel.lags import add_lag_features
18
+ from eb_features.panel.rolling import add_rolling_features
19
+
20
+
21
+ def _resolve_version() -> str:
22
+ """
23
+ Resolve the installed package version.
24
+
25
+ Returns
26
+ -------
27
+ str
28
+ Installed version string. If the package is not installed (e.g., running
29
+ from source without installation), returns ``"0.0.0"``.
30
+ """
31
+ try:
32
+ return version("eb-features")
33
+ except PackageNotFoundError:
34
+ return "0.0.0"
35
+
36
+
37
+ __version__ = _resolve_version()
38
+
39
+ __all__ = [
40
+ "FeatureConfig",
41
+ "FeatureEngineer",
42
+ "__version__",
43
+ "add_calendar_features",
44
+ "add_lag_features",
45
+ "add_rolling_features",
46
+ ]
@@ -1,5 +1,3 @@
1
- from __future__ import annotations
2
-
3
1
  """
4
2
  Panel time-series feature engineering.
5
3
 
@@ -34,9 +32,33 @@ See Also
34
32
  - [`eb_features.panel.engineering.FeatureConfig`][eb_features.panel.engineering.FeatureConfig]
35
33
  """
36
34
 
35
+ from __future__ import annotations
36
+
37
+ from eb_features.panel.calendar import add_calendar_features
38
+ from eb_features.panel.constants import (
39
+ ALLOWED_CALENDAR_FEATURES,
40
+ ALLOWED_ROLLING_STATS,
41
+ DEFAULT_CALENDAR_FEATURES,
42
+ DEFAULT_LAG_STEPS,
43
+ DEFAULT_ROLLING_STATS,
44
+ DEFAULT_ROLLING_WINDOWS,
45
+ )
46
+ from eb_features.panel.encoders import encode_non_numeric_as_category_codes
37
47
  from eb_features.panel.engineering import FeatureConfig, FeatureEngineer
48
+ from eb_features.panel.lags import add_lag_features
49
+ from eb_features.panel.rolling import add_rolling_features
38
50
 
39
51
  __all__ = [
52
+ "ALLOWED_CALENDAR_FEATURES",
53
+ "ALLOWED_ROLLING_STATS",
54
+ "DEFAULT_CALENDAR_FEATURES",
55
+ "DEFAULT_LAG_STEPS",
56
+ "DEFAULT_ROLLING_STATS",
57
+ "DEFAULT_ROLLING_WINDOWS",
40
58
  "FeatureConfig",
41
59
  "FeatureEngineer",
42
- ]
60
+ "add_calendar_features",
61
+ "add_lag_features",
62
+ "add_rolling_features",
63
+ "encode_non_numeric_as_category_codes",
64
+ ]
@@ -1,10 +1,8 @@
1
- from __future__ import annotations
2
-
3
1
  r"""
4
2
  Calendar and time-derived features for panel time series.
5
3
 
6
4
  This module provides utilities to derive calendar/time features from a timestamp column.
7
- It is designed for *panel* time-series data (entity × timestamp) and is typically used
5
+ It is designed for *panel* time-series data (entity-by-timestamp) and is typically used
8
6
  as part of a broader feature engineering pipeline.
9
7
 
10
8
  Supported base calendar features
@@ -47,7 +45,9 @@ Notes
47
45
  representation as stored in the column.
48
46
  """
49
47
 
50
- from typing import Iterable, List, Sequence, Tuple
48
+ from __future__ import annotations
49
+
50
+ from collections.abc import Iterable, Sequence
51
51
 
52
52
  import numpy as np
53
53
  import pandas as pd
@@ -58,6 +58,7 @@ from eb_features.panel.constants import (
58
58
  HOUR_PERIOD,
59
59
  WEEKEND_DAYS,
60
60
  )
61
+ from eb_features.panel.validation import ensure_entity_time_order, infer_panel_entity_col
61
62
 
62
63
 
63
64
  def add_calendar_features(
@@ -66,7 +67,7 @@ def add_calendar_features(
66
67
  timestamp_col: str,
67
68
  calendar_features: Sequence[str],
68
69
  use_cyclical_time: bool = True,
69
- ) -> Tuple[pd.DataFrame, List[str], List[str]]:
70
+ ) -> tuple[pd.DataFrame, list[str], list[str]]:
70
71
  r"""
71
72
  Add calendar/time-derived features to a DataFrame.
72
73
 
@@ -114,34 +115,55 @@ def add_calendar_features(
114
115
  if timestamp_col not in df.columns:
115
116
  raise KeyError(f"Timestamp column {timestamp_col!r} not found in DataFrame.")
116
117
 
118
+ df_out = ensure_entity_time_order(
119
+ df.copy(),
120
+ entity_col=infer_panel_entity_col(df, timestamp_col=timestamp_col),
121
+ timestamp_col=timestamp_col,
122
+ )
123
+ feature_cols, calendar_cols = _assign_calendar_features(
124
+ df_out,
125
+ timestamp_col=timestamp_col,
126
+ calendar_features=calendar_features,
127
+ use_cyclical_time=use_cyclical_time,
128
+ )
129
+ return df_out, feature_cols, calendar_cols
130
+
131
+
132
+ def _assign_calendar_features(
133
+ df: pd.DataFrame,
134
+ *,
135
+ timestamp_col: str,
136
+ calendar_features: Sequence[str],
137
+ use_cyclical_time: bool,
138
+ ) -> tuple[list[str], list[str]]:
139
+ """Mutate ``df`` by adding calendar (and optional cyclical) columns."""
117
140
  _validate_calendar_features(calendar_features)
118
141
 
119
- df_out = df.copy()
120
- ts = pd.to_datetime(df_out[timestamp_col])
142
+ ts = pd.to_datetime(df[timestamp_col])
121
143
 
122
- calendar_cols: List[str] = []
123
- feature_cols: List[str] = []
144
+ calendar_cols: list[str] = []
145
+ feature_cols: list[str] = []
124
146
 
125
147
  for name in calendar_features:
126
148
  if name == "hour":
127
149
  col = "hour"
128
- df_out[col] = ts.dt.hour.astype("int16")
150
+ df[col] = ts.dt.hour.astype("int16")
129
151
  calendar_cols.append(col)
130
152
  elif name == "dow":
131
153
  col = "dayofweek"
132
- df_out[col] = ts.dt.dayofweek.astype("int16")
154
+ df[col] = ts.dt.dayofweek.astype("int16")
133
155
  calendar_cols.append(col)
134
156
  elif name == "dom":
135
157
  col = "dayofmonth"
136
- df_out[col] = ts.dt.day.astype("int16")
158
+ df[col] = ts.dt.day.astype("int16")
137
159
  calendar_cols.append(col)
138
160
  elif name == "month":
139
161
  col = "month"
140
- df_out[col] = ts.dt.month.astype("int16")
162
+ df[col] = ts.dt.month.astype("int16")
141
163
  calendar_cols.append(col)
142
164
  elif name == "is_weekend":
143
165
  col = "is_weekend"
144
- df_out[col] = ts.dt.dayofweek.isin(WEEKEND_DAYS).astype("int8")
166
+ df[col] = ts.dt.dayofweek.isin(WEEKEND_DAYS).astype("int8")
145
167
  calendar_cols.append(col)
146
168
  else: # pragma: no cover
147
169
  # Guarded by _validate_calendar_features, but keep a defensive fallback.
@@ -151,23 +173,20 @@ def add_calendar_features(
151
173
 
152
174
  feature_cols.extend(calendar_cols)
153
175
 
154
- # ---------------------------------------------------------------------
155
- # Optional cyclical encodings
156
- # ---------------------------------------------------------------------
157
176
  if use_cyclical_time:
158
177
  if "hour" in calendar_cols:
159
- hour = df_out["hour"].astype(float)
160
- df_out["hour_sin"] = np.sin(2.0 * np.pi * hour / float(HOUR_PERIOD))
161
- df_out["hour_cos"] = np.cos(2.0 * np.pi * hour / float(HOUR_PERIOD))
178
+ hour = df["hour"].astype(float)
179
+ df["hour_sin"] = np.sin(2.0 * np.pi * hour / float(HOUR_PERIOD))
180
+ df["hour_cos"] = np.cos(2.0 * np.pi * hour / float(HOUR_PERIOD))
162
181
  feature_cols.extend(["hour_sin", "hour_cos"])
163
182
 
164
183
  if "dayofweek" in calendar_cols:
165
- dow = df_out["dayofweek"].astype(float)
166
- df_out["dow_sin"] = np.sin(2.0 * np.pi * dow / float(DOW_PERIOD))
167
- df_out["dow_cos"] = np.cos(2.0 * np.pi * dow / float(DOW_PERIOD))
184
+ dow = df["dayofweek"].astype(float)
185
+ df["dow_sin"] = np.sin(2.0 * np.pi * dow / float(DOW_PERIOD))
186
+ df["dow_cos"] = np.cos(2.0 * np.pi * dow / float(DOW_PERIOD))
168
187
  feature_cols.extend(["dow_sin", "dow_cos"])
169
188
 
170
- return df_out, feature_cols, calendar_cols
189
+ return feature_cols, calendar_cols
171
190
 
172
191
 
173
192
  def _validate_calendar_features(calendar_features: Iterable[str]) -> None:
@@ -190,4 +209,4 @@ def _validate_calendar_features(calendar_features: Iterable[str]) -> None:
190
209
  raise ValueError(
191
210
  "Unsupported calendar feature(s) requested: "
192
211
  f"{invalid}. Allowed: {sorted(ALLOWED_CALENDAR_FEATURES)}."
193
- )
212
+ )
@@ -1,5 +1,3 @@
1
- from __future__ import annotations
2
-
3
1
  """
4
2
  Configuration objects for panel time-series feature engineering.
5
3
 
@@ -12,27 +10,36 @@ pipeline. The configuration is designed to be:
12
10
 
13
11
  Notes
14
12
  -----
15
- This configuration is consumed by [`FeatureEngineer`][eb_features.panel.engineer.FeatureEngineer]
16
- and related helper modules (lags, rolling, calendar, encoders).
13
+ This configuration is consumed by
14
+ [`FeatureEngineer`][eb_features.panel.engineering.FeatureEngineer] and related helper
15
+ modules (lags, rolling, calendar, encoders).
17
16
  """
18
17
 
18
+ from __future__ import annotations
19
+
20
+ from collections.abc import Sequence
19
21
  from dataclasses import dataclass, field
20
- from typing import Optional, Sequence, Tuple
21
22
 
22
23
  # -------------------------------------------------------------------------
23
24
  # Public constants (useful for validation, docs, and IDE discoverability)
24
25
  # -------------------------------------------------------------------------
25
26
 
26
27
  #: Allowed rolling statistics for rolling window features.
27
- ALLOWED_ROLLING_STATS: Tuple[str, ...] = ("mean", "std", "min", "max", "sum", "median")
28
+ ALLOWED_ROLLING_STATS: tuple[str, ...] = ("mean", "std", "min", "max", "sum", "median")
28
29
 
29
30
  #: Allowed calendar feature keys derived from timestamps.
30
- ALLOWED_CALENDAR_FEATURES: Tuple[str, ...] = ("hour", "dow", "dom", "month", "is_weekend")
31
+ ALLOWED_CALENDAR_FEATURES: tuple[str, ...] = (
32
+ "hour",
33
+ "dow",
34
+ "dom",
35
+ "month",
36
+ "is_weekend",
37
+ )
31
38
 
32
39
 
33
40
  @dataclass(frozen=True)
34
41
  class FeatureConfig:
35
- r"""
42
+ """
36
43
  Configuration for panel time-series feature engineering.
37
44
 
38
45
  The feature engineering pipeline assumes a long-form panel DataFrame with an entity
@@ -77,9 +84,9 @@ class FeatureConfig:
77
84
  by lags and rolling windows).
78
85
  """
79
86
 
80
- lag_steps: Optional[Sequence[int]] = field(default_factory=lambda: (1, 2, 24))
87
+ lag_steps: Sequence[int] | None = field(default_factory=lambda: (1, 2, 24))
81
88
 
82
- rolling_windows: Optional[Sequence[int]] = field(default_factory=lambda: (3, 24))
89
+ rolling_windows: Sequence[int] | None = field(default_factory=lambda: (3, 24))
83
90
  rolling_stats: Sequence[str] = field(
84
91
  default_factory=lambda: ("mean", "std", "min", "max", "sum")
85
92
  )
@@ -89,7 +96,7 @@ class FeatureConfig:
89
96
  )
90
97
  use_cyclical_time: bool = True
91
98
 
92
- regressor_cols: Optional[Sequence[str]] = None
93
- static_cols: Optional[Sequence[str]] = None
99
+ regressor_cols: Sequence[str] | None = None
100
+ static_cols: Sequence[str] | None = None
94
101
 
95
- dropna: bool = True
102
+ dropna: bool = True
@@ -1,5 +1,3 @@
1
- from __future__ import annotations
2
-
3
1
  r"""
4
2
  Shared constants for panel feature engineering.
5
3
 
@@ -15,14 +13,14 @@ Notes
15
13
  used consistently across feature builders.
16
14
  """
17
15
 
18
- from typing import Final, FrozenSet, Tuple
16
+ from __future__ import annotations
17
+
18
+ from typing import Final
19
19
 
20
20
  # -----------------------------------------------------------------------------
21
21
  # Allowed feature keys
22
22
  # -----------------------------------------------------------------------------
23
- ALLOWED_ROLLING_STATS: FrozenSet[str] = frozenset(
24
- {"mean", "std", "min", "max", "sum", "median"}
25
- )
23
+ ALLOWED_ROLLING_STATS: frozenset[str] = frozenset({"mean", "std", "min", "max", "sum", "median"})
26
24
  r"""
27
25
  Allowed rolling-window summary statistics.
28
26
 
@@ -36,9 +34,7 @@ where ``w`` is the window length (in index steps) and ``stat`` is one of the all
36
34
  """
37
35
 
38
36
 
39
- ALLOWED_CALENDAR_FEATURES: FrozenSet[str] = frozenset(
40
- {"hour", "dow", "dom", "month", "is_weekend"}
41
- )
37
+ ALLOWED_CALENDAR_FEATURES: frozenset[str] = frozenset({"hour", "dow", "dom", "month", "is_weekend"})
42
38
  r"""
43
39
  Allowed calendar features derived from the timestamp column.
44
40
 
@@ -49,12 +45,12 @@ cyclical encodings (sine/cosine) for periodic components.
49
45
  # -----------------------------------------------------------------------------
50
46
  # Default configuration values (used by FeatureConfig)
51
47
  # -----------------------------------------------------------------------------
52
- DEFAULT_LAG_STEPS: Final[Tuple[int, ...]] = (1, 2, 24)
48
+ DEFAULT_LAG_STEPS: Final[tuple[int, ...]] = (1, 2, 24)
53
49
 
54
- DEFAULT_ROLLING_WINDOWS: Final[Tuple[int, ...]] = (3, 24)
55
- DEFAULT_ROLLING_STATS: Final[Tuple[str, ...]] = ("mean", "std", "min", "max", "sum")
50
+ DEFAULT_ROLLING_WINDOWS: Final[tuple[int, ...]] = (3, 24)
51
+ DEFAULT_ROLLING_STATS: Final[tuple[str, ...]] = ("mean", "std", "min", "max", "sum")
56
52
 
57
- DEFAULT_CALENDAR_FEATURES: Final[Tuple[str, ...]] = (
53
+ DEFAULT_CALENDAR_FEATURES: Final[tuple[str, ...]] = (
58
54
  "hour",
59
55
  "dow",
60
56
  "month",
@@ -71,5 +67,5 @@ DOW_PERIOD: Final[int] = 7
71
67
  """Period used for cyclical day-of-week encodings."""
72
68
 
73
69
  # pandas dt.dayofweek convention: Monday=0 ... Sunday=6
74
- WEEKEND_DAYS: Final[Tuple[int, int]] = (5, 6)
75
- """Day-of-week values corresponding to Saturday and Sunday."""
70
+ WEEKEND_DAYS: Final[tuple[int, int]] = (5, 6)
71
+ """Day-of-week values corresponding to Saturday and Sunday."""
@@ -1,5 +1,3 @@
1
- from __future__ import annotations
2
-
3
1
  """
4
2
  Encoding utilities for panel feature engineering.
5
3
 
@@ -24,7 +22,9 @@ consider:
24
22
  - introducing a fitted encoder with persisted category mappings.
25
23
  """
26
24
 
27
- from typing import Iterable
25
+ from __future__ import annotations
26
+
27
+ from collections.abc import Iterable
28
28
 
29
29
  import pandas as pd
30
30
  from pandas.api.types import is_bool_dtype, is_numeric_dtype
@@ -53,7 +53,7 @@ def encode_non_numeric_as_category_codes(
53
53
  -------
54
54
  pandas.DataFrame
55
55
  Copy of ``feature_frame`` where:
56
- - boolean columns are converted to {0,1}
56
+ - boolean columns are converted to {0, 1}
57
57
  - non-numeric, non-boolean columns are replaced by categorical integer codes
58
58
 
59
59
  Notes
@@ -88,4 +88,4 @@ def encode_non_numeric_as_category_codes(
88
88
  cat = pd.Categorical(s, categories=categories, ordered=False)
89
89
  df[col] = cat.codes.astype(dtype)
90
90
 
91
- return df
91
+ return df