Package: scenarioselector
The scenario selection algorithm selects a maximal subset of scenarios from a scenario set1, so that the selected scenarios have specified means (or sums).Package InstallationThe Python scenarioselector package is published on thePython Package Index, and is hosted onGitHub. The package can be installed with thePackage Installer for Python.pip install scenarioselectorDemonstrationsThe easiest way to understand the scenario selection algorithm is to read through, download2and run two accompanying Jupyter Notebook demos presented with theJupyter NBViewer.Demo 1: Selecting Scenarios from a Monte Carlo Simulation;Demo 2: Selecting Scenarios of Bivariate Data.Basic UsageThe following three steps outline basic usage of the ScenarioSelector class, which constructs instances of scenario selection problems and applies the selection algorithm.1. Instantiate ScenarioSelectorConstruct an object which defines the scenario selection problem you want to solve.fromscenarioselectorimportScenarioSelectorselector=ScenarioSelector(data,weights=1,means=0,sums=0)VariableAllowable TypesShapeDefault ValueDescriptiondataList of lists, NumPy array, or pandas dataframe.(N,D)Required parameter.Scenario set withNscenarios andDvariables.weightsScalar, list or NumPy array.(N,)Unit weight for each scenario.Strictly positive weights for each of theNscenarios.meansScalar, list or NumPy array.(D,)Zero mean for each variable.Target means for theDvariables.sumsScalar, list or NumPy array.(D,)Zero sum for each variable.Target sums for theDvariables.Note: Non-zero target values may be specified for eithermeansorsums, but not both.2. Run the Scenario Selection AlgorithmCall the ScenarioSelector's optimize method to run the scenario selection algorithm.selector.optimize(callback=None,pivot_rule=None)Note: Callingselector.optimize()without parameters runs the algorithm with default parameters.3. View ResultsResults of the optimization can be inspected as follows3.selector.selectedis a Numpy array of Booleans which indicates which scenarios have been selected. If the input variabledatais a NumPy array, then you can use NumPy's Boolean indexing functionality to obtain the selected scenario set asselected_data = data[selector.selected], and the associated weights asselected_weights = selector.weights[selector.selected].If you have specified targetmeans, the weighted means of the reduced scenario set will be close to your specified target. You can verify this by calculatingnumpy.average(selected_data, weights=selected_weights, axis=0). If the original scenario set is equally weighted then you do not need to specify the selected weights.If you have specified targetsums, the weighted sums of the reduced scenario set will be close to your specified target. You can verify this by calculatingnumpy.dot(selected_weights, selected_data). If each scenario has unit weight then you can get the same result by calculatingnumpy.sum(selected_data, axis=0).selector.reduced_weightsis a NumPy array of reduced weights associated with each scenario. You can verify the algorithm has hit thesumstarget precisely by calculatingnumpy.dot(selector.reduced_weights, data).selector.probabilitiesis an NumPy array of probabilities associated with each scenario. You can verify the algorithm has hit themeanstarget precisely by calculatingnumpy.dot(selector.probabilities, data).Example of Basic UsageThe following is an example of basic usage withN= 5 andD= 2.Consider a finite discrete probability space, (Ω, P), whereΩ:= {ω1, ω2, ω3, ω4, ω5}
and the probabilities of each outcome arep1= P(ω1) = 0.15,p2= P(ω2) = 0.25,p3= P(ω3) = 0.2,p4= P(ω4) = 0.25 andp5= P(ω5) = 0.15.Consider an R2-valued random variableXwith five realizationsX(ω1) = (0.8, -3.2),X(ω2) = (3.0, 2.9),X(ω3) = (3.0, 2.5),X(ω4) = (-0.8, 1.0) andX(ω5) = (0.8, -2.0).Suppose we want to select a maximal subset of the five scenarios, so that the weighted sum of the outcomesX(ωn) selected scenarios is equal to (1.1, 1.0). More precisely, we want to find reduced weights 0 ≤qn≤pnwhich maximize Σnqn, subject to the constraint ΣnqnX(ωn) = (1.1, 1.0).We define an array of shape (5, 2) which holds the scenario set data.fromscenarioselectorimportScenarioSelectorimportnumpyasnpdata=np.array([[0.8,-3.2],[3.0,2.9],[3.0,2.5],[-0.8,-1.0],[0.8,-2.0]])weights=[0.15,0.25,0.2,0.25,0.15]sums=[1.1,1.0]selector=ScenarioSelector(data,weights=weights,sums=sums)print()print("Before optimization")print("-------------------")print(sum(selector.selected),"scenarios selected: ",selector.selected)print("Exact sums:",np.dot(selector.reduced_weights,data))print("Approx sums:",np.dot(selector.weights[selector.selected],data[selector.selected]))selector.optimize()print()print("After optimization")print("------------------")print(sum(selector.selected),"scenarios selected: ",selector.selected)print("Exact sums:",np.dot(selector.reduced_weights,data))print("Approx sums:",np.dot(selector.weights[selector.selected],data[selector.selected]))Note: Python uses zero-based array indices so, for example,data[1]evaluates to[3.0, 2.9].Advanced UsageScenarioSelector PropertiesA ScenarioSelector object has the following properties, which can be queried at any stage of the optimization.PropertyTypeShapeDescriptionselectedNumPy array(N,)Booleans, indicating which scenarios are selected.reduced_weightsNumPy array(N,)Reduced weights associated with each scenario.probabilitiesNumPy array(N,)Probabilities associated with each scenario.lagrange_multiplierNumpy array(D,)Lagrange multiplier for the dual problem.tableaupandas dataframeCondensed tableau for the simplex algorithm.pivot_countintNumber of pivots operations used to get to the current state.Callback FunctionThe scenario selector's optimize method can be parameterized with a bespoke callback function. For example,tableaus=[]defcallback(selector,i,element):print("Iteration{}pivots on element{}.".format(i,element))tableaus.append(selector.tableau)To keep track of the optimization progress, call the ScenarioSelector's optimize method with the callback function as a parameter.selector.optimize(callback=callback)Pivot RuleA pivot rule determines which variable and scenario(s) to use for pivot and flip operations in the modified simplex algorithm.fromscenarioselector.pivot_ruleimportPivotRule,PivotRuleSlowedfromscenarioselector.pivot_variableimport(Dantzig,DantzigTwoPhase,MaxObjectiveImprovement,MaxObjectiveImprovementTwoPhase)fromscenarioselector.pivot_scenariosimportpivot_scenarios,barrodale_robertspivot_rule=PivotRule(pivot_variable=DantzigTwoPhase,pivot_scenarios=barrodale_roberts)selector.optimize(pivot_rule=pivot_rule)The choices of pivot variable and pivot scenario(s) are discussed in the next two subsections.Note: The derived pivot rulePivotRuleSlowedis designed specifically for use with the Barrodale Roberts improvement. This rule slows down the effect of passing through each vertex in succession, and is included only for demonstration purposes.Pivot VariableApivot_variablerule determines which variable to use for the next pivot operation. Pre-definedpivot_variablerules can be summarised as follows.RuleDescriptionDantzigChoose the variable whose corresponding entry in the basement row of the condensed tableau has the largest magnitude.DantzigTwoPhaseSimilar toDantzig, however the firstDoperations move all the Lagrange multiplier variables into the basis.MaxObjectiveImprovementChoose the variable such that a classical pivot operation will lead to the largest improvement in the objective value.MaxObjectiveImprovementTwoPhaseSimilar toMaxObjectiveImprovement, however the firstDoperations move all the Lagrange multiplier variables into the basis.Pivot ScenariosApivot_scenariosrule determines which scenario(s) to use for the next pivot and associated flip operations. The Barrodale Roberts improvement allows the modified simplex algorithm to pass through multiple vertices at once, allowing the algorithm to flip an array of selection states in a single operation.FootnotesA scenario set is a set of (possibly weighted) observations of multi-variate data.The example notebooks are located in a separate project which is also hosted onGitHub.This section assumes you have imported NumPy with the statementimport numpy.