spotoptim 3.0.0__tar.gz → 3.2.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.
- {spotoptim-3.0.0 → spotoptim-3.2.0}/PKG-INFO +2 -1
- {spotoptim-3.0.0 → spotoptim-3.2.0}/pyproject.toml +2 -1
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/data/__init__.py +21 -1
- spotoptim-3.2.0/src/spotoptim/data/manydataset.py +375 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/function/__init__.py +5 -0
- spotoptim-3.2.0/src/spotoptim/function/sequence_cv_objective.py +278 -0
- spotoptim-3.2.0/src/spotoptim/nn/__init__.py +44 -0
- spotoptim-3.2.0/src/spotoptim/nn/many_to_many_rnn.py +234 -0
- spotoptim-3.2.0/src/spotoptim/nn/optimizer.py +202 -0
- spotoptim-3.2.0/src/spotoptim/nn/training.py +234 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/utils/__init__.py +3 -0
- spotoptim-3.2.0/src/spotoptim/utils/seed.py +60 -0
- spotoptim-3.0.0/src/spotoptim/nn/__init__.py +0 -26
- {spotoptim-3.0.0 → spotoptim-3.2.0}/README.md +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/SpotOptim.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/__init__.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/core/__init__.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/core/data.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/core/experiment.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/core/protocol.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/core/storage.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/data/base.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/data/diabetes.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/datasets/__init__.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/datasets/py.typed +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/datasets/test01.csv +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/datasets/test02.csv +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/datasets/test11.csv +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/eda/__init__.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/eda/plots.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/factor_analyzer/__init__.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/factor_analyzer/confirmatory_factor_analyzer.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/factor_analyzer/factor_analyzer.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/factor_analyzer/factor_analyzer_rotator.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/factor_analyzer/factor_analyzer_utils.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/function/cd_data.csv +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/function/forr08a.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/function/mo.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/function/remote.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/function/so.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/function/torch_objective.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/hyperparameters/__init__.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/hyperparameters/parameters.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/hyperparameters/repr_helpers.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/inspection/__init__.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/inspection/importance.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/inspection/predictions.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/mo/__init__.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/mo/mo_mm.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/mo/pareto.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/nn/linear_regressor.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/nn/mlp.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/optimizer/__init__.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/optimizer/acquisition.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/optimizer/schedule_free.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/optimizer/wrapper.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/plot/__init__.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/plot/contour.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/plot/mo.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/plot/visualization.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/py.typed +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/reporting/__init__.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/reporting/analysis.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/reporting/results.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/sampling/__init__.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/sampling/design.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/sampling/effects.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/sampling/lhs.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/sampling/mm.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/surrogate/__init__.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/surrogate/kernels.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/surrogate/kriging.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/surrogate/mlp_surrogate.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/surrogate/nystroem.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/surrogate/pipeline.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/surrogate/simple_kriging.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/tricands/__init__.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/tricands/tricands.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/utils/boundaries.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/utils/convert.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/utils/dimreduction.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/utils/eval.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/utils/file.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/utils/mapping.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/utils/ocba.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/utils/pca.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/utils/scaler.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/utils/serialization.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/utils/stats.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/utils/tensorboard.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/utils/transform.py +0 -0
- {spotoptim-3.0.0 → spotoptim-3.2.0}/src/spotoptim/utils/variables.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: spotoptim
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.0
|
|
4
4
|
Summary: Sequential Parameter Optimization Toolbox
|
|
5
5
|
Author: bartzbeielstein
|
|
6
6
|
Author-email: bartzbeielstein <32470350+bartzbeielstein@users.noreply.github.com>
|
|
@@ -36,6 +36,7 @@ Requires-Dist: requests>=2.32.3 ; extra == 'remote'
|
|
|
36
36
|
Requires-Dist: statsmodels>=0.14.6 ; extra == 'stats'
|
|
37
37
|
Requires-Dist: torch>=2.9.1 ; extra == 'torch'
|
|
38
38
|
Requires-Dist: tensorboard>=2.20.0 ; extra == 'torch'
|
|
39
|
+
Requires-Dist: torchmetrics>=1.8.2 ; extra == 'torch'
|
|
39
40
|
Requires-Dist: matplotlib>=3.10.7 ; extra == 'viz'
|
|
40
41
|
Requires-Dist: seaborn>=0.13.2 ; extra == 'viz'
|
|
41
42
|
Requires-Python: >=3.13
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "spotoptim"
|
|
3
|
-
version = "3.
|
|
3
|
+
version = "3.2.0"
|
|
4
4
|
description = "Sequential Parameter Optimization Toolbox"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "AGPL-3.0-or-later" }
|
|
@@ -44,6 +44,7 @@ dev = [
|
|
|
44
44
|
torch = [
|
|
45
45
|
"torch>=2.9.1",
|
|
46
46
|
"tensorboard>=2.20.0",
|
|
47
|
+
"torchmetrics>=1.8.2",
|
|
47
48
|
]
|
|
48
49
|
viz = [
|
|
49
50
|
"matplotlib>=3.10.7",
|
|
@@ -10,11 +10,31 @@ machine learning tasks.
|
|
|
10
10
|
|
|
11
11
|
from .base import Config, FileConfig
|
|
12
12
|
|
|
13
|
-
__all__ = [
|
|
13
|
+
__all__ = [
|
|
14
|
+
"DiabetesDataset",
|
|
15
|
+
"get_diabetes_dataloaders",
|
|
16
|
+
"Config",
|
|
17
|
+
"FileConfig",
|
|
18
|
+
"ManyToManyDataset",
|
|
19
|
+
"ManyToOneDataset",
|
|
20
|
+
"PadSequenceManyToMany",
|
|
21
|
+
"PadSequenceManyToOne",
|
|
22
|
+
"load_sequence_data",
|
|
23
|
+
"load_pooled_sequence_data",
|
|
24
|
+
]
|
|
14
25
|
|
|
15
26
|
_lazy_map = {
|
|
16
27
|
"DiabetesDataset": ("spotoptim.data.diabetes", "DiabetesDataset"),
|
|
17
28
|
"get_diabetes_dataloaders": ("spotoptim.data.diabetes", "get_diabetes_dataloaders"),
|
|
29
|
+
"ManyToManyDataset": ("spotoptim.data.manydataset", "ManyToManyDataset"),
|
|
30
|
+
"ManyToOneDataset": ("spotoptim.data.manydataset", "ManyToOneDataset"),
|
|
31
|
+
"PadSequenceManyToMany": ("spotoptim.data.manydataset", "PadSequenceManyToMany"),
|
|
32
|
+
"PadSequenceManyToOne": ("spotoptim.data.manydataset", "PadSequenceManyToOne"),
|
|
33
|
+
"load_sequence_data": ("spotoptim.data.manydataset", "load_sequence_data"),
|
|
34
|
+
"load_pooled_sequence_data": (
|
|
35
|
+
"spotoptim.data.manydataset",
|
|
36
|
+
"load_pooled_sequence_data",
|
|
37
|
+
),
|
|
18
38
|
}
|
|
19
39
|
|
|
20
40
|
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2026 bartzbeielstein
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
4
|
+
|
|
5
|
+
"""Variable-length sequence datasets and padding collates for recurrent models.
|
|
6
|
+
|
|
7
|
+
Ported from spotPython (``spotpython.data.manydataset`` and the padding
|
|
8
|
+
collates from ``spotpython.data.lightdatamodule``) without any Lightning
|
|
9
|
+
dependency. Each dataset item is one complete sequence (e.g. one operating
|
|
10
|
+
curve of a compressor map), so batches must be padded with the collate
|
|
11
|
+
classes provided here.
|
|
12
|
+
|
|
13
|
+
Requires the ``torch`` optional extra (``pip install 'spotoptim[torch]'``).
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from typing import List, Optional, Tuple, Union
|
|
17
|
+
|
|
18
|
+
import pandas as pd
|
|
19
|
+
import torch
|
|
20
|
+
from torch.nn.utils.rnn import pad_sequence
|
|
21
|
+
from torch.utils.data import ConcatDataset, Dataset
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ManyToManyDataset(Dataset):
|
|
25
|
+
"""Sequence dataset with one target value per time step.
|
|
26
|
+
|
|
27
|
+
Each element of ``df_list`` is one variable-length sequence; item ``i``
|
|
28
|
+
is the pair ``(features_i, targets_i)`` with shapes ``(T_i, n_features)``
|
|
29
|
+
and ``(T_i,)``.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
df_list (List[pd.DataFrame]): List of pandas DataFrames, one per sequence.
|
|
33
|
+
target (str): The target column name.
|
|
34
|
+
drop (Optional[Union[str, List[str]]]): Column(s) to drop from the
|
|
35
|
+
DataFrames before extracting features. If a listed column is
|
|
36
|
+
missing, no column is dropped. Defaults to None.
|
|
37
|
+
dtype (torch.dtype): Data type for the tensors. Defaults to ``torch.float32``.
|
|
38
|
+
|
|
39
|
+
Attributes:
|
|
40
|
+
data (List[pd.DataFrame]): DataFrames with the ``drop`` columns removed.
|
|
41
|
+
target (List[torch.Tensor]): Per-sequence target tensors, shape ``(T_i,)``.
|
|
42
|
+
features (List[torch.Tensor]): Per-sequence feature tensors, shape
|
|
43
|
+
``(T_i, n_features)``.
|
|
44
|
+
|
|
45
|
+
Examples:
|
|
46
|
+
```{python}
|
|
47
|
+
import pandas as pd
|
|
48
|
+
from spotoptim.data.manydataset import ManyToManyDataset
|
|
49
|
+
|
|
50
|
+
df1 = pd.DataFrame({"x": [1.0, 2.0, 3.0], "y": [2.0, 4.0, 6.0]})
|
|
51
|
+
df2 = pd.DataFrame({"x": [4.0, 5.0], "y": [8.0, 10.0]})
|
|
52
|
+
ds = ManyToManyDataset([df1, df2], target="y")
|
|
53
|
+
print(len(ds))
|
|
54
|
+
features, targets = ds[0]
|
|
55
|
+
print(features.shape, targets.shape)
|
|
56
|
+
```
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
def __init__(
|
|
60
|
+
self,
|
|
61
|
+
df_list: List[pd.DataFrame],
|
|
62
|
+
target: str,
|
|
63
|
+
drop: Optional[Union[str, List[str]]] = None,
|
|
64
|
+
dtype: torch.dtype = torch.float32,
|
|
65
|
+
):
|
|
66
|
+
if drop is None:
|
|
67
|
+
self.data = list(df_list)
|
|
68
|
+
else:
|
|
69
|
+
try:
|
|
70
|
+
self.data = [df.drop(drop, axis=1) for df in df_list]
|
|
71
|
+
except KeyError:
|
|
72
|
+
self.data = df_list
|
|
73
|
+
self.target = [
|
|
74
|
+
torch.tensor(df[target].to_numpy(), dtype=dtype) for df in self.data
|
|
75
|
+
]
|
|
76
|
+
self.features = [
|
|
77
|
+
torch.tensor(df.drop([target], axis=1).to_numpy(), dtype=dtype)
|
|
78
|
+
for df in self.data
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
def __getitem__(self, index: int):
|
|
82
|
+
"""Return the ``(features, targets)`` pair of sequence ``index``."""
|
|
83
|
+
x = self.features[index]
|
|
84
|
+
y = self.target[index]
|
|
85
|
+
return x, y
|
|
86
|
+
|
|
87
|
+
def __len__(self) -> int:
|
|
88
|
+
"""Return the number of sequences."""
|
|
89
|
+
return len(self.data)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class ManyToOneDataset(Dataset):
|
|
93
|
+
"""Sequence dataset with a single target value per sequence.
|
|
94
|
+
|
|
95
|
+
Like `ManyToManyDataset`, but item ``i`` pairs the full feature sequence
|
|
96
|
+
with the scalar target taken from the first row of sequence ``i``.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
df_list (List[pd.DataFrame]): List of pandas DataFrames, one per sequence.
|
|
100
|
+
target (str): The target column name.
|
|
101
|
+
drop (Optional[Union[str, List[str]]]): Column(s) to drop from the
|
|
102
|
+
DataFrames before extracting features. If a listed column is
|
|
103
|
+
missing, no column is dropped. Defaults to None.
|
|
104
|
+
dtype (torch.dtype): Data type for the tensors. Defaults to ``torch.float32``.
|
|
105
|
+
|
|
106
|
+
Attributes:
|
|
107
|
+
data (List[pd.DataFrame]): DataFrames with the ``drop`` columns removed.
|
|
108
|
+
target (List[torch.Tensor]): Per-sequence scalar target tensors.
|
|
109
|
+
features (List[torch.Tensor]): Per-sequence feature tensors, shape
|
|
110
|
+
``(T_i, n_features)``.
|
|
111
|
+
|
|
112
|
+
Examples:
|
|
113
|
+
```{python}
|
|
114
|
+
import pandas as pd
|
|
115
|
+
from spotoptim.data.manydataset import ManyToOneDataset
|
|
116
|
+
|
|
117
|
+
df1 = pd.DataFrame({"x": [1.0, 2.0, 3.0], "y": [5.0, 5.0, 5.0]})
|
|
118
|
+
df2 = pd.DataFrame({"x": [4.0, 5.0], "y": [7.0, 7.0]})
|
|
119
|
+
ds = ManyToOneDataset([df1, df2], target="y")
|
|
120
|
+
features, target = ds[1]
|
|
121
|
+
print(features.shape, target)
|
|
122
|
+
```
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
def __init__(
|
|
126
|
+
self,
|
|
127
|
+
df_list: List[pd.DataFrame],
|
|
128
|
+
target: str,
|
|
129
|
+
drop: Optional[Union[str, List[str]]] = None,
|
|
130
|
+
dtype: torch.dtype = torch.float32,
|
|
131
|
+
):
|
|
132
|
+
if drop is None:
|
|
133
|
+
self.data = list(df_list)
|
|
134
|
+
else:
|
|
135
|
+
try:
|
|
136
|
+
self.data = [df.drop(drop, axis=1) for df in df_list]
|
|
137
|
+
except KeyError:
|
|
138
|
+
self.data = df_list
|
|
139
|
+
self.target = [
|
|
140
|
+
torch.tensor(df[target].to_numpy()[0], dtype=dtype) for df in self.data
|
|
141
|
+
]
|
|
142
|
+
self.features = [
|
|
143
|
+
torch.tensor(df.drop([target], axis=1).to_numpy(), dtype=dtype)
|
|
144
|
+
for df in self.data
|
|
145
|
+
]
|
|
146
|
+
|
|
147
|
+
def __getitem__(self, index: int):
|
|
148
|
+
"""Return the ``(features, target)`` pair of sequence ``index``."""
|
|
149
|
+
x = self.features[index]
|
|
150
|
+
y = self.target[index]
|
|
151
|
+
return x, y
|
|
152
|
+
|
|
153
|
+
def __len__(self) -> int:
|
|
154
|
+
"""Return the number of sequences."""
|
|
155
|
+
return len(self.data)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
class PadSequenceManyToMany:
|
|
159
|
+
"""Padding collate for `ManyToManyDataset` batches.
|
|
160
|
+
|
|
161
|
+
Pads features and targets of a batch of variable-length sequences with
|
|
162
|
+
zeros to the longest sequence in the batch and records the true lengths,
|
|
163
|
+
as required by ``torch.nn.utils.rnn.pack_padded_sequence``.
|
|
164
|
+
|
|
165
|
+
Examples:
|
|
166
|
+
```{python}
|
|
167
|
+
import pandas as pd
|
|
168
|
+
from torch.utils.data import DataLoader
|
|
169
|
+
from spotoptim.data.manydataset import ManyToManyDataset, PadSequenceManyToMany
|
|
170
|
+
|
|
171
|
+
df1 = pd.DataFrame({"x": [1.0, 2.0, 3.0], "y": [2.0, 4.0, 6.0]})
|
|
172
|
+
df2 = pd.DataFrame({"x": [4.0, 5.0], "y": [8.0, 10.0]})
|
|
173
|
+
ds = ManyToManyDataset([df1, df2], target="y")
|
|
174
|
+
dl = DataLoader(ds, batch_size=2, shuffle=False, collate_fn=PadSequenceManyToMany())
|
|
175
|
+
x, lengths, y = next(iter(dl))
|
|
176
|
+
print(x.shape, lengths.tolist(), y.shape)
|
|
177
|
+
```
|
|
178
|
+
"""
|
|
179
|
+
|
|
180
|
+
def __call__(self, batch):
|
|
181
|
+
"""Collate a batch into ``(padded_x, lengths, padded_y)``.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
batch: Sequence of ``(features, targets)`` pairs as produced by
|
|
185
|
+
`ManyToManyDataset`.
|
|
186
|
+
|
|
187
|
+
Returns:
|
|
188
|
+
tuple: ``(padded_x, lengths, padded_y)`` where ``padded_x`` has
|
|
189
|
+
shape ``(B, T_max, n_features)``, ``lengths`` is an int tensor of
|
|
190
|
+
shape ``(B,)``, and ``padded_y`` has shape ``(B, T_max)``.
|
|
191
|
+
"""
|
|
192
|
+
batch_x, batch_y = zip(*batch)
|
|
193
|
+
padded_batch_x = pad_sequence(list(batch_x), batch_first=True)
|
|
194
|
+
padded_batch_y = pad_sequence(list(batch_y), batch_first=True)
|
|
195
|
+
lengths = torch.tensor([len(x) for x in batch_x])
|
|
196
|
+
|
|
197
|
+
return padded_batch_x, lengths, padded_batch_y
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
class PadSequenceManyToOne:
|
|
201
|
+
"""Padding collate for `ManyToOneDataset` batches.
|
|
202
|
+
|
|
203
|
+
Pads the feature sequences with zeros and stacks the scalar targets.
|
|
204
|
+
|
|
205
|
+
Examples:
|
|
206
|
+
```{python}
|
|
207
|
+
import pandas as pd
|
|
208
|
+
from torch.utils.data import DataLoader
|
|
209
|
+
from spotoptim.data.manydataset import ManyToOneDataset, PadSequenceManyToOne
|
|
210
|
+
|
|
211
|
+
df1 = pd.DataFrame({"x": [1.0, 2.0, 3.0], "y": [5.0, 5.0, 5.0]})
|
|
212
|
+
df2 = pd.DataFrame({"x": [4.0, 5.0], "y": [7.0, 7.0]})
|
|
213
|
+
ds = ManyToOneDataset([df1, df2], target="y")
|
|
214
|
+
dl = DataLoader(ds, batch_size=2, shuffle=False, collate_fn=PadSequenceManyToOne())
|
|
215
|
+
x, lengths, y = next(iter(dl))
|
|
216
|
+
print(x.shape, lengths.tolist(), y.shape)
|
|
217
|
+
```
|
|
218
|
+
"""
|
|
219
|
+
|
|
220
|
+
def __call__(self, batch):
|
|
221
|
+
"""Collate a batch into ``(padded_x, lengths, y)``.
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
batch: Sequence of ``(features, target)`` pairs as produced by
|
|
225
|
+
`ManyToOneDataset`.
|
|
226
|
+
|
|
227
|
+
Returns:
|
|
228
|
+
tuple: ``(padded_x, lengths, y)`` where ``padded_x`` has shape
|
|
229
|
+
``(B, T_max, n_features)``, ``lengths`` is an int tensor of shape
|
|
230
|
+
``(B,)``, and ``y`` is a tensor of shape ``(B,)``.
|
|
231
|
+
"""
|
|
232
|
+
batch_x, batch_y = zip(*batch)
|
|
233
|
+
padded_batch_x = pad_sequence(list(batch_x), batch_first=True)
|
|
234
|
+
lengths = torch.tensor([len(x) for x in batch_x])
|
|
235
|
+
|
|
236
|
+
return padded_batch_x, lengths, torch.tensor(batch_y)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def load_sequence_data(
|
|
240
|
+
data: pd.DataFrame,
|
|
241
|
+
target: str,
|
|
242
|
+
group_by: str,
|
|
243
|
+
drop: Optional[Union[str, List[str]]] = None,
|
|
244
|
+
input_features: Optional[List[str]] = None,
|
|
245
|
+
feature_scaling=None,
|
|
246
|
+
target_scaling=None,
|
|
247
|
+
dataset_type: str = "many_to_many",
|
|
248
|
+
) -> Tuple[Dataset, pd.DataFrame]:
|
|
249
|
+
"""Group a DataFrame into a variable-length sequence dataset.
|
|
250
|
+
|
|
251
|
+
Splits ``data`` by the values of ``group_by`` (e.g. one compressor speed
|
|
252
|
+
line per group) and wraps the groups in a `ManyToManyDataset` or
|
|
253
|
+
`ManyToOneDataset`. Ported from the schu25a study's ``load_data`` helper
|
|
254
|
+
(``src/rnn/utils.py``); the experiment-specific column defaults were
|
|
255
|
+
removed.
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
data (pd.DataFrame): Input data; one row per time step.
|
|
259
|
+
target (str): The target column name.
|
|
260
|
+
group_by (str): Column whose values define the sequences.
|
|
261
|
+
drop (Optional[Union[str, List[str]]]): Column(s) to drop from the
|
|
262
|
+
groups before extracting features. Defaults to None.
|
|
263
|
+
input_features (Optional[List[str]]): Columns scaled by
|
|
264
|
+
``feature_scaling``. Only used when ``feature_scaling`` is given;
|
|
265
|
+
the dataset features are always all columns except ``drop`` and
|
|
266
|
+
``target``. Defaults to None.
|
|
267
|
+
feature_scaling: Optional sklearn-style scaler; applied in place to
|
|
268
|
+
``data[input_features]`` via ``fit_transform``. Defaults to None.
|
|
269
|
+
target_scaling: Optional sklearn-style scaler; applied in place to
|
|
270
|
+
``data[target]`` via ``fit_transform``. Defaults to None.
|
|
271
|
+
dataset_type (str, optional): Dataset flavor. Options:
|
|
272
|
+
- "many_to_many": one target value per time step.
|
|
273
|
+
- "many_to_one": one scalar target per sequence.
|
|
274
|
+
Defaults to "many_to_many".
|
|
275
|
+
|
|
276
|
+
Returns:
|
|
277
|
+
tuple: ``(dataset, data)`` — the sequence dataset and the (possibly
|
|
278
|
+
scaled) DataFrame.
|
|
279
|
+
|
|
280
|
+
Raises:
|
|
281
|
+
ValueError: If ``dataset_type`` is not "many_to_many" or "many_to_one".
|
|
282
|
+
|
|
283
|
+
Examples:
|
|
284
|
+
```{python}
|
|
285
|
+
import pandas as pd
|
|
286
|
+
from spotoptim.data.manydataset import load_sequence_data
|
|
287
|
+
|
|
288
|
+
df = pd.DataFrame({
|
|
289
|
+
"line": [1, 1, 1, 2, 2],
|
|
290
|
+
"x": [0.1, 0.2, 0.3, 0.4, 0.5],
|
|
291
|
+
"y": [1.0, 2.0, 3.0, 4.0, 5.0],
|
|
292
|
+
})
|
|
293
|
+
ds, df = load_sequence_data(df, target="y", group_by="line", drop="line")
|
|
294
|
+
print(len(ds), ds[0][0].shape)
|
|
295
|
+
```
|
|
296
|
+
"""
|
|
297
|
+
if feature_scaling is not None:
|
|
298
|
+
data[input_features] = feature_scaling.fit_transform(data[input_features])
|
|
299
|
+
|
|
300
|
+
if target_scaling is not None:
|
|
301
|
+
data[target] = target_scaling.fit_transform(data[target])
|
|
302
|
+
|
|
303
|
+
groups = [group for _, group in data.groupby(group_by)]
|
|
304
|
+
|
|
305
|
+
if dataset_type == "many_to_many":
|
|
306
|
+
return ManyToManyDataset(groups, target=target, drop=drop), data
|
|
307
|
+
elif dataset_type == "many_to_one":
|
|
308
|
+
return ManyToOneDataset(groups, target=target, drop=drop), data
|
|
309
|
+
raise ValueError(
|
|
310
|
+
f"dataset_type {dataset_type!r} not supported. "
|
|
311
|
+
"Options: 'many_to_many', 'many_to_one'."
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def load_pooled_sequence_data(
|
|
316
|
+
data_list: List[pd.DataFrame],
|
|
317
|
+
target: str,
|
|
318
|
+
group_by: str,
|
|
319
|
+
drop: Optional[Union[str, List[str]]] = None,
|
|
320
|
+
input_features: Optional[List[str]] = None,
|
|
321
|
+
feature_scaling=None,
|
|
322
|
+
target_scaling=None,
|
|
323
|
+
dataset_type: str = "many_to_many",
|
|
324
|
+
) -> ConcatDataset:
|
|
325
|
+
"""Pool several DataFrames into one concatenated sequence dataset.
|
|
326
|
+
|
|
327
|
+
Applies `load_sequence_data` to every DataFrame (e.g. one compressor map
|
|
328
|
+
each) and concatenates the resulting sequence datasets — the pooled
|
|
329
|
+
training set of the schu25a "global training" workflow (ported from
|
|
330
|
+
``load_pretrain_data`` in ``src/rnn/utils.py``).
|
|
331
|
+
|
|
332
|
+
Args:
|
|
333
|
+
data_list (List[pd.DataFrame]): Input DataFrames; one per map.
|
|
334
|
+
target (str): The target column name.
|
|
335
|
+
group_by (str): Column whose values define the sequences.
|
|
336
|
+
drop (Optional[Union[str, List[str]]]): Column(s) to drop from the
|
|
337
|
+
groups before extracting features. Defaults to None.
|
|
338
|
+
input_features (Optional[List[str]]): Columns scaled by
|
|
339
|
+
``feature_scaling``; see `load_sequence_data`. Defaults to None.
|
|
340
|
+
feature_scaling: Optional sklearn-style scaler, applied per DataFrame.
|
|
341
|
+
Defaults to None.
|
|
342
|
+
target_scaling: Optional sklearn-style scaler, applied per DataFrame.
|
|
343
|
+
Defaults to None.
|
|
344
|
+
dataset_type (str, optional): "many_to_many" or "many_to_one".
|
|
345
|
+
Defaults to "many_to_many".
|
|
346
|
+
|
|
347
|
+
Returns:
|
|
348
|
+
ConcatDataset: The concatenation of the per-DataFrame sequence datasets.
|
|
349
|
+
|
|
350
|
+
Examples:
|
|
351
|
+
```{python}
|
|
352
|
+
import pandas as pd
|
|
353
|
+
from spotoptim.data.manydataset import load_pooled_sequence_data
|
|
354
|
+
|
|
355
|
+
df1 = pd.DataFrame({"line": [1, 1, 2], "x": [0.1, 0.2, 0.3], "y": [1.0, 2.0, 3.0]})
|
|
356
|
+
df2 = pd.DataFrame({"line": [1, 1], "x": [0.4, 0.5], "y": [4.0, 5.0]})
|
|
357
|
+
pooled = load_pooled_sequence_data([df1, df2], target="y", group_by="line", drop="line")
|
|
358
|
+
print(len(pooled))
|
|
359
|
+
```
|
|
360
|
+
"""
|
|
361
|
+
ds_ls = []
|
|
362
|
+
for data in data_list:
|
|
363
|
+
ds, _ = load_sequence_data(
|
|
364
|
+
data,
|
|
365
|
+
target=target,
|
|
366
|
+
group_by=group_by,
|
|
367
|
+
drop=drop,
|
|
368
|
+
input_features=input_features,
|
|
369
|
+
feature_scaling=feature_scaling,
|
|
370
|
+
target_scaling=target_scaling,
|
|
371
|
+
dataset_type=dataset_type,
|
|
372
|
+
)
|
|
373
|
+
ds_ls.append(ds)
|
|
374
|
+
|
|
375
|
+
return ConcatDataset(ds_ls)
|
|
@@ -69,11 +69,16 @@ __all__ = [
|
|
|
69
69
|
"branin",
|
|
70
70
|
"onevar",
|
|
71
71
|
"TorchObjective",
|
|
72
|
+
"SequenceCVObjective",
|
|
72
73
|
"objective_remote",
|
|
73
74
|
]
|
|
74
75
|
|
|
75
76
|
_lazy_map = {
|
|
76
77
|
"TorchObjective": ("spotoptim.function.torch_objective", "TorchObjective"),
|
|
78
|
+
"SequenceCVObjective": (
|
|
79
|
+
"spotoptim.function.sequence_cv_objective",
|
|
80
|
+
"SequenceCVObjective",
|
|
81
|
+
),
|
|
77
82
|
"objective_remote": ("spotoptim.function.remote", "objective_remote"),
|
|
78
83
|
}
|
|
79
84
|
|