A choice optimizer is a version of an online choice simulator which allows multiple selections per attribute and generates multiple-preference share combinations at the same time. This article outlines how to build one by hand. This is helpful for when you have respondent-level parameters from a model that wasn't created in Displayr.
Requirements
- A Displayr document.
- A data set that includes respondent-level parameters. In this example, we are using parameters from a latent class model, but there are many other types of data that could have been used (e.g., parameters from a GLM, draws from the posterior distribution, or beta draws from a maximum simulated likelihood model).
- This example uses estimated parameters of respondents from a discrete choice experiment of the market for eggs.
- The optimizer we wish to create has 4 alternatives (columns), one fixed for each brand.
- You can work your way through this example here. This link will first take you to a login page in Displayr and then to a document that contains the data in the variable set called Individual-Level Parameter Means for Segments 26-Jun-17 9:01:57 AM.
Method
Prepare your data
Your respondent-level parameters will include a variable for each level per attribute. The easiest workflow to follow here is to combine each attribute's variables as a separate variable set with the label of the levels matching what you want to use in your simulator controls.
1. If your parameter variables are all combined as a single variable set in the Data Sources tree, select all of them and right-click > Split.
2. Now select the level variables for a particular attribute and right-click > Combine. For example, Weight is made up of 4 level variables: 55g, 60g, 65g, 70g:
3. Repeat step 2 for every other attribute set.
Create the controls
1. Click Anything in the toolbar > Page Design > Control > Combo Box (Drop-Down).
2. Under Control > Item list, replace the default items with the levels for the first attribute, separated by semi-colons. These must match exactly the labels you have entered in the related variable labels. For example, for Weight, this would be 55g; 60g; 65g; 70g. Where you have a numeric attribute, such as Price in this example, you enter the range of values that you wish the user to be able to choose from (e.g., 1.50; 2.00; 2.50; 3.00; 3.50; 4.00; 4.50; 5.00).
3. Set Selection mode to Multiple selection.
4. Under General > General > Name, set the name of the control to what you set the Label as for the corresponding variable set label with a full stop and number 1 affixed at the end. For example, Weight.1. This convention will save you time in later steps.
5. Repeat these steps for every attribute to be included in your simulator.
6. Select the combo boxes and right-click > Duplicate. This will create a copy of these controls for a second alternative or column.
7. Repeat step 6 for each remaining alternative.
8. Click the Textbox icon in the toolbar to add a label for each attribute on the left of the first column.
Calculate preference shares
1. Click the Calculation icon in the toolbar > Custom Code and draw the outline on your page below your combo boxes.
2. Paste the below into the code editor:
# Variables containing utilities
variables = list("Weight" = Weight,
"Organic" = Organic,
"Charity" = Charity,
"Quality" = Quality,
"Uniformity" = Uniformity,
"Feed" = Feed,
"Price" = Price)
# Scenarios, as defined by selections in combo boxes
# Attributes should be in the same order as the
# variables listed above.
scenario = list(Brand1 = list(Weight.1, Organic.1, Charity.1, Quality.1, Uniformity.1, Feed.1, Price.1),
Brand2 = list(Weight.2, Organic.2, Charity.2, Quality.2, Uniformity.2, Feed.2, Price.2),
Brand3 = list(Weight.3, Organic.3, Charity.3, Quality.3, Uniformity.3, Feed.3, Price.3),
Brand4 = list(Weight.4, Organic.4, Charity.4, Quality.4, Uniformity.4, Feed.4, Price.4))
attribute.names = names(variables)
scenario = lapply(scenario, FUN = function (x) setNames(x, attribute.names))
scenarios <- flipChoice:::flattenScenario(scenario)
n.resp = length(variables[[1]])
n.scenarios <- length(scenarios)
n.alt <- length(scenario)
dims <- c(n.scenarios, n.alt)
dim.prod <- prod(dims[-1])
resp.shares <- array(dim = dims)
pref.shares = NULL
for (i in seq_along(scenarios)){
idx <- seq.int(i, length(resp.shares), by = n.scenarios)
cur.scenario = scenarios[[i]]
utils = lapply(cur.scenario, FUN = function (x, vars) {
util = 0
for (i in seq_along(vars)) {
if (NCOL(vars[[i]]) == 1) {
util = util + as.numeric(gsub("\\$", "", x[i])) * vars[[i]]
} else {
util = util + vars[[i]][, x[i]]
}
}
util
}, vars = variables)
utilities = do.call(cbind, utils)
eutilities = exp(utilities)
shares = prop.table(eutilities, 1)
shares = shares[QFilter, ]
weight = if (is.null(QPopulationWeight)) rep(1, length(variables[[1]])) else QPopulationWeight
weight = weight[QFilter]
# Computing shares for the total sample
shares = sweep(shares, 1, weight, "*")
shares = as.matrix(apply(shares, 2, sum))
pref.shares = rbind(pref.shares, t(100 * prop.table(shares, 2)))
}
rownames(pref.shares) <- names(scenarios)
pref.shares
A few key aspects of the code:
- The code is designed for four alternatives but can easily be modified to handle a different number of alternatives.
- We have been careful with the naming of the variable sets and controls to make this easier to read.
- The variable set Label of each set of variables that contain the utilities needs to be entered in the first section on lines 2 to 8. The left-hand labels within speech marks are the attribute labels that are shown in the final output. On the right-hand are the variable set label references. Note, if your variable set label includes spaces, you will need to wrap the label references here within backticks.
- We have named the columns as Brand1 to Brand4 but this can be changed in the
scenario
section on lines 12 to 15. - This includes conditional code for numeric attributes without levels whereby it multiplies the values by the price level after removing the $ sign and converting it to numeric.
- The code is already setup to deal with filters and weights.
- The code works with other models.
3. Apply any filters or weight to your preference share calculations via Data > Filters & Weight in the object inspector. The simulator will automatically re-run with each change. This also applies to control and page filters in the published link. See, for example, How to Setup Filtering in a Dashboard.
4. OPTIONAL: You can customize the styling of the preference share calculation in the object inspector via Appearance > Appearance > Table style.
See also How to Customize the Formatting of Tables in Displayr.
5. OPTIONAL: Alternatively, you can transform this table into a custom formatted Autofit table by clicking Visualization > Specialty Tables > Table with Custom Formatting in the object inspector and then performing the below:
- Untick Data > Data Manipulation > Tidy labels.
- Untick Chart > Column Header > Show column headers.
- Adjust Fill and Border color, Font size and Padding under Cells and Row Header (as relevant).
See How to Create an Autofit Table for details.
6. OPTIONAL: As the number of rows could get very large when using an Autofit table, we can additionally set the row height and force a scroll bar to appear when there is not enough space within the table to show all rows.
- Click Data > Show Advanced Options > R Code > Edit Code.
- Accept the prompt to change the code.
- Search for the
show.row.headers
line of code and insertrow.height = "30px"
in the line below, while setting the most appropriate height.
See How to Add Scrolling to an Autofit or CreateCustomTable R Table for details.
7. You can additionally add background images and logos or customize your page further. See Customizing Online Reports/Dashboards for details.
8. Click Share > Publish to web > Anyone with the link or Login and password required to share your simulator. See also How to Publish a Document as a Web Page (Dashboard).
Next
How to Create an Online Choice Simulator By Hand