Skip to content

Commit 85a5826

Browse files
committed
Add BayesianOptimizerOutputEvaluator
1 parent 8ab8600 commit 85a5826

File tree

5 files changed

+294
-261
lines changed

5 files changed

+294
-261
lines changed

climada/test/test_util_calibrate.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,13 @@
1111

1212
from climada.entity import ImpactFuncSet, ImpactFunc
1313

14-
from climada.util.calibrate import Input, ScipyMinimizeOptimizer, BayesianOptimizer, OutputEvaluator
14+
from climada.util.calibrate import (
15+
Input,
16+
ScipyMinimizeOptimizer,
17+
BayesianOptimizer,
18+
OutputEvaluator,
19+
BayesianOptimizerOutputEvaluator,
20+
)
1521

1622
from climada.util.calibrate.test.test_base import hazard, exposure
1723

@@ -213,6 +219,8 @@ def test_plots(self):
213219
output_eval.impf_set.plot()
214220
output_eval.plot_at_event()
215221
output_eval.plot_at_region()
222+
output_eval.plot_event_region_heatmap()
223+
224+
output_eval = BayesianOptimizerOutputEvaluator(self.input, output)
216225
ax = output_eval.plot_impf_variability()
217226
self.assertIsInstance(ax, Axes)
218-
output_eval.plot_event_region_heatmap()

climada/util/calibrate/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
"""Impact function calibration module"""
22

33
from .base import Input, OutputEvaluator
4-
from .bayesian_optimizer import BayesianOptimizer
4+
from .bayesian_optimizer import BayesianOptimizer, BayesianOptimizerOutputEvaluator
55
from .scipy_optimizer import ScipyMinimizeOptimizer
6-
from .func import rmse, rmsf, impact_at_reg

climada/util/calibrate/base.py

Lines changed: 0 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -201,142 +201,6 @@ def __post_init__(self):
201201
).impact(assign_centroids=True, save_mat=True)
202202
self._impact_label = f"Impact [{self.input.exposure.value_unit}]"
203203

204-
def plot_impf_variability(
205-
self,
206-
cost_func_diff: float = 0.1,
207-
p_space_df: Optional[pd.DataFrame] = None,
208-
plot_haz: bool = True,
209-
plot_impf_kws: Optional[dict] = None,
210-
plot_hist_kws: Optional[dict] = None,
211-
):
212-
"""Plot impact function variability with parameter combinations of
213-
almost equal cost function values
214-
215-
Args:
216-
cost_func_diff (float, optional): Max deviation from optimal cost
217-
function value (as fraction). Defaults to 0.1 (i.e. 10%).
218-
p_space_df (pd.DataFrame, optional): parameter space. Defaults to None.
219-
plot_haz (bool, optional): Whether or not to plot hazard intensity
220-
distibution. Defaults to False.
221-
plot_impf_kws (dict, optional): Keyword arguments for impact
222-
function plot. Defaults to None.
223-
plot_hist_kws (dict, optional): Keyword arguments for hazard
224-
intensity distribution plot. Defaults to None.
225-
"""
226-
227-
# Initialize plot keyword arguments
228-
if plot_impf_kws is None:
229-
plot_impf_kws = {}
230-
if plot_hist_kws is None:
231-
plot_hist_kws = {}
232-
233-
# Retrieve hazard type and parameter space
234-
haz_type = self.input.hazard.haz_type
235-
if p_space_df is None:
236-
# Assert that self.output has the p_space_to_dataframe() method,
237-
# which is defined for the BayesianOptimizerOutput class
238-
if not hasattr(self.output, "p_space_to_dataframe"):
239-
raise TypeError(
240-
"To derive the full impact function parameter space, "
241-
"plot_impf_variability() requires BayesianOptimizerOutput "
242-
"as OutputEvaluator.output attribute, which provides the "
243-
"method p_space_to_dataframe()."
244-
)
245-
p_space_df = self.output.p_space_to_dataframe()
246-
247-
# Retrieve parameters of impact functions with cost function values
248-
# within 'cost_func_diff' % of the best estimate
249-
params_within_range = p_space_df["Parameters"]
250-
plot_space_label = "Parameter space"
251-
if cost_func_diff is not None:
252-
max_cost_func_val = p_space_df["Calibration", "Cost Function"].min() * (
253-
1 + cost_func_diff
254-
)
255-
params_within_range = params_within_range.loc[
256-
p_space_df["Calibration", "Cost Function"] <= max_cost_func_val
257-
]
258-
plot_space_label = (
259-
f"within {int(cost_func_diff*100)} percent " f"of best fit"
260-
)
261-
262-
# Set plot defaults
263-
color = plot_impf_kws.pop("color", "tab:blue")
264-
lw = plot_impf_kws.pop("lw", 2)
265-
zorder = plot_impf_kws.pop("zorder", 3)
266-
label = plot_impf_kws.pop("label", "best fit")
267-
268-
# get number of impact functions and create a plot for each
269-
n_impf = len(self.impf_set.get_func(haz_type=haz_type))
270-
axes = []
271-
272-
for impf_idx in range(n_impf):
273-
_, ax = plt.subplots()
274-
275-
# Plot best-fit impact function
276-
best_impf = self.impf_set.get_func(haz_type=haz_type)[impf_idx]
277-
ax.plot(
278-
best_impf.intensity,
279-
best_impf.mdd * best_impf.paa * 100,
280-
color=color,
281-
lw=lw,
282-
zorder=zorder,
283-
label=label,
284-
**plot_impf_kws,
285-
)
286-
287-
# Plot all impact functions within 'cost_func_diff' % of best estimate
288-
for row in range(params_within_range.shape[0]):
289-
label_temp = plot_space_label if row == 0 else None
290-
291-
sel_params = params_within_range.iloc[row, :].to_dict()
292-
temp_impf_set = self.input.impact_func_creator(**sel_params)
293-
temp_impf = temp_impf_set.get_func(haz_type=haz_type)[impf_idx]
294-
295-
ax.plot(
296-
temp_impf.intensity,
297-
temp_impf.mdd * temp_impf.paa * 100,
298-
color="grey",
299-
alpha=0.4,
300-
label=label_temp,
301-
)
302-
303-
# Plot hazard intensity value distributions
304-
if plot_haz:
305-
haz_vals = self.input.hazard.intensity[
306-
:, self.input.exposure.gdf[f"centr_{haz_type}"]
307-
]
308-
309-
# Plot defaults
310-
color_hist = plot_hist_kws.pop("color", "tab:orange")
311-
alpha_hist = plot_hist_kws.pop("alpha", 0.3)
312-
313-
ax2 = ax.twinx()
314-
ax2.hist(
315-
haz_vals.data,
316-
bins=40,
317-
color=color_hist,
318-
alpha=alpha_hist,
319-
label="Hazard intensity\noccurence",
320-
)
321-
ax2.set(ylabel="Hazard intensity occurence (#Exposure points)")
322-
ax.axvline(
323-
x=haz_vals.max(), label="Maximum hazard value", color="tab:orange"
324-
)
325-
ax2.legend(loc="lower right")
326-
327-
ax.set(
328-
xlabel=f"Intensity ({self.input.hazard.units})",
329-
ylabel="Mean Damage Ratio (MDR) in %",
330-
xlim=(min(best_impf.intensity), max(best_impf.intensity)),
331-
)
332-
ax.legend()
333-
axes.append(ax)
334-
335-
if n_impf > 1:
336-
return axes
337-
338-
return ax
339-
340204
def plot_at_event(
341205
self,
342206
data_transf: Callable[[pd.DataFrame], pd.DataFrame] = lambda x: x,

0 commit comments

Comments
 (0)