Estimating Mixed Logit Models

This vignette demonstrates an example of how to use the logitr() function to estimate mixed logit (MXL) models with preference space and WTP space utility parameterizations.

Supported distributions

In mixed logit models, parameters are assumed to follow a particular distribution. This is implemented in logitr with the randPars argument, which should be a named vector defining which distribution to use for each random parameter. In the example below, we set randPars = c(feat = 'n', brand = 'n') so that feat and brand are normally distributed. Mixed logit models will estimate a mean and standard deviation of the underlying normal distribution for each random coefficient.

The current version of the package includes the following distributions:

Note that log-normal or zero-censored normal parameters force positivity, so when using these you may need to use the negative of a value. For example, the “price” coefficient is typically negative, so if modeling “price” with a log-normal or zero-censored normal distribution you should convert “price” to the negative of price in the data prior to estimating the model.

The data

This example uses the yogurt data set from Jain et al. (1994). The data set contains 2,412 choice observations from a series of yogurt purchases by a panel of 100 households in Springfield, Missouri, over a roughly two-year period. The data were collected by optical scanners and contain information about the price, brand, and a “feature” variable, which identifies whether a newspaper advertisement was shown to the customer. There are four brands of yogurt: Yoplait, Dannon, Weight Watchers, and Hiland, with market shares of 34%, 40%, 23% and 3%, respectively.

In the utility models described below, the data variables are represented as follows:

Symbol Variable
\(p\) The price in US dollars.
\(x_{j}^{\mathrm{Feat}}\) Dummy variable for whether the newspaper advertisement was shown to the customer.
\(x_{j}^{\mathrm{Hiland}}\) Dummy variable for the “Highland” brand.
\(x_{j}^{\mathrm{Weight}}\) Dummy variable for the “Weight Watchers” brand.
\(x_{j}^{\mathrm{Yoplait}}\) Dummy variable for the “Yoplait” brand.

Preference space model

This example will estimate the following mixed logit model in the preference space:

\[\begin{equation} u_{j} = \alpha p_{j} + \beta_1 x_{j}^{\mathrm{Feat}} + \beta_2 x_{j}^{\mathrm{Hiland}} + \beta_3 x_{j}^{\mathrm{Weight}} + \beta_4 x_{j}^{\mathrm{Yoplait}} + \varepsilon_{j} \label{eq:mnlPrefExample} \end{equation}\]

where the parameters \(\alpha\), \(\beta_1\), \(\beta_2\), \(\beta_3\), and \(\beta_4\) have units of utility. In the example below, we will model \(\beta_1\), \(\beta_2\), \(\beta_3\), and \(\beta_4\) as normally distributed across the population. As a result, the model will estimate a mean and standard deviation for each of these coefficients.

Note that since the yogurt data has a panel structure (i.e. multiple choice observations for each respondent), it is necessary to set the panelID argument to the id variable, which identifies the individual. This will use the panel version of the log-likelihood (see Train 2009 chapter 6, section 6.7 for details).

Finally, as with WTP space models, it is recommended to use a multistart search for mixed logit models as they are non-convex. This is implemented in the example below by setting numMultiStarts = 10:

library("logitr")

mxl_pref <- logitr(
  data     = yogurt,
  outcome  = 'choice',
  obsID    = 'obsID',
  panelID  = 'id',
  pars     = c('price', 'feat', 'brand'),
  randPars = c(feat = 'n', brand = 'n'),
  numMultiStarts = 10
)
#> Running multistart...
#>   Iterations: 10
#>   Cores: 3
#> Done!

Print a summary of the results:

summary(mxl_pref)
#> =================================================
#> 
#> Model estimated on: Fri Jun 03 11:49:52 2022 
#> 
#> Using logitr version: 0.6.0 
#> 
#> Call:
#> logitr(data = yogurt, outcome = "choice", obsID = "obsID", pars = c("price", 
#>     "feat", "brand"), randPars = c(feat = "n", brand = "n"), 
#>     panelID = "id", numMultiStarts = 10)
#> 
#> Frequencies of alternatives:
#>        1        2        3        4 
#> 0.402156 0.029436 0.229270 0.339138 
#> 
#> Summary Of Multistart Runs:
#>    Log Likelihood Iterations Exit Status
#> 1       -1266.550         34           3
#> 2       -1280.748         52           3
#> 3       -1265.998         43           3
#> 4       -1244.641         39           3
#> 5       -1265.435         64           3
#> 6       -1287.848         58           3
#> 7       -1272.385         50           3
#> 8       -1328.674         71           3
#> 9       -1274.295         70           3
#> 10      -1308.966         49           3
#> 
#> Use statusCodes() to view the meaning of each status code
#> 
#> Exit Status: 3, Optimization stopped because ftol_rel or ftol_abs was reached.
#>                              
#> Model Type:       Mixed Logit
#> Model Space:       Preference
#> Model Run:            4 of 10
#> Iterations:                39
#> Elapsed Time:        0h:0m:2s
#> Algorithm:     NLOPT_LD_LBFGS
#> Weights Used?:          FALSE
#> Panel ID:                  id
#> Robust?                 FALSE
#> 
#> Model Coefficients: 
#>                  Estimate Std. Error  z-value  Pr(>|z|)    
#> price           -0.462115   0.040195 -11.4969 < 2.2e-16 ***
#> feat             0.872419   0.184992   4.7160 2.405e-06 ***
#> brandhiland     -5.469771   0.375874 -14.5521 < 2.2e-16 ***
#> brandweight     -3.926602   0.365632 -10.7392 < 2.2e-16 ***
#> brandyoplait     2.533334   0.227397  11.1406 < 2.2e-16 ***
#> sd_feat          0.052732   0.228971   0.2303    0.8179    
#> sd_brandhiland  -2.000008   0.220070  -9.0880 < 2.2e-16 ***
#> sd_brandweight   6.337794   0.452727  13.9992 < 2.2e-16 ***
#> sd_brandyoplait  3.740190   0.232866  16.0615 < 2.2e-16 ***
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#>                                      
#> Log-Likelihood:         -1244.6405356
#> Null Log-Likelihood:    -3343.7419990
#> AIC:                     2507.2810711
#> BIC:                     2559.3750000
#> McFadden R2:                0.6277702
#> Adj McFadden R2:            0.6250786
#> Number of Observations:  2412.0000000
#> 
#> Summary of 10k Draws for Random Coefficients: 
#>              Min.      1st Qu.     Median      Mean    3rd Qu. Max.
#> feat         -Inf  0.836816107  0.8723785  0.872345  0.9079289  Inf
#> brandhiland  -Inf -6.817749618 -5.4691298 -5.467917 -4.1200815  Inf
#> brandweight  -Inf -8.204643354 -3.9318008 -3.936381  0.3422438  Inf
#> brandyoplait -Inf  0.005385916  2.5269304  2.523723  5.0492251  Inf

The above summary table prints summaries of the estimated coefficients as well as a summary table of the distribution of 10,000 population draws for each normally-distributed model coefficient. The results show that the feat attribute has a significant standard deviation coefficient, suggesting that there is considerable heterogeneity across the population for this attribute. In contrast, the brand coefficients have small and insignificant standard deviation coefficients.

Compute the WTP implied from the preference space model:

wtp_mxl_pref <- wtp(mxl_pref, price =  "price")
wtp_mxl_pref
#>                  Estimate Std. Error  z-value  Pr(>|z|)    
#> lambda            0.46211    0.04039  11.4414 < 2.2e-16 ***
#> feat              1.88788    0.47446   3.9790 6.921e-05 ***
#> brandhiland     -11.83638    1.03074 -11.4833 < 2.2e-16 ***
#> brandweight      -8.49702    1.08577  -7.8258 5.107e-15 ***
#> brandyoplait      5.48204    0.54393  10.0786 < 2.2e-16 ***
#> sd_feat           0.11411    0.49970   0.2284    0.8194    
#> sd_brandhiland   -4.32794    0.56923  -7.6031 2.887e-14 ***
#> sd_brandweight   13.71475    1.59186   8.6155 < 2.2e-16 ***
#> sd_brandyoplait   8.09363    0.82861   9.7677 < 2.2e-16 ***
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

WTP space model

This example will estimate the following mixed logit model in the WTP space:

\[\begin{equation} u_{j} = \lambda ( \omega_1 x_{j}^{\mathrm{Feat}} + \omega_2 x_{j}^{\mathrm{Hiland}} + \omega_3 x_{j}^{\mathrm{Weight}} + \omega_4 x_{j}^{\mathrm{Yoplait}} - p_{j}) + \varepsilon_{j} \label{eq:mnlWtpExample} \end{equation}\]

where the parameters \(\omega_1\), \(\omega_2\), \(\omega_3\), and \(\omega_4\) have units of dollars and \(\lambda\) is the scale parameter. In the example below, we will model \(\omega_1\), \(\omega_2\), \(\omega_3\), and \(\omega_4\) as normally distributed across the population. Note that this is a slightly different assumption than in the preference space model. In the WTP space, we are assuming that the WTP for these features is normally-distributed (as opposed to the preference space model where the utility coefficients are assumed to follow a normal distribution).

In the example below, we also use a 10-iteration multistart. We also set the starting values for the first iteration to the computed WTP from the preference space model:

mxl_wtp <- logitr(
  data       = yogurt,
  outcome    = 'choice',
  obsID      = 'obsID',
  panelID    = 'id',
  pars       = c('feat', 'brand'),
  price      = 'price',
  randPars   = c(feat = 'n', brand = 'n'),
  modelSpace = 'wtp',
  numMultiStarts = 10,
  startVals = wtp_mxl_pref$Estimate
)
#> Running multistart...
#>   Iterations: 10
#>   Cores: 3
#>   NOTE: Using user-provided starting values for first iteration
#> Done!

Print a summary of the results:

summary(mxl_wtp)
#> =================================================
#> 
#> Model estimated on: Fri Jun 03 11:50:05 2022 
#> 
#> Using logitr version: 0.6.0 
#> 
#> Call:
#> logitr(data = yogurt, outcome = "choice", obsID = "obsID", pars = c("feat", 
#>     "brand"), price = "price", randPars = c(feat = "n", brand = "n"), 
#>     modelSpace = "wtp", panelID = "id", startVals = wtp_mxl_pref$Estimate, 
#>     numMultiStarts = 10)
#> 
#> Frequencies of alternatives:
#>        1        2        3        4 
#> 0.402156 0.029436 0.229270 0.339138 
#> 
#> Summary Of Multistart Runs:
#>    Log Likelihood Iterations Exit Status
#> 1       -1239.294        129           3
#> 2       -1345.266        130           4
#> 3       -1256.886         70           3
#> 4       -1267.905         81           3
#> 5       -1345.497        119           4
#> 6       -1253.781         72           3
#> 7       -1255.878         60           3
#> 8       -1244.640         71           3
#> 9       -1275.792         90           3
#> 10      -1258.974         62           3
#> 
#> Use statusCodes() to view the meaning of each status code
#> 
#> Exit Status: 3, Optimization stopped because ftol_rel or ftol_abs was reached.
#>                                  
#> Model Type:           Mixed Logit
#> Model Space:   Willingness-to-Pay
#> Model Run:                1 of 10
#> Iterations:                   129
#> Elapsed Time:           0h:0m:16s
#> Algorithm:         NLOPT_LD_LBFGS
#> Weights Used?:              FALSE
#> Panel ID:                      id
#> Robust?                     FALSE
#> 
#> Model Coefficients: 
#>                   Estimate Std. Error  z-value  Pr(>|z|)    
#> lambda            0.448619   0.040011  11.2123 < 2.2e-16 ***
#> feat              1.732037   0.491936   3.5209 0.0004301 ***
#> brandhiland     -14.227513   1.366407 -10.4124 < 2.2e-16 ***
#> brandweight      -8.172564   0.956165  -8.5472 < 2.2e-16 ***
#> brandyoplait      2.503461   0.407102   6.1495 7.774e-10 ***
#> sd_feat           1.267864   0.497362   2.5492 0.0107977 *  
#> sd_brandhiland   -7.117527   0.944763  -7.5337 4.929e-14 ***
#> sd_brandweight    9.130796   0.923837   9.8836 < 2.2e-16 ***
#> sd_brandyoplait   7.269277   0.752668   9.6580 < 2.2e-16 ***
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#>                                      
#> Log-Likelihood:         -1239.2939893
#> Null Log-Likelihood:    -3343.7419990
#> AIC:                     2496.5879787
#> BIC:                     2548.6819000
#> McFadden R2:                0.6293691
#> Adj McFadden R2:            0.6266775
#> Number of Observations:  2412.0000000
#> 
#> Summary of 10k Draws for Random Coefficients: 
#>              Min.     1st Qu.     Median       Mean   3rd Qu. Max.
#> feat         -Inf   0.8760138   1.731068   1.730262  2.585831  Inf
#> brandhiland  -Inf -19.0246287 -14.225229 -14.220914 -9.424305  Inf
#> brandweight  -Inf -14.3358948  -8.180054  -8.186652 -2.022481  Inf
#> brandyoplait -Inf  -2.4097527   2.491015   2.484782  7.393241  Inf

If you want to compare the WTP from the two different model spaces, use the wtpCompare() function:

wtpCompare(mxl_pref, mxl_wtp, price = 'price')
#>                          pref           wtp  difference
#> lambda              0.4621152     0.4486187 -0.01349647
#> feat                1.8878818     1.7320369 -0.15584492
#> brandhiland       -11.8363815   -14.2275126 -2.39113109
#> brandweight        -8.4970203    -8.1725639  0.32445647
#> brandyoplait        5.4820400     2.5034609 -2.97857919
#> sd_feat             0.1141091     1.2678643  1.15375514
#> sd_brandhiland     -4.3279430    -7.1175272 -2.78958420
#> sd_brandweight     13.7147504     9.1307961 -4.58395432
#> sd_brandyoplait     8.0936327     7.2692772 -0.82435549
#> logLik          -1244.6405356 -1239.2939893  5.34654621

Note that the WTP will not necessarily be the same between preference space and WTP space MXL models. This is because the distributional assumptions in MXL models imply different distributions on WTP depending on the model space. See Train and Weeks (2005) and Sonnier, Ainslie, and Otter (2007) for details on this topic.

Correlated heterogeneity

By default, logitr assumes that mixed logit models have uncorrelated heterogeneity. However, correlated heterogeneity can be implemented by setting correlation = TRUE for models in either space (preference or WTP). The example below shows the results for the same mixed logit model in the preference space as above but now with correlated heterogeneity:

library("logitr")

mxl_pref_cor <- logitr(
  data     = yogurt,
  outcome  = 'choice',
  obsID    = 'obsID',
  panelID  = 'id',
  pars     = c('price', 'feat', 'brand'),
  randPars = c(feat = 'n', brand = 'n'),
  numMultiStarts = 10,
  correlation = TRUE
)
#> Running multistart...
#>   Iterations: 10
#>   Cores: 3
#> Done!

Print a summary of the results:

summary(mxl_pref_cor)
#> =================================================
#> 
#> Model estimated on: Fri Jun 03 11:48:47 2022 
#> 
#> Using logitr version: 0.6.0 
#> 
#> Call:
#> logitr(data = yogurt, outcome = "choice", obsID = "obsID", pars = c("price", 
#>     "feat", "brand"), randPars = c(feat = "n", brand = "n"), 
#>     panelID = "id", correlation = TRUE, numMultiStarts = 10)
#> 
#> Frequencies of alternatives:
#>        1        2        3        4 
#> 0.402156 0.029436 0.229270 0.339138 
#> 
#> Summary Of Multistart Runs:
#>    Log Likelihood Iterations Exit Status
#> 1       -1244.289         73           3
#> 2       -1277.641         68           3
#> 3       -1247.568         42           3
#> 4       -1238.784         45           3
#> 5       -1243.559         73           3
#> 6       -1243.559         53           3
#> 7       -1273.648         59           3
#> 8       -1235.918         39           3
#> 9       -1296.580         47           3
#> 10      -1250.394         63           3
#> 
#> Use statusCodes() to view the meaning of each status code
#> 
#> Exit Status: 3, Optimization stopped because ftol_rel or ftol_abs was reached.
#>                              
#> Model Type:       Mixed Logit
#> Model Space:       Preference
#> Model Run:            8 of 10
#> Iterations:                39
#> Elapsed Time:        0h:0m:3s
#> Algorithm:     NLOPT_LD_LBFGS
#> Weights Used?:          FALSE
#> Panel ID:                  id
#> Robust?                 FALSE
#> 
#> Model Coefficients: 
#>                               Estimate Std. Error  z-value  Pr(>|z|)    
#> price                        -0.441768   0.038759 -11.3979 < 2.2e-16 ***
#> feat                          0.856909   0.193140   4.4367 9.134e-06 ***
#> brandhiland                  -3.670086   0.339633 -10.8060 < 2.2e-16 ***
#> brandweight                  -1.359367   0.230555  -5.8961 3.723e-09 ***
#> brandyoplait                  1.322356   0.195921   6.7494 1.484e-11 ***
#> sd_feat_feat                 -0.156479   0.266773  -0.5866   0.55750    
#> sd_feat_brandhiland           0.541663   0.216926   2.4970   0.01253 *  
#> sd_feat_brandweight           0.068207   0.211578   0.3224   0.74717    
#> sd_feat_brandyoplait          0.323531   0.334673   0.9667   0.33369    
#> sd_brandhiland_brandhiland    2.475031   0.355262   6.9668 3.243e-12 ***
#> sd_brandhiland_brandweight    0.234401   0.229237   1.0225   0.30653    
#> sd_brandhiland_brandyoplait   1.527129   0.324500   4.7061 2.525e-06 ***
#> sd_brandweight_brandweight    3.162503   0.238017  13.2869 < 2.2e-16 ***
#> sd_brandweight_brandyoplait   3.982019   0.378310  10.5258 < 2.2e-16 ***
#> sd_brandyoplait_brandyoplait  4.205531   0.349567  12.0307 < 2.2e-16 ***
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#>                                      
#> Log-Likelihood:         -1235.9179290
#> Null Log-Likelihood:    -3343.7419990
#> AIC:                     2501.8358581
#> BIC:                     2588.6590000
#> McFadden R2:                0.6303788
#> Adj McFadden R2:            0.6258928
#> Number of Observations:  2412.0000000
#> 
#> Summary of 10k Draws for Random Coefficients: 
#>              Min.    1st Qu.     Median      Mean   3rd Qu. Max.
#> feat         -Inf  0.4177968  0.8569074  0.855689  1.297735  Inf
#> brandhiland  -Inf -5.6351796 -3.6684956 -3.676666 -1.706678  Inf
#> brandweight  -Inf -4.8111879 -1.3459269 -1.374478  2.063552  Inf
#> brandyoplait -Inf -1.5201097  1.3151560  1.311550  4.151265  Inf

References

Jain, Dipak C, Naufel J Vilcassim, and Pradeep K Chintagunta. 1994. “A Random-Coefficients Logit Brand-Choice Model Applied to Panel Data.” Journal of Business & Economic Statistics 12 (3): 317–28.
Sonnier, Garrett, Andrew Ainslie, and Thomas Otter. 2007. Heterogeneity distributions of willingness-to-pay in choice models.” Quant. Mark. Econ. 5 (3): 313–31. https://doi.org/10.1007/s11129-007-9024-6.
Train, Kenneth E., and Melvyn Weeks. 2005. Discrete Choice Models in Preference and Willingness-to-Pay Space.” In Appl. Simul. Methods Environ. Resour. Econ., 1–16.