# Example for using the multi target mode for the objective Example for using the multi target mode for the objective. It uses a desirability value to handle several targets. This example assumes some basic familiarity with using BayBE. We thus refer to [`campaign`](./../Basics/campaign.md) for a basic example. ## Necessary imports for this example ```python import pandas as pd ``` ```python from baybe import Campaign from baybe.objectives import DesirabilityObjective from baybe.parameters import CategoricalParameter, NumericalDiscreteParameter from baybe.searchspace import SearchSpace from baybe.targets import NumericalTarget from baybe.utils.dataframe import add_fake_results ``` ## Experiment setup and creating the searchspace ```python Categorical_1 = CategoricalParameter("Cat_1", values=["22", "33"], encoding="OHE") Categorical_2 = CategoricalParameter( "Cat_2", values=["very bad", "bad", "OK", "good", "very good"], encoding="INT", ) Num_disc_1 = NumericalDiscreteParameter( "Num_disc_1", values=[1, 2, 3, 4, 6, 8, 10], tolerance=0.3 ) Num_disc_2 = NumericalDiscreteParameter( "Num_disc_2", values=[-1, -3, -6, -9], tolerance=0.3 ) ``` ```python parameters = [Categorical_1, Categorical_2, Num_disc_1, Num_disc_2] ``` ```python searchspace = SearchSpace.from_product(parameters=parameters) ``` ## Defining the targets The multi target mode is handled when creating the objective object. Thus we first need to define the different targets. This examples has different targets with different modes. The first target is maximized and while the second one is minimized. Note that in this multi target mode, the user must specify bounds for each target. ```python Target_1 = NumericalTarget( name="Target_1", mode="MAX", bounds=(0, 100), transformation="LINEAR" ) Target_2 = NumericalTarget( name="Target_2", mode="MIN", bounds=(0, 100), transformation="LINEAR" ) ``` For each target it is also possible to specify a `target_transform` function. A detailed discussion of this functionality can be found at the end of this example. In this example, define a third target working with the mode `MATCH`. We furthermore use `target_transform="BELL"`. ```python Target_3 = NumericalTarget( name="Target_3", mode="MATCH", bounds=(45, 55), transformation="BELL" ) ``` Note that the `MATCH` mode seeks to have the target at the mean between the two bounds. For example, choosing 95 and 105 will lead the algorithm seeking 100 as the optimal value. Thus, using the bounds, it is possible to control both the match target and the range around this target that is considered viable. ## Creating the objective Now to work with these three targets the objective object must be properly created. The mode is set to `DESIRABILITY` and the targets are described in a list. ```python targets = [Target_1, Target_2, Target_3] ``` As the recommender requires a single function, the different targets need to be combined. Thus, a `scalarizer` is used to create a single target out of the several targets given. The combine function can either be the mean `MEAN` or the geometric mean `GEOM_MEAN`. Per default, `GEOM_MEAN` is used. Weights for each target can also be specified as a list of floats in the arguments Per default, weights are equally distributed between all targets and are normalized internally. It is thus not necessary to handle normalization or scaling. ```python objective = DesirabilityObjective( targets=targets, weights=[20, 20, 60], scalarizer="MEAN", ) ``` ```python print(objective) ``` Objective Type: DesirabilityObjective Targets  Type Name Mode Lower_Bound Upper_Bound Transformation \ 0 NumericalTarget Target_1 MAX 0.0 100.0 LINEAR 1 NumericalTarget Target_2 MIN 0.0 100.0 LINEAR 2 NumericalTarget Target_3 MATCH 45.0 55.0 BELL Weight 0 20.0 1 20.0 2 60.0 Scalarizer: MEAN ## Creating and printing the campaign ```python campaign = Campaign(searchspace=searchspace, objective=objective) print(campaign) ``` Campaign Meta Data Batches Done: 0 Fits Done: 0 Search Space Search Space Type: DISCRETE Discrete Search Space Discrete Parameters Name Type Num_Values Encoding 0 Cat_1 CategoricalParameter 2 CategoricalEncoding.OHE 1 Cat_2 CategoricalParameter 5 CategoricalEncoding.INT 2 Num_disc_1 NumericalDiscreteParameter 7 None 3 Num_disc_2 NumericalDiscreteParameter 4 None Experimental Representation Cat_1 Cat_2 Num_disc_1 Num_disc_2 0 22 very bad 1.0 -9.0 1 22 very bad 1.0 -6.0 2 22 very bad 1.0 -3.0 .. ... ... ... ... 277 33 very good 10.0 -6.0 278 33 very good 10.0 -3.0 279 33 very good 10.0 -1.0 [280 rows x 4 columns] Metadata: was_recommended: 0/280 was_measured: 0/280 dont_recommend: 0/280 Constraints Empty DataFrame Columns: [] Index: [] Computational Representation Cat_1_22 Cat_1_33 ... Num_disc_1 Num_disc_2 0 1.0 0.0 ... 1.0 -9.0 1 1.0 0.0 ... 1.0 -6.0 2 1.0 0.0 ... 1.0 -3.0 .. ... ... ... ... ... 277 0.0 1.0 ... 10.0 -6.0 278 0.0 1.0 ... 10.0 -3.0 279 0.0 1.0 ... 10.0 -1.0 [280 rows x 5 columns] Objective Type: DesirabilityObjective Targets  Type Name Mode Lower_Bound Upper_Bound Transformation \ 0 NumericalTarget Target_1 MAX 0.0 100.0 LINEAR 1 NumericalTarget Target_2 MIN 0.0 100.0 LINEAR 2 NumericalTarget Target_3 MATCH 45.0 55.0 BELL Weight 0 20.0 1 20.0 2 60.0 Scalarizer: MEAN TwoPhaseMetaRecommender(initial_recommender=RandomRecommender(allow_repeated_recomm endations=False, allow_recommending_already_measured=True), recommender=BotorchRecommender(allow_repeated_recommendations=False, allow_recommending_already_measured=True, surrogate_model=GaussianProcessSurrogate(kernel_factory=DefaultKernelFactory(), _model=None), acquisition_function=qLogExpectedImprovement(), _botorch_acqf=None, acquisition_function_cls=None, sequential_continuous=False, hybrid_sampler=None, sampling_percentage=1.0), switch_after=1) ## Performing some iterations The following loop performs some recommendations and adds fake results. It also prints what happens to internal data. ```python N_ITERATIONS = 3 ``` ```python for kIter in range(N_ITERATIONS): rec = campaign.recommend(batch_size=3) add_fake_results(rec, campaign.targets) campaign.add_measurements(rec) desirability = campaign.objective.transform(campaign.measurements) print(f"\n\n#### ITERATION {kIter+1} ####") print("\nRecommended measurements with fake measured results:\n") print(rec) print("\nInternal measurement database with desirability values:\n") print(pd.concat([campaign.measurements, desirability], axis=1)) ``` #### ITERATION 1 #### Recommended measurements with fake measured results: Cat_1 Cat_2 Num_disc_1 Num_disc_2 Target_1 Target_2 Target_3 46 22 bad 6.0 -3.0 89.287695 27.689040 53.620385 188 33 bad 8.0 -9.0 54.714958 32.395289 56.792072 136 22 very good 10.0 -9.0 82.235979 29.393339 53.739874 Internal measurement database with desirability values: Cat_1 Cat_2 Num_disc_1 Num_disc_2 Target_1 Target_2 Target_3 \ 0 22 bad 6.0 -3.0 89.287695 27.689040 53.620385 1 33 bad 8.0 -9.0 54.714958 32.395289 56.792072 2 22 very good 10.0 -9.0 82.235979 29.393339 53.739874 BatchNr FitNr Desirability 0 1 NaN 0.784838 1 1 NaN 0.483119 2 1 NaN 0.759277 #### ITERATION 2 #### Recommended measurements with fake measured results: Cat_1 Cat_2 Num_disc_1 Num_disc_2 Target_1 Target_2 Target_3 index 18 22 very bad 6.0 -3.0 52.099147 47.343427 51.813798 74 22 OK 6.0 -3.0 93.488807 41.706375 55.159932 104 22 good 8.0 -9.0 63.316223 84.934914 51.455603 Internal measurement database with desirability values: Cat_1 Cat_2 Num_disc_1 Num_disc_2 Target_1 Target_2 Target_3 \ 0 22 bad 6.0 -3.0 89.287695 27.689040 53.620385 1 33 bad 8.0 -9.0 54.714958 32.395289 56.792072 2 22 very good 10.0 -9.0 82.235979 29.393339 53.739874 3 22 very bad 6.0 -3.0 52.099147 47.343427 51.813798 4 22 OK 6.0 -3.0 93.488807 41.706375 55.159932 5 22 good 8.0 -9.0 63.316223 84.934914 51.455603 BatchNr FitNr Desirability 0 1 1.0 0.784838 1 1 1.0 0.483119 2 1 1.0 0.759277 3 2 NaN 0.771304 4 2 NaN 0.655847 5 2 NaN 0.731868 #### ITERATION 3 #### Recommended measurements with fake measured results: Cat_1 Cat_2 Num_disc_1 Num_disc_2 Target_1 Target_2 Target_3 index 2 22 very bad 1.0 -3.0 32.944727 88.076184 56.847457 19 22 very bad 6.0 -1.0 73.640865 70.293208 56.821857 26 22 very bad 10.0 -3.0 5.462638 37.145001 53.003474 Internal measurement database with desirability values: Cat_1 Cat_2 Num_disc_1 Num_disc_2 Target_1 Target_2 Target_3 \ 0 22 bad 6.0 -3.0 89.287695 27.689040 53.620385 1 33 bad 8.0 -9.0 54.714958 32.395289 56.792072 2 22 very good 10.0 -9.0 82.235979 29.393339 53.739874 3 22 very bad 6.0 -3.0 52.099147 47.343427 51.813798 4 22 OK 6.0 -3.0 93.488807 41.706375 55.159932 5 22 good 8.0 -9.0 63.316223 84.934914 51.455603 6 22 very bad 1.0 -3.0 32.944727 88.076184 56.847457 7 22 very bad 6.0 -1.0 73.640865 70.293208 56.821857 8 22 very bad 10.0 -3.0 5.462638 37.145001 53.003474 BatchNr FitNr Desirability 0 1 1.0 0.784838 1 1 1.0 0.483119 2 1 1.0 0.759277 3 2 2.0 0.771304 4 2 2.0 0.655847 5 2 2.0 0.731868 6 3 NaN 0.324641 7 3 NaN 0.443249 8 3 NaN 0.637588 ## Addendum: Description of `transformation` functions This function is used to transform target values to the interval `[0,1]` for `MAX`/`MIN` mode. An ascending or decreasing `LINEAR` function is used per default. This function maps input values in a specified interval [lower, upper] to the interval `[0,1]`. Outside the specified interval, the function remains constant, that is, 0 or 1. For the match mode, two functions are available `TRIANGULAR` and `BELL`. The `TRIANGULAR` function is 0 outside a specified interval and linearly increases to 1 from both interval ends, reaching the value 1 at the center of the interval. This function is used per default for MATCH mode. The `BELL` function is a Gaussian bell curve, specified through the boundary values of the sigma interval, reaching the maximum value of 1 at the interval center.