Skip to content

Commit 3b504cd

Browse files
v0.0.16
1 parent ebf33dd commit 3b504cd

6 files changed

Lines changed: 362 additions & 27 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
77

88
[project]
99
name = "spotPython"
10-
version = "0.0.15"
10+
version = "0.0.16"
1111
authors = [
1212
{ name="T. Bartz-Beielstein", email="tbb@bartzundbartz.de" }
1313
]

src/spotPython/hyperparameters/categorical.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,15 @@ def add_missing_elements(a: list, b: list) -> list:
107107
def find_closest_key(integer_value: int, encoding_dict: dict) -> str:
108108
"""
109109
Given an integer value and an encoding dictionary that maps keys to binary values,
110-
this function finds the key in the dictionary whose binary value is closest to the binary representation of the integer value.
110+
this function finds the key in the dictionary whose binary value is closest to the binary
111+
representation of the integer value.
111112
112113
Arguments:
113114
integer_value (int): The integer value to find the closest key for.
114115
encoding_dict (dict): The encoding dictionary that maps keys to binary values.
115116
Returns:
116-
str: The key in the encoding dictionary whose binary value is closest to the binary representation of the integer value.
117+
str: The key in the encoding dictionary whose binary value is
118+
closest to the binary representation of the integer value.
117119
Example:
118120
>>> encoding_dict = {'A': [1, 0, 0], 'B': [0, 1, 0], 'C': [0, 0, 1]}
119121
find_closest_key(6, encoding_dict)

src/spotPython/hyperparameters/levels.py

Lines changed: 0 additions & 22 deletions
This file was deleted.
Lines changed: 310 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,310 @@
1+
from spotPython.utils.convert import class_for_name
2+
import numpy as np
3+
4+
5+
def modify_hyper_parameter_levels(fun_control, hyperparameter, levels):
6+
"""
7+
8+
Args:
9+
fun_control (dict): fun_control dictionary
10+
hyperparameter (str): hyperparameter name
11+
levels (list): list of levels
12+
13+
Returns:
14+
fun_control (dict): updated fun_control
15+
Example:
16+
>>> fun_control = {}
17+
core_model = HoeffdingTreeRegressor
18+
fun_control.update({"core_model": core_model})
19+
fun_control.update({"core_model_hyper_dict": river_hyper_dict[core_model.__name__]})
20+
levels = ["mean", "model"]
21+
fun_control = modify_hyper_parameter_levels(fun_control, "leaf_prediction", levels)
22+
"""
23+
fun_control["core_model_hyper_dict"][hyperparameter].update({"levels": levels})
24+
fun_control["core_model_hyper_dict"][hyperparameter].update({"lower": 0})
25+
fun_control["core_model_hyper_dict"][hyperparameter].update({"upper": len(levels) - 1})
26+
return fun_control
27+
28+
29+
def modify_hyper_parameter_bounds(fun_control, hyperparameter, bounds):
30+
"""
31+
32+
Args:
33+
fun_control (dict): fun_control dictionary
34+
hyperparameter (str): hyperparameter name
35+
bounds (list): list of two bound values. The first value represents the lower bound
36+
and the second value represents the upper bound.
37+
38+
Returns:
39+
fun_control (dict): updated fun_control
40+
Example:
41+
>>> fun_control = {}
42+
core_model = HoeffdingTreeRegressor
43+
fun_control.update({"core_model": core_model})
44+
fun_control.update({"core_model_hyper_dict": river_hyper_dict[core_model.__name__]})
45+
bounds = [3, 11]
46+
fun_control = modify_hyper_parameter_levels(fun_control, "min_samples_split", bounds)
47+
"""
48+
fun_control["core_model_hyper_dict"][hyperparameter].update({"lower": bounds[0]})
49+
fun_control["core_model_hyper_dict"][hyperparameter].update({"upper": bounds[1]})
50+
return fun_control
51+
52+
53+
def get_dict_with_levels_and_types(fun_control, v):
54+
"""Get dictionary with levels and types.
55+
The function is maps the numerical output of the hyperparameter optimization to the corresponding levels
56+
of the hyperparameter needed by the core model, i.e., the tuned algorithm.
57+
The function takes the dictionaries d and v and returns a new dictionary with the same keys as v
58+
but with the values of the levels of the keys from d.
59+
If the key value in the dictionary is 0, it takes the first value from the list,
60+
if it is 1, it takes the second and so on.
61+
If a key is not in d, it takes the key from v.
62+
If the core_model_parameter_type value is instance, it returns the class of the value from the module
63+
via getattr("class", value).
64+
For example,
65+
if d = {"HoeffdingTreeRegressor":{
66+
"leaf_prediction": {
67+
"levels": ["mean", "model", "adaptive"],
68+
"type": "factor",
69+
"default": "mean",
70+
"core_model_parameter_type": "str"},
71+
"leaf_model": {
72+
"levels": ["linear_model.LinearRegression", "linear_model.PARegressor", "linear_model.Perceptron"],
73+
"type": "factor",
74+
"default": "LinearRegression",
75+
"core_model_parameter_type": "instance"},
76+
"splitter": {"levels": ["EBSTSplitter", "TEBSTSplitter", "QOSplitter"],
77+
"type": "factor",
78+
"default": "EBSTSplitter", "core_model_parameter_type": "instance()"},
79+
"binary_split": {
80+
"levels": [0, 1],
81+
"type": "factor",
82+
"default": 0,
83+
"core_model_parameter_type": "bool"},
84+
"stop_mem_management": {
85+
"levels": [0, 1],
86+
"type": "factor",
87+
"default": 0,
88+
"core_model_parameter_type": "bool"}}}
89+
and
90+
v = {'grace_period': 200,
91+
'max_depth': 10,
92+
'delta': 1e-07,
93+
'tau': 0.05,
94+
'leaf_prediction': 0,
95+
'leaf_model': 0,
96+
'model_selector_decay': 0.95,
97+
'splitter': 1,
98+
'min_samples_split': 9,
99+
'binary_split': 0,
100+
'max_size': 500.0}
101+
then the function returns
102+
{'grace_period': 200,
103+
'max_depth': 10,
104+
'delta': 1e-07,
105+
'tau': 0.05,
106+
'leaf_prediction': 'mean',
107+
'leaf_model': linear_model.LinearRegression,
108+
'model_selector_decay': 0.95,
109+
'splitter': 'TEBSTSplitter',
110+
'min_samples_split': 9,
111+
'binary_split': 0,
112+
'max_size': 500.0}.
113+
114+
Args:
115+
fun_control (dict): dictionary with levels and types
116+
v (dict): dictionary with values
117+
118+
Returns:
119+
new_dict (dict): dictionary with levels and types
120+
121+
Example:
122+
>>> d = {"HoeffdingTreeRegressor":{
123+
"leaf_prediction": {"levels": ["mean", "model", "adaptive"],
124+
"type": "factor",
125+
"default": "mean",
126+
"core_model_parameter_type": "str"}}}
127+
v = {"leaf_prediction": 0}
128+
get_dict_with_levels_and_types(d, v)
129+
{"leaf_prediction": "mean"}
130+
"""
131+
d = fun_control["core_model_hyper_dict"]
132+
new_dict = {}
133+
for key, value in v.items():
134+
if key in d and d[key]["type"] == "factor":
135+
if d[key]["core_model_parameter_type"] == "instance":
136+
if "class_name" in d[key]:
137+
mdl = d[key]["class_name"]
138+
c = d[key]["levels"][value]
139+
new_dict[key] = class_for_name(mdl, c)
140+
elif d[key]["core_model_parameter_type"] == "instance()":
141+
mdl = d[key]["class_name"]
142+
c = d[key]["levels"][value]
143+
k = class_for_name(mdl, c)
144+
new_dict[key] = k()
145+
else:
146+
new_dict[key] = d[key]["levels"][value]
147+
else:
148+
new_dict[key] = v[key]
149+
return new_dict
150+
151+
152+
def get_default_values(fun_control):
153+
"""Get the values from the "default" keys from the dictionary fun_control as a list.
154+
If the key of the value has as "type" the value "int" or "float", convert the value to the corresponding type.
155+
Args:
156+
fun_control (dict): dictionary with levels and types
157+
Returns:
158+
new_dict (dict): dictionary with default values
159+
Example:
160+
>>> d = {"core_model_hyper_dict":{
161+
"leaf_prediction": {
162+
"levels": ["mean", "model", "adaptive"],
163+
"type": "factor",
164+
"default": "mean",
165+
"core_model_parameter_type": "str"},
166+
"leaf_model": {
167+
"levels": ["linear_model.LinearRegression", "linear_model.PARegressor", "linear_model.Perceptron"],
168+
"type": "factor",
169+
"default": "LinearRegression",
170+
"core_model_parameter_type": "instance"},
171+
"splitter": {
172+
"levels": ["EBSTSplitter", "TEBSTSplitter", "QOSplitter"],
173+
"type": "factor",
174+
"default": "EBSTSplitter",
175+
"core_model_parameter_type": "instance()"},
176+
"binary_split": {
177+
"levels": [0, 1],
178+
"type": "factor",
179+
"default": 0,
180+
"core_model_parameter_type": "bool"},
181+
"stop_mem_management": {
182+
"levels": [0, 1],
183+
"type": "factor",
184+
"default": 0,
185+
"core_model_parameter_type": "bool"}}}
186+
get_default_values_from_dict(d)
187+
{'leaf_prediction': 'mean',
188+
'leaf_model': 'linear_model.LinearRegression',
189+
'splitter': 'EBSTSplitter',
190+
'binary_split': 0,
191+
'stop_mem_management': 0}
192+
"""
193+
d = fun_control["core_model_hyper_dict"]
194+
new_dict = {}
195+
for key, value in d.items():
196+
if value["type"] == "int":
197+
new_dict[key] = int(value["default"])
198+
elif value["type"] == "float":
199+
new_dict[key] = float(value["default"])
200+
else:
201+
new_dict[key] = value["default"]
202+
return new_dict
203+
204+
205+
def get_var_type(fun_control):
206+
"""Get the types of the values from the dictionary fun_control as a list.
207+
Args:
208+
fun_control (dict): dictionary with levels and types
209+
Returns:
210+
(list): list with types
211+
Example:
212+
>>> d = {"core_model_hyper_dict":{
213+
"leaf_prediction": {
214+
"levels": ["mean", "model", "adaptive"],
215+
"type": "factor",
216+
"default": "mean",
217+
"core_model_parameter_type": "str"},
218+
"leaf_model": {
219+
"levels": ["linear_model.LinearRegression", "linear_model.PARegressor", "linear_model.Perceptron"],
220+
"type": "factor",
221+
"default": "LinearRegression",
222+
"core_model_parameter_type": "instance"},
223+
"splitter": {
224+
"levels": ["EBSTSplitter", "TEBSTSplitter", "QOSplitter"],
225+
"type": "factor",
226+
"default": "EBSTSplitter",
227+
"core_model_parameter_type": "instance()"},
228+
"binary_split": {
229+
"levels": [0, 1],
230+
"type": "factor",
231+
"default": 0,
232+
"core_model_parameter_type": "bool"},
233+
"stop_mem_management": { "levels": [0, 1],
234+
"type": "factor",
235+
"default": 0,
236+
"core_model_parameter_type": "bool"}}}
237+
238+
get_var_type(d)
239+
['factor', 'factor', 'factor', 'factor', 'factor']
240+
"""
241+
return list(
242+
fun_control["core_model_hyper_dict"][key]["type"] for key in fun_control["core_model_hyper_dict"].keys()
243+
)
244+
245+
246+
def get_var_name(fun_control):
247+
"""Get the names of the values from the dictionary fun_control as a list.
248+
Args:
249+
fun_control (dict): dictionary with names
250+
Returns:
251+
(list): list with names
252+
Example:
253+
>>> d = {"core_model_hyper_dict":{
254+
"leaf_prediction": {
255+
"levels": ["mean", "model", "adaptive"],
256+
"type": "factor",
257+
"default": "mean",
258+
"core_model_parameter_type": "str"},
259+
"leaf_model": {
260+
"levels": ["linear_model.LinearRegression", "linear_model.PARegressor", "linear_model.Perceptron"],
261+
"type": "factor",
262+
"default": "LinearRegression",
263+
"core_model_parameter_type": "instance"},
264+
"splitter": {
265+
"levels": ["EBSTSplitter", "TEBSTSplitter", "QOSplitter"],
266+
"type": "factor",
267+
"default": "EBSTSplitter",
268+
"core_model_parameter_type": "instance()"},
269+
"binary_split": {
270+
"levels": [0, 1],
271+
"type": "factor",
272+
"default": 0,
273+
"core_model_parameter_type": "bool"},
274+
"stop_mem_management": { "levels": [0, 1],
275+
"type": "factor",
276+
"default": 0,
277+
"core_model_parameter_type": "bool"}}}
278+
279+
get_var_name(d)
280+
['leaf_prediction', 'leaf_model', 'splitter', 'binary_split', 'stop_mem_management']
281+
"""
282+
return list(fun_control["core_model_hyper_dict"].keys())
283+
284+
285+
def get_bound_values(fun_control: dict, bound: str, as_list=False) -> list or np.array:
286+
"""Generate a list from a dictionary.
287+
It takes the values from the keys "bound" in the
288+
fun_control[]"core_model_hyper_dict"] dictionary and
289+
returns a list of the values in the same order as the keys in the
290+
dictionary.
291+
For example if the dictionary is
292+
{"a": {"upper": 1}, "b": {"upper": 2}}
293+
the list is [1, 2] if bound="upper".
294+
Args:
295+
fun_control (dict): dictionary with upper values
296+
bound (str): either "upper" or "lower"
297+
Returns:
298+
(list): list with lower or upper values
299+
"""
300+
# Throw value error if bound is not upper or lower:
301+
if bound not in ["upper", "lower"]:
302+
raise ValueError("bound must be either 'upper' or 'lower'")
303+
d = fun_control["core_model_hyper_dict"]
304+
b = []
305+
for key, value in d.items():
306+
b.append(value[bound])
307+
if as_list:
308+
return b
309+
else:
310+
return np.array(b)

src/spotPython/spot/spot.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from numpy import ravel
1919
from numpy import array
2020
from numpy import append
21-
from spotPython.utils.compare import selectNew, find_equal_in_lists
21+
from spotPython.utils.compare import selectNew
2222
from spotPython.utils.aggregate import aggregate_mean_var
2323
from spotPython.utils.repair import remove_nan
2424
from spotPython.budget.ocba import get_ocba_X
@@ -251,7 +251,7 @@ def __init__(
251251
def to_red_dim(self):
252252
self.all_lower = self.lower
253253
self.all_upper = self.upper
254-
self.ident = find_equal_in_lists(a=self.lower, b=self.upper)
254+
self.ident = (self.upper - self.lower) == 0
255255
self.lower = self.lower[~self.ident]
256256
self.upper = self.upper[~self.ident]
257257
self.red_dim = self.ident.any()

0 commit comments

Comments
 (0)