Parameter Estimation using parmest requires a Pyomo model, experimental data which defines multiple scenarios, and parameters (thetas) to estimate. parmest uses Pyomo [PyomoBookII]_ and (optionally) mpi-sppy [mpisppy]_ to solve a two-stage stochastic programming problem, where the experimental data is used to create a scenario tree. The objective function needs to be written with the Pyomo Expression for first stage cost (named "FirstStageCost") set to zero and the Pyomo Expression for second stage cost (named "SecondStageCost") defined as the deviation between the model and the observations (typically defined as the sum of squared deviation between model values and observed values).
If the Pyomo model is not formatted as a two-stage stochastic programming problem in this format, the user can supply a custom function to use as the second stage cost and the Pyomo model will be modified within parmest to match the required specifications. The stochastic programming callback function is also defined within parmest. The callback function returns a populated and initialized model for each scenario.
To use parmest, the user creates a :class:`~pyomo.contrib.parmest.parmest.Estimator` object which includes the following methods:
.. autosummary:: :nosignatures: ~pyomo.contrib.parmest.parmest.Estimator.theta_est ~pyomo.contrib.parmest.parmest.Estimator.theta_est_bootstrap ~pyomo.contrib.parmest.parmest.Estimator.theta_est_leaveNout ~pyomo.contrib.parmest.parmest.Estimator.objective_at_theta ~pyomo.contrib.parmest.parmest.Estimator.confidence_region_test ~pyomo.contrib.parmest.parmest.Estimator.likelihood_ratio_test ~pyomo.contrib.parmest.parmest.Estimator.leaveNout_bootstrap_test
Additional functions are available in parmest to plot results and fit distributions to theta values.
.. autosummary:: :nosignatures: ~pyomo.contrib.parmest.graphics.pairwise_plot ~pyomo.contrib.parmest.graphics.grouped_boxplot ~pyomo.contrib.parmest.graphics.grouped_violinplot ~pyomo.contrib.parmest.graphics.fit_rect_dist ~pyomo.contrib.parmest.graphics.fit_mvn_dist ~pyomo.contrib.parmest.graphics.fit_kde_dist
A :class:`~pyomo.contrib.parmest.parmest.Estimator` object can be created using the following code. A description of each argument is listed below. Examples are provided in the :ref:`examplesection` Section.
.. testsetup:: * :skipif: not __import__('pyomo.contrib.parmest.parmest').contrib.parmest.parmest.parmest_available # Data import pandas as pd data = pd.DataFrame( data=[[1, 8.3], [2, 10.3], [3, 19.0], [4, 16.0], [5, 15.6], [7, 19.8]], columns=['hour', 'y'], ) # Sum of squared error function def SSE(model): expr = ( model.experiment_outputs[model.y] - model.response_function[model.experiment_outputs[model.hour]] ) ** 2 return expr # Create an experiment list from pyomo.contrib.parmest.examples.rooney_biegler.rooney_biegler import RooneyBieglerExperiment exp_list = [] for i in range(data.shape[0]): exp_list.append(RooneyBieglerExperiment(data.loc[i, :]))
>>> import pyomo.contrib.parmest.parmest as parmest
>>> pest = parmest.Estimator(exp_list, obj_function=SSE)
Optionally, solver options can be supplied, e.g.,
>>> solver_options = {"max_iter": 6000}
>>> pest = parmest.Estimator(exp_list, obj_function=SSE, solver_options=solver_options)
The first argument is a list of experiment objects which is used to create one labeled model for each expeirment. The template :class:`~pyomo.contrib.parmest.experiment.Experiment` can be used to generate a list of experiment objects.
A labeled Pyomo model m
has the following additional suffixes (Pyomo Suffix):
m.experiment_outputs
which defines experiment output (Pyomo Param, Var, or Expression) and their associated data values (float, int).m.unknown_parameters
which defines the mutable parameters or variables (Pyomo Param or Var) to estimate along with their component unique identifier (Pyomo ComponentUID). Within parmest, any parameters that are to be estimated are converted to unfixed variables. Variables that are to be estimated are also unfixed.
The experiment class has one required method:
- :class:`~pyomo.contrib.parmest.experiment.Experiment.get_labeled_model` which returns the labeled Pyomo model. Note that the model does not have to be specifically written as a two-stage stochastic programming problem for parmest. That is, parmest can modify the objective, see :ref:`ObjFunction` below.
Parmest comes with several :ref:`examplesection` that illustrates how to set up the list of experiment objects. The examples commonly include additional :class:`~pyomo.contrib.parmest.experiment.Experiment` class methods to create the model, finalize the model, and label the model. The user can customize methods to suit their needs.
The second argument is an optional argument which defines the optimization objective function to use in parameter estimation.
If no objective function is specified, the Pyomo model is used "as is" and should be defined with "FirstStageCost" and "SecondStageCost" expressions that are used to build an objective for the two-stage stochastic programming problem.
If the Pyomo model is not written as a two-stage stochastic programming problem in this format, and/or if the user wants to use an objective that is different than the original model, a custom objective function can be defined for parameter estimation. The objective function has a single argument, which is the model from a single experiment. The objective function returns a Pyomo expression which is used to define "SecondStageCost". The objective function can be used to customize data points and weights that are used in parameter estimation.
Parmest includes one built in objective function to compute the sum of squared errors ("SSE") between the
m.experiment_outputs
model values and data values.
To check the quality of initial guess values provided for the fitted parameters, we suggest solving a square instance of the problem prior to solving the parameter estimation problem using the following steps:
1. Create :class:`~pyomo.contrib.parmest.parmest.Estimator` object. To initialize the parameter
estimation solve from the square problem solution, set optional argument solver_options = {bound_push: 1e-8}
.
2. Call :class:`~pyomo.contrib.parmest.parmest.Estimator.objective_at_theta` with optional
argument (initialize_parmest_model=True)
. Different initial guess values for the fitted
parameters can be provided using optional argument theta_values (Pandas Dataframe)
- Solve parameter estimation problem by calling :class:`~pyomo.contrib.parmest.parmest.Estimator.theta_est`