Welcome to desdeo-problem’s documentation¶
Contains tools to model and define multiobjective optimization problems to be used in the DESDEO framework.
Requirements¶
Python 3.7 or newer.
Poetry dependency manager : Only for developers.
See pyproject.toml for Python package requirements.
Installation¶
To install and use this package on a *nix-based system, follow one of the following procedures.
For users¶
First, create a new virtual environment for the project. Then install the package using the following command:
$ pip install desdeo_problem
For developers¶
Download the code or clone it with the following command:
$ git clone https://github.com/industrial-optimization-group/desdeo-problem
Then, create a new virtual environment for the project and install the package in it:
$ cd desdeo-problem
$ poetry init
$ poetry install
API Documentation¶
desdeo_problem.problem Package¶
Desdeo-problem package
This package is for creating a problem for desdeo to solve. It includes modules for Variables, Objectives, Constraints, and actual Problem.
Functions¶
|
A function that creates an evaluator. |
|
Automatically build all variable objects. |
Classes¶
|
A simple scalar constraint that evaluates to a single scalar. |
Raised when an error related to the Constraint class in encountered. |
|
Base class for constraints. |
|
The abstract base class for objectives. |
|
Raised when an error related to the Objective class is encountered. |
|
|
The return object of <problem>.evaluate methods. |
The abstract base class for multiple objectives which are calculated at once. |
|
|
A simple objective function that returns a scalar. |
|
|
|
An objective object that calculated one or more objective functions. |
|
A simple Objective class for single valued objectives. |
|
|
|
A Objective class for multi/valued objectives. |
Raised when an error related to the Problem class is encountered. |
|
The base class for the problems. |
|
|
The return object of <problem>.evaluate methods. |
|
A multiobjective optimization problem. |
|
A problem class for case where the data is pre-computed. |
|
An user defined multiobjective optimization problem. |
|
A class for a data based problem. |
|
A problem class for data-based problem. |
Raised when an error is encountered during the handling of the Variable objects. |
|
Raised when an error is encountered during the handling of the Variable objects. |
|
|
Simple variable with a name, initial value and bounds. |
|
A problem class for data-based problems with discrete values. |
Class Inheritance Diagram¶

desdeo_problem.testproblems Package¶
Functions¶
|
Build test problems. |
An example on how to implement a problem with 3 objectives and 4 variables and no constraints. |
desdeo_problem.surrogatemodels Package¶
Classes¶
Raised when an error related to the surrogate models classes is encountered. |
|
|
|
Class Inheritance Diagram¶

Examples¶
Analytical problem¶
Defining a problem with an explicit mathematical representation is straightforward.
As an example, consider the following multiobjective optimization problem:
where the feasible region is
Begin by importing the necessary classes:
[1]:
from desdeo_problem import Variable, ScalarObjective, ScalarConstraint, ScalarMOProblem
Define the variables:
[2]:
# Args: name, starting value, lower bound, upper bound
x1 = Variable("x_1", 0, -0.5, 0.5)
x2 = Variable("x_2", 0, -0.5, 0.5)
Define the objectives, notice the argument of the callable objective function, it is assumed to be array-like.
[3]:
# Args: name, callable
obj1 = ScalarObjective("f_1", lambda x: x[:,0]**2 - x[:,1])
obj2 = ScalarObjective("f_2", lambda x: x[:,1]**2 - 3*x[:,0])
Define the constraints. Constraint may depend on objective function as well (second argument to the lambda, notice the underscore). In that case, the objectives should not be defined inline, like above, but as their own function definitions. The constraint should be defined so, that when evaluated, it should return a positive value, if the constraint is adhered to, and a negative, if the constraint is breached.
[4]:
# Args: name, n of variables, n of objectives, callable
cons1 = ScalarConstraint("c_1", 2, 2, lambda x, _: 10 - (x[:,0] + x[:,1]))
Finally, put it all together and create the problem.
[5]:
# Args: list of objevtives, variables and constraints
problem = ScalarMOProblem([obj1, obj2]
,[x1, x2]
,[cons1])
Now, the problem is fully specified and can be evaluated and played around with.
[6]:
import numpy as np
print("N of objectives:", problem.n_of_objectives)
print("N of variables:", problem.n_of_variables)
print("N of constraints:", problem.n_of_constraints)
res1 = problem.evaluate(np.array([2, 4]))
res2 = problem.evaluate(np.array([6, 6]))
res3 = problem.evaluate(np.array([[6, 3], [4,3], [7,4]]))
print("Single feasible decision variables:", res1.objectives, "with constraint values", res1.constraints)
print("Single non-feasible decision variables:", res2.objectives, "with constraint values", res2.constraints)
print("Multiple decision variables:", res3.objectives, "with constraint values", res3.constraints)
N of objectives: 2
N of variables: 2
N of constraints: 1
Single feasible decision variables: [[ 0. 10.]] with constraint values [[4.]]
Single non-feasible decision variables: [[30. 18.]] with constraint values [[-2.]]
Multiple decision variables: [[33. -9.]
[13. -3.]
[45. -5.]] with constraint values [[ 1.]
[ 3.]
[-1.]]
[ ]:
The Problem
class¶
An analytical problem is a problem where the mathematical formulation of the various objectives is known, as opposed to a data-driven problem, where one may need to train surrogate models to proceed with optimization.
The Problem
class is the way to define optimization problems in the DESDEO framework. Once defined, the same Problem
class instance can be used to solve optimization problems using various EAs from the desdeo-emo
package, or the more traditional methods from the desdeo-mcdm
package.
This notebook will help you understand how to instantiate a analytical problem object from scratch. The notebook will also go over other abstractions, namely classes for defining the decision variables, objectives, and the constraints, and will go over the functionalities provided by the abstractions.
Multiobjective Optimization Problem¶
Let’s say that we have the following minimization problem:
Variables¶
Before instantiating the problem instance, we have to create object to define each of the variables, objectives, and constraints.
The variable objects can be created with the desdeo_problem.Variable.Variable
class. This object stores the information related to the variable (such as, lower bound, upper bound, and an initial value). This information is used by the methods whenever required (such as when setting box constraints on searching algorithms or recombination operators) and for displaying results to the decision maker. Use this class to create variable objects, one variable at a time.
To define multiple Variable
instances easily, use the desdeo_problem.Variable.variable_builder
function. The function takes in all the necessary information for all the variables at once, and returns a List of Variable
instances, one for each decision variable.
Use the help()
function to know more about any function/class in the desdeo framework.
[1]:
from desdeo_problem import variable_builder
help(variable_builder)
Help on function variable_builder in module desdeo_problem.problem.Variable:
variable_builder(names: List[str], initial_values: Union[List[float], numpy.ndarray], lower_bounds: Union[List[float], numpy.ndarray] = None, upper_bounds: Union[List[float], numpy.ndarray] = None) -> List[desdeo_problem.problem.Variable.Variable]
Automatically build all variable objects.
Args:
names (List[str]): Names of the variables
initial_values (np.ndarray): Initial values taken by the variables.
lower_bounds (Union[List[float], np.ndarray], optional): Lower bounds of the
variables. If None, it defaults to negative infinity. Defaults to None.
upper_bounds (Union[List[float], np.ndarray], optional): Upper bounds of the
variables. If None, it defaults to positive infinity. Defaults to None.
Raises:
VariableError: Lengths of the input arrays are different.
Returns:
List[Variable]: List of variable objects
Let’s build the Variable
objects
[2]:
var_names = ["a", "b", "c"] # Make sure that the variable names are meaningful to you.
initial_values = [1, 1, 1]
lower_bounds = [-2, -1, 0]
upper_bounds = [5, 10, 3]
variables = variable_builder(var_names, initial_values, lower_bounds, upper_bounds)
[3]:
print("Type of \"variables\": ", type(variables))
print("Length of \"variables\": ", len(variables))
print("Type of the contents of \"variables\": ", type(variables[0]))
Type of "variables": <class 'list'>
Length of "variables": 3
Type of the contents of "variables": <class 'desdeo_problem.problem.Variable.Variable'>
Objectives¶
Objectives are defined using tha various objective classes found within the module desdeo_problem.Objective
. To define an objective class instance, one needs to pass the following:
Objective name/s (Required): Name of the objective (or list of names, for multiple objective). This information will be used when displaying results to the user. Hence, these names must be understandable to the user.
Evaluator (Required for analytical/simulation based objectives): An evaluator is a python
Callable
which takes in the decision variables as it’s input and returns the corresponding objective values. This python function can be used to connect to simulators outside the DESDEO framework.Lower bound (Not required): A lower bound for the objective. This information can be used to generate approximate ideal/nadir point during optimization.
Upper bound (Not required): An upper bound for the objective. This information can be used to generate approximate ideal/nadir point during optimization.
maximize (Not required): This is a boolean value that determines whether an objective is to be maximized or minimized. This is
False
by default (i.e. the objective is minimized).
The DESDEO framework has the following classification for objectives, based on the kind of evaluater to be used:
“Scalar” objectives: If an evaluator/simulator evaluates only one objective, the objective is defined as a Scalar objective. Use the
desdeo_problem.Objective._ScalarObjective
class to handle such cases.“Vector” objectives: If an evaluator evaluates and returns more than one objective at once, the set of objectives is defined as Vector objective. Use the
desdeo_problem.Objective.VectorObjective
class to handle such cases.
Note:_ScalarObjective
will be depreciated in the future, and all of it’s functionality will be handled by the VectorObjective
class, which will be renamed to, simply, Objective
.
To define a problem instance, the objectives may be defined as all Scalar objectives, all Vector objectives, or a mix of both, depending upon the case.
Let’s see how to define and use both kinds of Objective classes:
[4]:
from desdeo_problem import ScalarObjective, VectorObjective
import numpy as np
Define the evaluators for the objectives. These evaluators should be python functions that take in the decision variable values and give out the objective value/s. The arguments of these evaluators are 2-D Numpy arrays.
[5]:
def obj1_2(x): # This is a "simulator" that returns more than one objective at a time. Hence, use VectorObjective
y1 = x[:, 0] + x[:, 1] + x[:, 2]
y2 = x[:, 0] * x[:, 1] * x[:, 2]
return (y1, y2)
def obj3(x): # This is a "simulator" that returns only one objective at a time. Hence, use ScalarObjective
y3 = x[:, 0] * x[:, 1] + x[:, 2]
return y3
Define the objectives. For this, you need the names of the objectives, and the evaluators defined above. If an evaluator returns multiple objective values, use the VectorObjective
class to define those objectives. If an evaluator returns objective values for only one objective, either VectorObjective
or ScalarObjective
can be used.
If using VectorObjective
, names should be provided in a list.
Additionaly, bounds of the objective values can also be provided.
[6]:
f1_2 = VectorObjective(["y1", "y2"], obj1_2)
f3 = ScalarObjective("y3", obj3, maximize=True) # Note: f3 = VectorObjective(["y3"], obj3) will also work.
Constraints¶
Constraint may depend on the decision variable values, as well as the objective function.
The constraint should be defined so, that when evaluated, it should return a positive value, if the constraint is adhered to, and a negative, if the constraint is breached.
[7]:
from desdeo_problem import ScalarConstraint
const_func = lambda x, y: 10 - (x[:, 0] + x[:, 1] + x[:, 2])
# Args: name, number of variables, number of objectives, callable
cons1 = ScalarConstraint("c_1", 3, 3, const_func)
Creating the Problem object¶
Now that we have all the building blocks, we can create the problem object, using the desdeo_problem.Problem.MOProblem
class.
Provide objectives, variables and constraints in lists.
[8]:
from desdeo_problem import MOProblem
prob = MOProblem(objectives=[f1_2, f3], variables=variables, constraints=[cons1])
The problem class provides abstractions such as the evaluate
method. The method evaluates all the objective and constraint values for a given set of decision variables (in a numpy array), using the evaluators.
The abstraction also provides methods such as train
and surrogate_evaluate
for data driven problem. These will be tackled in the next notebook.
The output is a NamedTuple object. It contains the following elements:
objectives
: Contains the objective valuesfitness
: Contains the fitness values. Fitness is either equal to the objective value, or equal to (-1 * objective value), depending upon whether the objective is to be minimized or maximized respectively. The optimization methods in the DESDEO framework internally use this value, rather than the values contained in output.objectivesconstraints
: Contains constraint violation values.uncertainity
: Contains the quantification of “uncertainity” of the evaluation
All of these values can be accessed in different ways, as shown below.
Note: Input as list of lists is not supported
[9]:
data = np.asarray([[1, -1, 0], [5, 5, 2]])
res= prob.evaluate(data)
[10]:
print(res)
# Note the sign reversal in the third objective and third fitness values because of maximization.
Evaluation Results Object
Objective values are:
[[ 0. 12. -1.]
[ 0. 50. 27.]]
Constraint violation values are:
[[10.]
[-2.]]
Fitness values are:
[[ 0. 12. 1.]
[ 0. 50. -27.]]
Uncertainity values are:
[[nan nan nan]
[nan nan nan]]
[11]:
print("The objective values for the given set of decision variables are: \n", res.objectives)
print("The constraint violation for the given set of decision variables are:\n", res.constraints)
The objective values for the given set of decision variables are:
[[ 0. 12. -1.]
[ 0. 50. 27.]]
The constraint violation for the given set of decision variables are:
[[10.]
[-2.]]
[12]:
res
[12]:
EvaluationResults(objectives=array([[ 0., 12., -1.],
[ 0., 50., 27.]]), fitness=array([[ 0., 12., 1.],
[ 0., 50., -27.]]), constraints=array([[10.],
[-2.]]), uncertainity=array([[nan, nan, nan],
[nan, nan, nan]]))
[ ]:
How to make and use the test problems¶
Currently supported: * ZDT Problems- ZDT1-4, ZDT6 * DTLZ Problems- DTLZ1-7
Import the test problem builder
[1]:
from desdeo_problem.testproblems.TestProblems import test_problem_builder
Use test_problem_builder
to build the necessary MOProblem
instance, which can be used by methods in desdeo-emo and desdeo-mcdm to solve multiobjective optimization problems
[2]:
help(test_problem_builder)
Help on function test_problem_builder in module desdeo_problem.testproblems.TestProblems:
test_problem_builder(name: str, n_of_variables: int = None, n_of_objectives: int = None) -> desdeo_problem.problem.Problem.MOProblem
Build test problems. Currently supported: ZDT1-4, ZDT6, and DTLZ1-7.
Args:
name (str): Name of the problem in all caps. For example: "ZDT1", "DTLZ4", etc.
n_of_variables (int, optional): Number of variables. Required for DTLZ problems,
but can be skipped for ZDT problems as they only support one variable value.
n_of_objectives (int, optional): Required for DTLZ problems,
but can be skipped for ZDT problems as they only support one variable value.
Raises:
ProblemError: When one of many issues occur while building the MOProblem
instance.
Returns:
MOProblem: The test problem object
[3]:
zdt1 = test_problem_builder("ZDT1")
zdt1
[3]:
<desdeo_problem.problem.Problem.MOProblem at 0x1f33b279ac8>
[4]:
dtlz3 = test_problem_builder("DTLZ3", n_of_objectives= 3, n_of_variables=20)
dtlz3
[4]:
<desdeo_problem.problem.Problem.MOProblem at 0x1f33b279208>
How to use these instances for other purposes, such as generating data:
[5]:
import numpy as np
Generate input data as desired:
[6]:
number_of_samples = 3
zdt_data = np.random.random((number_of_samples, 30)) # 30 is the number of variables in the ZDT1 problem
print(zdt_data)
[[0.9566665 0.12642707 0.75401858 0.03765694 0.01986561 0.48660617
0.49280935 0.85344899 0.27133411 0.93323257 0.84133493 0.20475801
0.92905088 0.06490354 0.8570188 0.83492128 0.62833644 0.99593786
0.81635487 0.82580931 0.56251793 0.97574662 0.47558831 0.3939823
0.27397178 0.7496003 0.04909389 0.08239682 0.34656906 0.49915204]
[0.74919761 0.28625722 0.67908382 0.6106337 0.6950148 0.25785019
0.61746779 0.76319615 0.89890242 0.75963628 0.98161652 0.67291301
0.79612155 0.52273917 0.20450823 0.7952598 0.60585745 0.4121897
0.05809478 0.34800526 0.58840432 0.18724738 0.68237086 0.61657321
0.3096879 0.32458604 0.16036243 0.82480997 0.17956196 0.01421743]
[0.9957692 0.19364135 0.11009589 0.63606894 0.92162454 0.95342228
0.88665615 0.74501953 0.09816078 0.48951933 0.76896919 0.64603171
0.90088292 0.26154581 0.91006787 0.89883207 0.45426937 0.47012129
0.01451065 0.40256939 0.2019439 0.45817166 0.56534801 0.18641038
0.91780371 0.19666782 0.83473067 0.15496044 0.01478023 0.85545543]]
[7]:
dtlz_data = np.random.random((number_of_samples, 20)) # We put the number of variables earlier as 20
<MOProblem object>.evaluate(data)
returns a tuple containing the objective values and constraint violations
[8]:
zdt_obj_val = zdt1.evaluate(zdt_data)
zdt_obj_val
[8]:
EvaluationResults(objectives=array([[0.9566665 , 3.42361516],
[0.74919761, 3.55955498],
[0.9957692 , 3.31853043]]), fitness=array([[0.9566665 , 3.42361516],
[0.74919761, 3.55955498],
[0.9957692 , 3.31853043]]), constraints=None, uncertainity=array([[nan, nan],
[nan, nan],
[nan, nan]]))
There are no constraints in the zdt or dtlz problems, hence cons_val is None
[9]:
dtlz_obj_val = dtlz3.evaluate(dtlz_data)
dtlz_obj_val
[9]:
EvaluationResults(objectives=array([[1307.49928399, 1214.1266996 , 555.10066581],
[ 248.94975775, 162.82774202, 2199.31133262],
[1052.58290325, 1701.71639663, 600.67385014]]), fitness=array([[1307.49928399, 1214.1266996 , 555.10066581],
[ 248.94975775, 162.82774202, 2199.31133262],
[1052.58290325, 1701.71639663, 600.67385014]]), constraints=None, uncertainity=array([[nan, nan, nan],
[nan, nan, nan],
[nan, nan, nan]]))
[ ]:
Data based problem¶
If the problem to be optimized has already been solved for a representation of its’ Pareto efficient front, it can be defined as a ScalarDataProblem.
Suppose we have a problem with 2 decision variables and 4 objectives. In this case, it is the river pollution problem as defined in https://ieeexplore.ieee.org/document/35354
The computed Pareto efficient solutions and the corresponding objective vector values have been computed in the file ‘riverpollution.dat’. There is a total of 500 entries. Begin by importing relevant classes and laoding the data.
[2]:
# NOTE: This will soon be depreciated.
from desdeo_problem import ScalarDataProblem
import numpy as np
data = np.loadtxt("./data/riverpollution.dat")
The first 2 entries of each row are the decision variables, and the last 4 the objective function values.
[3]:
xs, fs = data[:, 0:2], data[:, 2:]
The problem can now be defined:
[4]:
problem = ScalarDataProblem(xs, fs)
That’s it. Now the problem is defined and can be further utilized. Notice that there are no constraints. It is assumed that all the entries in the data file are feasible. The warning has to do with the fact, that the data is discrete, therefore the evaluations for specific decision variable values have to be approximated somehow. At the moment, the closest pair of decision variables is searched for in the data. Later on, a surrogate model for the data might be build to have a better approximation.
[5]:
print("N of objectives:", problem.n_of_objectives)
print("N of variables:", problem.n_of_variables)
print("Single decision vector evaluaion:", problem.evaluate([0.4, 0.5]))
N of objectives: 4
N of variables: 2
Single decision vector evaluaion: (array([-5.6304735 , -2.87892556, -7.06008234, 0.05013393]),)
[ ]:
Data Based Problems¶
The DESDEO framework provides handling of data-driven optimization problems. Some methods, such as E-NAUTILUS in desdeo-mcdm
, find the most preffered solution from a provided dataset. Other methods, such as most of the EA’s from desdeo-emo
, require a surrogate model to be trained for each of the objectives. The desdeo_problem
provides support for both of these cases.
For data based problems, use the data specific objective/problem classes
[1]:
import pandas as pd
import numpy as np
VectorDataObjective is an objective class that can handle data, as well as multi-objective evaluators.
The GaussianProcessRegressor here is same as the one in scikit-learn with one small difference. The predict method has been replaced to return uncertainity values (in the form of standard deviation of the prediction) by default. It supports hyperparameters in the same format as the sklearn method.
[2]:
from desdeo_problem import VectorDataObjective as VDO
from desdeo_problem.surrogatemodels.SurrogateModels import GaussianProcessRegressor
from sklearn.gaussian_process.kernels import Matern
Creating some random data¶
‘a’ and ‘b’ are randomly generated between 0 and 1.
For data-driven problems, make sure that the input dataset is in the pandas DataFrame format, with the column names being the same as the variable/objective names.
[3]:
data = np.random.rand(100,2)
f1 = (data[:,0]+data[:,1]).reshape(-1,1)
f2 = (data[:,0]*data[:,1]).reshape(-1,1)
data = np.hstack((data, f1, f2))
X = ['a','b']
y = ['f1','f2']
datapd = pd.DataFrame(data, columns=X+y)
datapd.head()
[3]:
a | b | f1 | f2 | |
---|---|---|---|---|
0 | 0.730445 | 0.051709 | 0.782154 | 0.037771 |
1 | 0.039999 | 0.693915 | 0.733915 | 0.027756 |
2 | 0.024957 | 0.584356 | 0.609313 | 0.014584 |
3 | 0.774647 | 0.427847 | 1.202494 | 0.331430 |
4 | 0.500549 | 0.012714 | 0.513263 | 0.006364 |
Using VectorDataObjective class¶
The VectorDataObjective
class takes as its input the data in a dataframe format and the objective names in a list.
[4]:
obj = VDO(data=datapd, name=y)
Training surrogate models¶
Pass the surrogate modelling technique and the model parameters to the train method of the objective instance.
If only one modelling technique is passed, the model_parameters
should be a dict (or None) and this will be used for all the objectives.
If multiple modelling techniques are passed, models
should be the list of modelling techniques, and model_parameters
should be a list of dicts. The length of these lists should be the same as the number of objectives and each list element will be used to train one objective in order.
[5]:
obj.train(models=GaussianProcessRegressor, model_parameters={'kernel': Matern(nu=1.5)})
Using surrogate models to evaluate objective values¶
Use the obj.evaluate method to get predictions. Note that use_surrogates
should be true.
[6]:
print(obj.evaluate(np.asarray([[0.5,0.3]]), use_surrogate=True))
Objective Evaluation Results Object
Objective values are:
f1 f2
0 0.800011 0.150043
Uncertainity values are:
f1 f2
0 0.000615 0.001536
[7]:
obj._model_trained
[7]:
{'f1': True, 'f2': True}
Creating data problem class¶
Creating the objective class should be bypassed for now, use DataProblem
class directly with the data in a dataframe.
The DataProblem
provides a train
method which trains all the objectives sequentially. The input arguments for this train method is the same as that of the VectorDataObjective
class.
To make sure that the evaluate
method uses the surrogate models for evaluations, pass the use_surrogate=True
argument.
[8]:
from desdeo_problem import DataProblem
[9]:
maximize = pd.DataFrame([[True, False]], columns=['f1','f2'])
prob = DataProblem(data=datapd, objective_names=y, variable_names=X, maximize=maximize)
[10]:
prob.train(GaussianProcessRegressor)
[11]:
print(prob.evaluate(np.asarray([[0.1,0.8], [0.5,0.3]]), use_surrogate=True))
Evaluation Results Object
Objective values are:
[[0.89999924 0.08000021]
[0.8 0.14999895]]
Constraint violation values are:
None
Fitness values are:
[[-0.89999924 0.08000021]
[-0.8 0.14999895]]
Uncertainity values are:
[[0.00346248 0.00346248]
[0.00374312 0.00374312]]
Lipschitian models¶
[12]:
from desdeo_problem.surrogatemodels.lipschitzian import LipschitzianRegressor
[13]:
prob = DataProblem(data=datapd, objective_names=y, variable_names=X)
[14]:
prob.train(LipschitzianRegressor)
[15]:
print(prob.evaluate(np.asarray([[0.1,0.8], [0.5,0.3]]), use_surrogate=True))
Evaluation Results Object
Objective values are:
[[0.9 0.08734629]
[0.8 0.16056562]]
Constraint violation values are:
None
Fitness values are:
[[0.9 0.08734629]
[0.8 0.16056562]]
Uncertainity values are:
[[3.33066907e-16 1.74576926e-02]
[6.10622664e-16 7.72293212e-02]]
[ ]:
How to use Lipschitzian modelling¶
[1]:
import numpy as np
import pandas as pd
from desdeo_problem.surrogatemodels.lipschitzian import LipschitzianRegressor
import matplotlib.pyplot as plt
[2]:
def y_func(x):
return(np.sin(x) + np.sin(2*x))
[3]:
num_points = 20
x = np.linspace(0, 2 * np.pi, num_points).reshape(-1,1)
y = y_func(x)
data = pd.DataFrame(np.hstack((x,y)), columns = ['x','y'])
[4]:
model = LipschitzianRegressor()
[5]:
model.fit(X=data['x'], y = data['y'])
[6]:
model.L
[6]:
2.8392177826759726
[7]:
model.y
[7]:
array([[ 0.00000000e+00],
[ 9.38912182e-01],
[ 1.58361298e+00],
[ 1.75293980e+00],
[ 1.44534766e+00],
[ 8.31989903e-01],
[ 1.80049416e-01],
[-2.60860582e-01],
[-3.61219085e-01],
[-1.60104879e-01],
[ 1.60104879e-01],
[ 3.61219085e-01],
[ 2.60860582e-01],
[-1.80049416e-01],
[-8.31989903e-01],
[-1.44534766e+00],
[-1.75293980e+00],
[-1.58361298e+00],
[-9.38912182e-01],
[-7.34788079e-16]])
[8]:
x_new = np.linspace(0, 2*np.pi, 1000).reshape(-1,1)
y_new_true = y_func(x_new)
y_mean, y_delta = model.predict(x_new)
[9]:
plt.scatter(x_new, y_new_true, marker='.')
plt.scatter(x_new, y_mean, marker='.')
plt.scatter(x_new, y_mean + y_delta, marker='.')
plt.scatter(x_new, y_mean - y_delta, marker='.')
[9]:
<matplotlib.collections.PathCollection at 0x2c4d3b5d9c8>

[10]:
def y_func2d(x):
return(np.sin(x[:,0]) + np.sin(2*x[:,1]))
[11]:
x = np.random.rand(200,2)
y = y_func2d(x).reshape(-1,1)
data = pd.DataFrame(np.hstack((x,y)), columns = ['x1', 'x2','y'])
[12]:
model = LipschitzianRegressor()
model.fit(X=data[['x1', 'x2']], y = data['y'])
[13]:
x_new = np.random.rand(2000,2)
y_new_true = y_func2d(x_new).reshape(-1,1)
y_predict, y_delta = model.predict(x_new)
[14]:
line = np.linspace(y_new_true.min(),y_new_true.max(),200)
plt.scatter(y_new_true, y_predict.reshape(-1,1), marker=".")
plt.scatter(y_new_true, (y_predict+y_delta).reshape(-1,1), marker=".", alpha=0.3)
plt.scatter(y_new_true, (y_predict-y_delta).reshape(-1,1), marker=".", alpha=0.3)
plt.scatter(line,line, marker='.')
[14]:
<matplotlib.collections.PathCollection at 0x2c4d4c56c08>

[ ]: