edrft 0.1.0__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.
- edrft-0.1.0/CITATION.cff +25 -0
- edrft-0.1.0/LICENSE +21 -0
- edrft-0.1.0/MANIFEST.in +6 -0
- edrft-0.1.0/PKG-INFO +166 -0
- edrft-0.1.0/README.md +128 -0
- edrft-0.1.0/docs/index.rst +18 -0
- edrft-0.1.0/examples/run_wave_forecasting.py +48 -0
- edrft-0.1.0/pyproject.toml +69 -0
- edrft-0.1.0/requirements.txt +2 -0
- edrft-0.1.0/setup.cfg +4 -0
- edrft-0.1.0/setup.py +4 -0
- edrft-0.1.0/src/edrft/__init__.py +18 -0
- edrft-0.1.0/src/edrft/data.py +57 -0
- edrft-0.1.0/src/edrft/metrics.py +26 -0
- edrft-0.1.0/src/edrft/models.py +266 -0
- edrft-0.1.0/src/edrft/tuning.py +191 -0
- edrft-0.1.0/src/edrft/wave.py +200 -0
- edrft-0.1.0/src/edrft.egg-info/PKG-INFO +166 -0
- edrft-0.1.0/src/edrft.egg-info/SOURCES.txt +22 -0
- edrft-0.1.0/src/edrft.egg-info/dependency_links.txt +1 -0
- edrft-0.1.0/src/edrft.egg-info/requires.txt +19 -0
- edrft-0.1.0/src/edrft.egg-info/top_level.txt +1 -0
- edrft-0.1.0/tests/test_models.py +36 -0
- edrft-0.1.0/tests/test_tuning.py +56 -0
edrft-0.1.0/CITATION.cff
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use edRFT in academic work, please cite this software and the associated article."
|
|
3
|
+
title: "edRFT"
|
|
4
|
+
version: "0.1.0"
|
|
5
|
+
date-released: "2026-06-25"
|
|
6
|
+
authors:
|
|
7
|
+
- family-names: "Bhambu"
|
|
8
|
+
given-names: "Aryan"
|
|
9
|
+
license: "MIT"
|
|
10
|
+
repository-code: "https://github.com/statsdl/edRFT"
|
|
11
|
+
preferred-citation:
|
|
12
|
+
type: article
|
|
13
|
+
title: "Deep random vector functional link transformer network with multiple output layers for significant wave height forecasting"
|
|
14
|
+
authors:
|
|
15
|
+
- family-names: "Bhambu"
|
|
16
|
+
given-names: "Aryan"
|
|
17
|
+
- family-names: "Gao"
|
|
18
|
+
given-names: "Ruobin"
|
|
19
|
+
- family-names: "Suganthan"
|
|
20
|
+
given-names: "Ponnuthurai Nagaratnam"
|
|
21
|
+
- family-names: "Natarajan"
|
|
22
|
+
given-names: "Selvaraju"
|
|
23
|
+
journal: "Applied Soft Computing"
|
|
24
|
+
year: 2025
|
|
25
|
+
start: "114136"
|
edrft-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Aryan Bhambu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
edrft-0.1.0/MANIFEST.in
ADDED
edrft-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: edrft
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: RFT and edRFT models for significant wave-height time-series forecasting.
|
|
5
|
+
Author: Aryan Bhambu
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/statsdl/edRFT
|
|
8
|
+
Project-URL: Issues, https://github.com/statsdl/edRFT/issues
|
|
9
|
+
Keywords: edrft,rft,rvfl,transformer,wave-height,forecasting
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: numpy>=1.21
|
|
22
|
+
Requires-Dist: torch>=2.0
|
|
23
|
+
Provides-Extra: tuning
|
|
24
|
+
Requires-Dist: hyperopt>=0.2.7; extra == "tuning"
|
|
25
|
+
Requires-Dist: setuptools<81; extra == "tuning"
|
|
26
|
+
Provides-Extra: wave
|
|
27
|
+
Requires-Dist: hyperopt>=0.2.7; extra == "wave"
|
|
28
|
+
Requires-Dist: pandas>=1.3; extra == "wave"
|
|
29
|
+
Requires-Dist: setuptools<81; extra == "wave"
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: build; extra == "dev"
|
|
32
|
+
Requires-Dist: hyperopt>=0.2.7; extra == "dev"
|
|
33
|
+
Requires-Dist: pandas>=1.3; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest; extra == "dev"
|
|
35
|
+
Requires-Dist: setuptools<81; extra == "dev"
|
|
36
|
+
Requires-Dist: twine; extra == "dev"
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
|
|
39
|
+
# edRFT
|
|
40
|
+
|
|
41
|
+
`edrft` provides Random Vector Functional Link Transformer models for
|
|
42
|
+
significant wave-height forecasting:
|
|
43
|
+
|
|
44
|
+
- `RFTRegressor`: a shallow randomized transformer encoder with ridge readout.
|
|
45
|
+
- `EDRFTRegressor`: an ensemble deep RFT with one output layer per hidden layer.
|
|
46
|
+
- Hyperopt/TPE tuning using the default edRFT search ranges.
|
|
47
|
+
- NDBC wave forecasting experiment helpers that do not write result artifacts.
|
|
48
|
+
|
|
49
|
+
The public package uses the model naming: `RFT` and `edRFT`. Older `rft` and
|
|
50
|
+
`edrft` script names are retained only under legacy files for traceability.
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
|
|
54
|
+
Core install:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
git clone https://github.com/statsdl/edRFT.git
|
|
58
|
+
cd edRFT
|
|
59
|
+
pip install .
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Wave experiment dependencies:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pip install ".[wave]"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Development:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pip install -e ".[dev]"
|
|
72
|
+
pytest
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Quick Start
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
import numpy as np
|
|
79
|
+
from edrft import EDRFTRegressor, make_forecasting_frame
|
|
80
|
+
|
|
81
|
+
series = np.sin(np.linspace(0, 16, 240))
|
|
82
|
+
X, y = make_forecasting_frame(series, order=4)
|
|
83
|
+
|
|
84
|
+
model = EDRFTRegressor(n_layers=3, n_hidden=32, random_state=0)
|
|
85
|
+
model.fit(X[:180], y[:180])
|
|
86
|
+
pred = model.predict(X[180:])
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Wave Forecasting Example
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
python examples/run_wave_forecasting.py \
|
|
93
|
+
--data-dir wave \
|
|
94
|
+
--stations 46001h \
|
|
95
|
+
--years 2017 \
|
|
96
|
+
--seeds 0 \
|
|
97
|
+
--look-back 48 \
|
|
98
|
+
--horizon 4 \
|
|
99
|
+
--layers 10 \
|
|
100
|
+
--max-evals 100
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The runner prints metrics to stdout only. It follows the original scripts:
|
|
104
|
+
|
|
105
|
+
- NDBC features: `WDIR`, `WSPD`, `GST`, `APD`, `WVHT`
|
|
106
|
+
- Missing sentinel cleanup
|
|
107
|
+
- Default look-back window: 48
|
|
108
|
+
- Default forecasting horizon: 4
|
|
109
|
+
- Min-max scaling to `[-1, 1]`
|
|
110
|
+
- Chronological split: 70% train, 10% validation, 20% test
|
|
111
|
+
- Hyperopt/TPE tuning with 100 evaluations by default
|
|
112
|
+
- Train+validation final fit
|
|
113
|
+
- RMSE, MAPE, MASE, and timing output
|
|
114
|
+
|
|
115
|
+
## Hyperopt Tuning
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
from edrft.tuning import layerwise_tune_edrft
|
|
119
|
+
|
|
120
|
+
result = layerwise_tune_edrft(
|
|
121
|
+
X,
|
|
122
|
+
y,
|
|
123
|
+
n_layers=10,
|
|
124
|
+
validation_fraction=0.1 / 0.8,
|
|
125
|
+
max_evals=100,
|
|
126
|
+
random_state=0,
|
|
127
|
+
)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Repository Notes
|
|
131
|
+
|
|
132
|
+
Supported package code lives in `src/edrft`.
|
|
133
|
+
|
|
134
|
+
The `legacy/`, `DeepRVFL_/`, `ForecastLib.py`, and old experiment scripts are
|
|
135
|
+
retained for traceability. They are not included in the PyPI wheel and are not
|
|
136
|
+
the supported package API.
|
|
137
|
+
|
|
138
|
+
## PyPI Release
|
|
139
|
+
|
|
140
|
+
The publish workflow uses PyPI Trusted Publishing. Configure the PyPI trusted
|
|
141
|
+
publisher with:
|
|
142
|
+
|
|
143
|
+
- owner: `statsdl`
|
|
144
|
+
- repository: `edRFT`
|
|
145
|
+
- workflow: `publish.yml`
|
|
146
|
+
- environment: `pypi`
|
|
147
|
+
|
|
148
|
+
## License
|
|
149
|
+
|
|
150
|
+
MIT
|
|
151
|
+
|
|
152
|
+
## Reference
|
|
153
|
+
|
|
154
|
+
If you use edRFT in your work, please cite:
|
|
155
|
+
|
|
156
|
+
```bibtex
|
|
157
|
+
@article{bhambu2025deep,
|
|
158
|
+
title={Deep random vector functional link transformer network with multiple output layers for significant wave height forecasting},
|
|
159
|
+
author={Bhambu, Aryan and Gao, Ruobin and Suganthan, Ponnuthurai Nagaratnam and Selvaraju, Natarajan},
|
|
160
|
+
journal={Applied Soft Computing},
|
|
161
|
+
pages={114136},
|
|
162
|
+
year={2025},
|
|
163
|
+
publisher={Elsevier}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
edrft-0.1.0/README.md
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# edRFT
|
|
2
|
+
|
|
3
|
+
`edrft` provides Random Vector Functional Link Transformer models for
|
|
4
|
+
significant wave-height forecasting:
|
|
5
|
+
|
|
6
|
+
- `RFTRegressor`: a shallow randomized transformer encoder with ridge readout.
|
|
7
|
+
- `EDRFTRegressor`: an ensemble deep RFT with one output layer per hidden layer.
|
|
8
|
+
- Hyperopt/TPE tuning using the default edRFT search ranges.
|
|
9
|
+
- NDBC wave forecasting experiment helpers that do not write result artifacts.
|
|
10
|
+
|
|
11
|
+
The public package uses the model naming: `RFT` and `edRFT`. Older `rft` and
|
|
12
|
+
`edrft` script names are retained only under legacy files for traceability.
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
Core install:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
git clone https://github.com/statsdl/edRFT.git
|
|
20
|
+
cd edRFT
|
|
21
|
+
pip install .
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Wave experiment dependencies:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install ".[wave]"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Development:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install -e ".[dev]"
|
|
34
|
+
pytest
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
import numpy as np
|
|
41
|
+
from edrft import EDRFTRegressor, make_forecasting_frame
|
|
42
|
+
|
|
43
|
+
series = np.sin(np.linspace(0, 16, 240))
|
|
44
|
+
X, y = make_forecasting_frame(series, order=4)
|
|
45
|
+
|
|
46
|
+
model = EDRFTRegressor(n_layers=3, n_hidden=32, random_state=0)
|
|
47
|
+
model.fit(X[:180], y[:180])
|
|
48
|
+
pred = model.predict(X[180:])
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Wave Forecasting Example
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
python examples/run_wave_forecasting.py \
|
|
55
|
+
--data-dir wave \
|
|
56
|
+
--stations 46001h \
|
|
57
|
+
--years 2017 \
|
|
58
|
+
--seeds 0 \
|
|
59
|
+
--look-back 48 \
|
|
60
|
+
--horizon 4 \
|
|
61
|
+
--layers 10 \
|
|
62
|
+
--max-evals 100
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The runner prints metrics to stdout only. It follows the original scripts:
|
|
66
|
+
|
|
67
|
+
- NDBC features: `WDIR`, `WSPD`, `GST`, `APD`, `WVHT`
|
|
68
|
+
- Missing sentinel cleanup
|
|
69
|
+
- Default look-back window: 48
|
|
70
|
+
- Default forecasting horizon: 4
|
|
71
|
+
- Min-max scaling to `[-1, 1]`
|
|
72
|
+
- Chronological split: 70% train, 10% validation, 20% test
|
|
73
|
+
- Hyperopt/TPE tuning with 100 evaluations by default
|
|
74
|
+
- Train+validation final fit
|
|
75
|
+
- RMSE, MAPE, MASE, and timing output
|
|
76
|
+
|
|
77
|
+
## Hyperopt Tuning
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from edrft.tuning import layerwise_tune_edrft
|
|
81
|
+
|
|
82
|
+
result = layerwise_tune_edrft(
|
|
83
|
+
X,
|
|
84
|
+
y,
|
|
85
|
+
n_layers=10,
|
|
86
|
+
validation_fraction=0.1 / 0.8,
|
|
87
|
+
max_evals=100,
|
|
88
|
+
random_state=0,
|
|
89
|
+
)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Repository Notes
|
|
93
|
+
|
|
94
|
+
Supported package code lives in `src/edrft`.
|
|
95
|
+
|
|
96
|
+
The `legacy/`, `DeepRVFL_/`, `ForecastLib.py`, and old experiment scripts are
|
|
97
|
+
retained for traceability. They are not included in the PyPI wheel and are not
|
|
98
|
+
the supported package API.
|
|
99
|
+
|
|
100
|
+
## PyPI Release
|
|
101
|
+
|
|
102
|
+
The publish workflow uses PyPI Trusted Publishing. Configure the PyPI trusted
|
|
103
|
+
publisher with:
|
|
104
|
+
|
|
105
|
+
- owner: `statsdl`
|
|
106
|
+
- repository: `edRFT`
|
|
107
|
+
- workflow: `publish.yml`
|
|
108
|
+
- environment: `pypi`
|
|
109
|
+
|
|
110
|
+
## License
|
|
111
|
+
|
|
112
|
+
MIT
|
|
113
|
+
|
|
114
|
+
## Reference
|
|
115
|
+
|
|
116
|
+
If you use edRFT in your work, please cite:
|
|
117
|
+
|
|
118
|
+
```bibtex
|
|
119
|
+
@article{bhambu2025deep,
|
|
120
|
+
title={Deep random vector functional link transformer network with multiple output layers for significant wave height forecasting},
|
|
121
|
+
author={Bhambu, Aryan and Gao, Ruobin and Suganthan, Ponnuthurai Nagaratnam and Selvaraju, Natarajan},
|
|
122
|
+
journal={Applied Soft Computing},
|
|
123
|
+
pages={114136},
|
|
124
|
+
year={2025},
|
|
125
|
+
publisher={Elsevier}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
edRFT
|
|
2
|
+
=====
|
|
3
|
+
|
|
4
|
+
``edrft`` provides RFT and edRFT regressors for significant wave-height
|
|
5
|
+
forecasting.
|
|
6
|
+
|
|
7
|
+
Installation
|
|
8
|
+
------------
|
|
9
|
+
|
|
10
|
+
.. code-block:: bash
|
|
11
|
+
|
|
12
|
+
pip install edrft
|
|
13
|
+
|
|
14
|
+
Optional wave experiment dependencies:
|
|
15
|
+
|
|
16
|
+
.. code-block:: bash
|
|
17
|
+
|
|
18
|
+
pip install "edrft[wave]"
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
|
|
3
|
+
from edrft.wave import run_wave_experiment
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def parse_csv(value):
|
|
7
|
+
return tuple(item.strip() for item in value.split(",") if item.strip())
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def parse_seeds(value):
|
|
11
|
+
return tuple(int(item) for item in parse_csv(value))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def main():
|
|
15
|
+
parser = argparse.ArgumentParser(description="Run RFT/edRFT wave forecasting experiments.")
|
|
16
|
+
parser.add_argument("--data-dir", default="wave")
|
|
17
|
+
parser.add_argument("--stations", default="46001h")
|
|
18
|
+
parser.add_argument("--years", default="2017")
|
|
19
|
+
parser.add_argument("--seeds", default="0")
|
|
20
|
+
parser.add_argument("--look-back", type=int, default=48)
|
|
21
|
+
parser.add_argument("--order", type=int, default=None, help=argparse.SUPPRESS)
|
|
22
|
+
parser.add_argument("--horizon", type=int, default=4)
|
|
23
|
+
parser.add_argument("--layers", type=int, default=10)
|
|
24
|
+
parser.add_argument("--max-evals", type=int, default=100)
|
|
25
|
+
args = parser.parse_args()
|
|
26
|
+
|
|
27
|
+
results = run_wave_experiment(
|
|
28
|
+
data_dir=args.data_dir,
|
|
29
|
+
stations=parse_csv(args.stations),
|
|
30
|
+
years=parse_csv(args.years),
|
|
31
|
+
seeds=parse_seeds(args.seeds),
|
|
32
|
+
look_back=args.order if args.order is not None else args.look_back,
|
|
33
|
+
horizon=args.horizon,
|
|
34
|
+
n_layers=args.layers,
|
|
35
|
+
max_evals=args.max_evals,
|
|
36
|
+
)
|
|
37
|
+
for result in results:
|
|
38
|
+
print(
|
|
39
|
+
f"{result.year} {result.station} seed={result.seed} {result.model:5s} "
|
|
40
|
+
f"RMSE={result.rmse:.6f} MAPE={result.mape:.6f} MASE={result.mase:.6f} "
|
|
41
|
+
f"tune={result.tuning_seconds:.3f}s train={result.training_seconds:.3f}s "
|
|
42
|
+
f"test={result.testing_seconds:.3f}s"
|
|
43
|
+
)
|
|
44
|
+
print(f"best_params={result.best_params}")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
if __name__ == "__main__":
|
|
48
|
+
main()
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "edrft"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "RFT and edRFT models for significant wave-height time-series forecasting."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [
|
|
14
|
+
{name = "Aryan Bhambu"},
|
|
15
|
+
]
|
|
16
|
+
keywords = ["edrft", "rft", "rvfl", "transformer", "wave-height", "forecasting"]
|
|
17
|
+
classifiers = [
|
|
18
|
+
"Development Status :: 3 - Alpha",
|
|
19
|
+
"Intended Audience :: Science/Research",
|
|
20
|
+
"Operating System :: OS Independent",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.10",
|
|
23
|
+
"Programming Language :: Python :: 3.11",
|
|
24
|
+
"Programming Language :: Python :: 3.12",
|
|
25
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
26
|
+
]
|
|
27
|
+
dependencies = [
|
|
28
|
+
"numpy>=1.21",
|
|
29
|
+
"torch>=2.0",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.optional-dependencies]
|
|
33
|
+
tuning = [
|
|
34
|
+
"hyperopt>=0.2.7",
|
|
35
|
+
"setuptools<81",
|
|
36
|
+
]
|
|
37
|
+
wave = [
|
|
38
|
+
"hyperopt>=0.2.7",
|
|
39
|
+
"pandas>=1.3",
|
|
40
|
+
"setuptools<81",
|
|
41
|
+
]
|
|
42
|
+
dev = [
|
|
43
|
+
"build",
|
|
44
|
+
"hyperopt>=0.2.7",
|
|
45
|
+
"pandas>=1.3",
|
|
46
|
+
"pytest",
|
|
47
|
+
"setuptools<81",
|
|
48
|
+
"twine",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
[project.urls]
|
|
52
|
+
Homepage = "https://github.com/statsdl/edRFT"
|
|
53
|
+
Issues = "https://github.com/statsdl/edRFT/issues"
|
|
54
|
+
|
|
55
|
+
[tool.setuptools.packages.find]
|
|
56
|
+
where = ["src"]
|
|
57
|
+
|
|
58
|
+
[tool.black]
|
|
59
|
+
line-length = 99
|
|
60
|
+
target-version = ["py38"]
|
|
61
|
+
|
|
62
|
+
[tool.isort]
|
|
63
|
+
profile = "black"
|
|
64
|
+
multi_line_output = 3
|
|
65
|
+
|
|
66
|
+
[tool.pytest.ini_options]
|
|
67
|
+
minversion = "6.0"
|
|
68
|
+
addopts = "-ra -q"
|
|
69
|
+
testpaths = ["tests"]
|
edrft-0.1.0/setup.cfg
ADDED
edrft-0.1.0/setup.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Random Vector Functional Link Transformer models."""
|
|
2
|
+
|
|
3
|
+
from .data import chronological_split, make_forecasting_frame
|
|
4
|
+
from .metrics import mean_absolute_scaled_error, mean_absolute_percentage_error, root_mean_squared_error
|
|
5
|
+
from .models import EDRFTRegressor, RFTLayerParams, RFTRegressor
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"EDRFTRegressor",
|
|
9
|
+
"RFTLayerParams",
|
|
10
|
+
"RFTRegressor",
|
|
11
|
+
"chronological_split",
|
|
12
|
+
"make_forecasting_frame",
|
|
13
|
+
"mean_absolute_percentage_error",
|
|
14
|
+
"mean_absolute_scaled_error",
|
|
15
|
+
"root_mean_squared_error",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Iterable
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def make_forecasting_frame(
|
|
10
|
+
series: Iterable[float] | np.ndarray,
|
|
11
|
+
order: int = 48,
|
|
12
|
+
horizon: int = 4,
|
|
13
|
+
) -> tuple[np.ndarray, np.ndarray]:
|
|
14
|
+
"""Convert a univariate or multivariate sequence into lagged samples."""
|
|
15
|
+
|
|
16
|
+
values = np.asarray(series, dtype=np.float32)
|
|
17
|
+
if values.ndim == 1:
|
|
18
|
+
values = values.reshape(-1, 1)
|
|
19
|
+
if values.ndim != 2:
|
|
20
|
+
raise ValueError("series must be a 1D or 2D array.")
|
|
21
|
+
if order <= 0 or horizon <= 0:
|
|
22
|
+
raise ValueError("order and horizon must be positive.")
|
|
23
|
+
n_samples = values.shape[0] - order - horizon + 1
|
|
24
|
+
if n_samples <= 0:
|
|
25
|
+
raise ValueError("series is too short for the requested order and horizon.")
|
|
26
|
+
X = np.zeros((n_samples, values.shape[1] * order), dtype=np.float32)
|
|
27
|
+
y = np.zeros((n_samples, values.shape[1]), dtype=np.float32)
|
|
28
|
+
for i in range(n_samples):
|
|
29
|
+
X[i] = values[i : i + order].ravel()
|
|
30
|
+
y[i] = values[i + order + horizon - 1]
|
|
31
|
+
return X, y.ravel() if y.shape[1] == 1 else y
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def chronological_split(n_samples: int, validation_fraction: float = 0.1, test_fraction: float = 0.2):
|
|
35
|
+
"""Return train, validation, full-train, and test indexes in time order."""
|
|
36
|
+
|
|
37
|
+
test_len = int(test_fraction * n_samples)
|
|
38
|
+
val_len = int(validation_fraction * n_samples)
|
|
39
|
+
train_len = n_samples - val_len - test_len
|
|
40
|
+
if train_len <= 0:
|
|
41
|
+
raise ValueError("Not enough samples for the requested split.")
|
|
42
|
+
train = np.arange(train_len)
|
|
43
|
+
val = np.arange(train_len, train_len + val_len)
|
|
44
|
+
full_train = np.arange(train_len + val_len)
|
|
45
|
+
test = np.arange(train_len + val_len, n_samples)
|
|
46
|
+
return train, val, full_train, test
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def load_ndbc_wave_file(path: str | Path, features: list[str] | None = None) -> pd.DataFrame:
|
|
50
|
+
"""Load an NDBC wave-height text file and clean sentinel missing values."""
|
|
51
|
+
|
|
52
|
+
import pandas as pd
|
|
53
|
+
|
|
54
|
+
features = features or ["WDIR", "WSPD", "GST", "APD", "WVHT"]
|
|
55
|
+
frame = pd.read_csv(path, sep=r"\s+", compression="infer")
|
|
56
|
+
frame = frame[features].replace(["99.0", "99.00", 99.0, 99.00], np.nan)
|
|
57
|
+
return frame.ffill().bfill().astype(float)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def root_mean_squared_error(y_true, y_pred) -> float:
|
|
7
|
+
truth = np.asarray(y_true, dtype=float).ravel()
|
|
8
|
+
pred = np.asarray(y_pred, dtype=float).ravel()
|
|
9
|
+
return float(np.sqrt(np.mean((truth - pred) ** 2)))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def mean_absolute_percentage_error(y_true, y_pred, epsilon: float = 1e-8) -> float:
|
|
13
|
+
truth = np.asarray(y_true, dtype=float).ravel()
|
|
14
|
+
pred = np.asarray(y_pred, dtype=float).ravel()
|
|
15
|
+
denom = np.maximum(np.abs(truth), epsilon)
|
|
16
|
+
return float(np.mean(np.abs((truth - pred) / denom)))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def mean_absolute_scaled_error(y_true, y_pred, history, seasonality: int = 1) -> float:
|
|
20
|
+
truth = np.asarray(y_true, dtype=float).ravel()
|
|
21
|
+
pred = np.asarray(y_pred, dtype=float).ravel()
|
|
22
|
+
hist = np.asarray(history, dtype=float).ravel()
|
|
23
|
+
scale = np.mean(np.abs(hist[seasonality:] - hist[:-seasonality]))
|
|
24
|
+
if scale == 0:
|
|
25
|
+
return float("inf")
|
|
26
|
+
return float(np.mean(np.abs(truth - pred)) / scale)
|