The math behind choicer: mixed logit
Source:vignettes/articles/mixed_logit_math.Rmd
mixed_logit_math.RmdThis document provides a detailed mathematical description of the
mixed logit (random coefficients logit) model as implemented in
src/mxlogit.cpp.
Table of Contents
- Notation
- Model Definition
- Log-Likelihood Function
- Gradient Computation
- Hessian Computation
- Implementation Details
- Elasticity Computation
- Diversion Ratios
- BLP Contraction Mapping
- Choice-Based Sampling and WESML Weighting
- Willingness to Pay
- Consumer Surplus and the Simulated Logsum
- Goodness of Fit
Notation
| Symbol | Description |
|---|---|
| Index for individuals (choice situations) | |
| Index for alternatives available to individual | |
| Index for simulation draws | |
| The alternative chosen by individual | |
| Weight for individual | |
| Row vector of covariates with fixed coefficients () | |
| Row vector of covariates with random coefficients () | |
| Fixed coefficient vector () | |
| Mean parameters for random coefficients () | |
| Lower-triangular Cholesky factor () | |
| Covariance matrix of the latent Gaussian deviations (and of realized coefficients only in the all-normal case) | |
| Alternative-specific constant (ASC) for alternative | |
| Standard-normal integration draw for choice situation and draw () | |
| Latent Gaussian random-coefficient deviation |
1. Model Definition
1.1 Utility Specification
The utility that individual derives from alternative under simulation draw is:
where: - captures the systematic utility from fixed coefficients - captures the mean contribution of random coefficients - captures the individual-specific random deviation - is the alternative-specific constant (the first inside ASC is normalized without an outside option; with an outside option all inside ASCs are free)
1.2 Random Coefficient Structure
Random coefficients are generated through a Cholesky decomposition structure:
This implies:
For finite parameter values the exponentiated diagonal makes nonsingular, so is positive definite (positive semidefinite in the limiting sense as a diagonal element tends to zero). Here is the covariance of the latent Gaussian deviation . It is the covariance of the realized coefficient vector only when all entries are normal. After any componentwise log-normal transformation, the realized coefficient covariance is a nonlinear function of and is not .
1.3 Distribution Transformations
The implementation supports two distributions for each random coefficient :
Normal Distribution (rc_dist[k] = 0):
Log-Normal Distribution
(rc_dist[k] = 1):
Note: This is a shifted log-normal parameterization: , which differs from the textbook parameterization .
When rc_mean = FALSE,
for every distribution. Thus a normal random coefficient is centered at
zero, while a log-normal random coefficient is
and has median one. Correlation is introduced on the latent-normal scale
by the rows of
;
componentwise transformations then induce a generally non-Gaussian joint
coefficient distribution.
1.4 Cholesky Parameterization
For a full covariance matrix (rc_correlation = TRUE),
the lower-triangular matrix
is parameterized as:
where: - Diagonal elements: (ensures positivity) - Off-diagonal elements: for (unconstrained)
For diagonal-only covariance
(rc_correlation = FALSE):
The parameter vector for has length: - Full: - Diagonal:
1.5 Variable Scaling
Motivation. When columns of and span very different magnitudes — e.g., a price variable in thousands alongside a binary dummy — the Hessian can become ill-conditioned and L-BFGS step sizes can mismatch across parameter blocks. Dividing columns by comparable scale denominators reduces this unit-driven conditioning problem and can substantially accelerate convergence; it does not guarantee a well-conditioned Hessian when the design is intrinsically weak or collinear.
Why centering is omitted. Without an outside option, subtracting a global column mean from every alternative shifts every utility in a situation by the same amount, which cancels from the softmax; the same argument applies draw by draw to . With an implicit outside option fixed at utility zero, however, an inside-only common shift does not cancel against the outside. A fixed- shift can be offset only by a compensating shift to every inside ASC when those ASCs are present, and a random shift cannot generally be absorbed by fixed ASCs. The implementation therefore does not center: it divides by a scale denominator only. This preserves the exact outside-option specification as well as the 0/1 structure of dummy columns and avoids unnecessary mean bookkeeping.
The transformation. Let and . Define scaled matrices
Estimation runs on . Let denote the parameter estimates in the scaled space.
Back-transformation. After optimization, parameters are mapped back to natural units:
| Parameter | Natural-scale value |
|---|---|
| (normal RC) | |
| (Cholesky diagonal, stored as ) | |
| (Cholesky off-diagonal, ) | |
| (unchanged) |
For the Cholesky rows, implies to preserve . Therefore the back-transform divides row by . On the diagonal — where is stored as — division becomes an additive shift (); for off-diagonal entries it is direct division (). Note that the scale factor is keyed on the row index in both cases, not on the column index .
Variance-covariance. The back-transform is linear in the stored parameters, so the delta method gives
where is the diagonal Jacobian of the natural-from-scaled map: entries are for , for , for (additive shift carries no scale factor on variance), for , and for ASCs.
Log-normal random coefficients. The shifted
log-normal parameterization
does not admit a closed-form back-transform under multiplicative column
scaling: dividing the full distribution of
by
cannot be re-expressed as a single shifted log-normal with shifted
,
because the two
terms cannot share a common scale factor. The implementation therefore
passes log-normal
columns through unscaled:
whenever rc_dist[k] == 1. The user retains responsibility
for choosing reasonable units for log-normal RC variables.
Alternative scale denominators. The
scale_vars option also accepts "mad"
(stats::mad, equal to
)
and "iqr" (stats::IQR(x) / 1.349); both are
SD-equivalent under normality and yield the same Jacobian construction
as "sd" — only the per-column denominator
(or
)
differs. The robust denominators are preferable when heavy-tailed
columns cause the sample SD to be dominated by outliers.
1.6 Sampling Unit and Cross-Sectional Mixing
In this implementation
indexes a choice situation, and the likelihood
integrates a separate coefficient distribution for each situation.
Reusing a person identifier as though several tasks formed a panel does
not create a shared latent coefficient across those tasks. Consequently
run_mxlogit() is a cross-sectional mixed-logit likelihood;
cluster-robust standard errors can allow score dependence across
repeated tasks but cannot turn that likelihood into a panel
random-coefficients model. The package’s panel random-coefficients path
is run_hmnlogit().
2. Log-Likelihood Function
2.1 Choice Probability
For a given draw , the probability that individual chooses alternative follows the logit formula:
If an outside option is included, it is normalized to .
2.2 Simulated Probability
Since the random coefficients are unobserved, we integrate over their distribution using simulation:
where is the alternative chosen by individual .
2.4 Log-Sum-Exp Trick for Numerical Stability
To avoid numerical overflow/underflow, the implementation uses:
Probability computation: Before computing , subtract :
-
Log-probability averaging: Use log-sum-exp to compute :
Applied iteratively across draws .
2.5 Statistical Properties of the Finite-Draw Criterion
For independent pseudo-random draws, is an unbiased simulator of the exact mixed-logit probability. Its logarithm is not: Jensen’s inequality gives when the simulator is nondegenerate, and a second-order expansion gives the familiar criterion bias. Under the regularity conditions in Hajivassiliou and Ruud (1994), Lee (1995), Gouriéroux and Monfort (1996), and Train (2009, Ch. 10), the classical pseudo-random MSL benchmarks are:
- Fixed : MSL is inconsistent — the simulation bias does not vanish as .
- with (at any rate): MSL is consistent.
- rising faster than : MSL is asymptotically equivalent to exact maximum likelihood — simulation bias is and simulation variance is negligible under the maintained draw scheme.
choicer uses a Halton sequence rather than independent
pseudo-random draws (§5.4), so the first sentence above is not a literal
property of its deterministic store-mode simulator, and the
pseudo-random rate conditions should not be quoted as an exact theorem
for this implementation. Quasi-Monte Carlo often reduces integration
error markedly at a given
(Bhat 2003), but its error depends on integrand smoothness, dimension,
sequence construction, and randomization. The operational implication is
to treat
and, for generated scrambled draws, the seed as part of the numerical
specification; increase
until estimates, the Cholesky block, the objective, and standard errors
stabilize. mc_asymptotics() supplies Monte Carlo
diagnostics rather than a proof that a particular
finite-
fit satisfies exact-ML asymptotics.
3. Gradient Computation
3.1 General Formula
Define for draw the log-probability of the chosen alternative:
The gradient of this with respect to utility is:
3.2 Per-Draw Gradient
Define as the gradient of utility with respect to parameters. The per-draw gradient is:
Vectorized implementation. Define the logit residual vector with elements . The per-block gradient components collapse to matrix-vector products — computed once per draw rather than looped over alternatives:
| Block | Scalar sum | Vectorized form |
|---|---|---|
where
(Wt_diff in the code) is computed once and shared across
the
and
blocks. The
block uses an irregular alt-index scatter and is kept as a loop.
Code reference: src/mxlogit.cpp
3.3 Gradient of Simulated Log-Likelihood
Using the identity for the derivative of a logarithm of a sum:
The full gradient is:
Code reference: src/mxlogit.cpp
3.4 Utility Derivatives by Parameter Block
3.4.2 Random Coefficient Means ()
For Normal distribution:
For Log-Normal distribution:
Both cases are captured by dmu_final_dmu(p)
(
for normal,
for log-normal). Summing over alternatives:
.
Code reference: src/mxlogit.cpp
3.4.3 Cholesky Parameters ()
Let denote the parameter for (where ).
Step 1: Derivative of with respect to :
Step 2: Derivative of with respect to :
Note: , so only the term with contributes.
Step 3: Derivative of transformed :
For Normal distribution:
For Log-Normal distribution:
Step 4: Chain rule for utility derivative:
Step 5: Summing over alternatives using :
For the diagonal case, all
parameters are computed simultaneously as
Wt_diff % dgamma_final_dgamma % L.diag() % eta_i_s. For the
full correlated case,
Wt_p = Wt_diff(p) * dgamma_final_dgamma(p) is factored out
per row
.
Code reference: src/mxlogit.cpp
3.4.4 Alternative-Specific Constants ()
where (normalized) if no outside option, or all for are free if outside option is included. The sum over alternatives is a simple scatter (one non-zero contribution per alternative), implemented as a loop.
Code reference: src/mxlogit.cpp
4. Hessian Computation
4.1 General Formula
Define: - — the gradient for individual - — the per-draw gradient - — the per-draw Hessian
The Hessian of the simulated log-probability for individual is:
The full Hessian is:
Code reference: src/mxlogit.cpp
4.2 Per-Draw Hessian
The per-draw Hessian has the form:
where is the Hessian of utility.
In the code, this is computed as: - sum_Pzz
- sum_Pz
- sum_diff_H_V
Then:
Code reference: src/mxlogit.cpp
4.3 Second Derivatives of Utility
Most second derivatives are zero since utility is linear in most parameters. Non-zero second derivatives arise from:
4.3.1 Mean Parameters () — Log-Normal Only
For log-normal distribution:
Code reference: src/mxlogit.cpp
4.3.2 Cholesky Diagonal Parameters ()
Since :
For normal distribution:
For log-normal distribution (combining chain rule):
where .
Code reference: src/mxlogit.cpp
4.3.3 Cholesky Cross-Derivatives Within a Row
Let with and define
Distinct Cholesky parameters affect the same transformed coefficient only when they belong to the same row . Their cross derivative is
where for a normal coefficient and for a log-normal coefficient. Hence the cross derivative is zero for normal coefficients and equals for log-normal coefficients. This expression also covers a diagonal/off-diagonal pair (say ); restricting both indices to be off-diagonal would omit terms that the C++ Hessian includes. Cross derivatives across different rows of are zero. The separate shifted term implies no – cross derivative.
Code reference: src/mxlogit.cpp
4.4 Implementation Tricks in mxl_hessian_parallel
The four subsections below describe the computational restructuring
used by mxl_hessian_parallel. They cover (i) a block
decomposition of the score vector and Hessian terms, (ii) buffer
accumulation that eliminates the per-draw dense matrix allocation, (iii)
BLAS-3 batching of two outer-product sums, and (iv) the symmetry
strategy used for final assembly.
A reader who has never seen the C++ can understand what the function does and why the result is numerically equivalent to the per-draw naive form (§4.1–4.2) from the following four sections alone.
4.4.1 Parameter Block Layout and Score Vector Decomposition
The parameter vector is partitioned into a continuous block of length and a delta block (ASCs) of length :
The boundary index
is stored as idx_delta_start in the code.
The per-draw score vector inherits this partition: . The continuous sub-vector is
where is the continuous-block utility gradient for alternative at draw . The delta sub-vector scatters logit residuals into the ASC index for each alternative.
Define also: - (the cc weighted-score sum, plus a -length delta counterpart ), - (, symmetric), and its cd () and dd (diagonal -vector) sub-blocks.
4.4.2 Block Buffer Accumulation — Identity C
Two of the three terms in (§4.2) are linear in the draw weight :
Their draw-weighted sum can therefore be accumulated directly into per-individual buffer matrices without constructing the full dense matrix at each draw:
Each buffer is updated at the end of draw
with a single scalar-times-matrix addition
(buf += P_s * block_s), replacing the original path that
assembled the full
and then computed
hess_term1_numerator += P_s * (g_is * g_isᵀ + H_is).
The block structure of buf_Pzz minimizes memory by
storing only the three structurally distinct sub-blocks:
| Buffer | Shape | Content | Notes |
|---|---|---|---|
buf_Pzz_cc |
Symmetric | ||
buf_Pzz_cd |
Rectangular; not symmetric | ||
buf_Pzz_dd |
-vector | Diagonal only | |
buf_diff_HV_cc |
Symmetric; cc block only ( has no delta rows) |
All four buffers are thread-private scratch allocated once per thread outside the -loop and zeroed at the start of each individual .
4.4.3 BLAS-3 Batching of Outer-Product Sums — Identities A and B
The third term in — — is not linear in , so it cannot go into a linear buffer. Instead, together with the OPG term , it is handled by reformulating both weighted outer-product sums as a single BLAS level-3 matrix multiply.
Identity A (OPG batching). Define the matrix with columns
Then
Proof.
.
The identity is exact in real arithmetic and requires only
,
which holds because
is a softmax probability (guaranteed by
stable_softmax).
Identity B (sum-Pz outer-product batching). Define the matrix with columns
Then
The proof is identical to Identity A.
Combined BLAS-3 form. Concatenating and into and forming one matrix product gives
because
and the block multiply sums over
columns with no
-
cross term. This is the form implemented in
mxl_hessian_parallel: G_stash and
F_stash are filled column-by-column during the
-loop,
and after the loop
GF = join_rows(G_stash, F_stash); opg_pz = GF * GF.t()
delivers
in a single cache-friendly level-3 kernel.
Floating-point precision. Changing the summation
order (per-draw increments vs. one level-3 multiply) is a reassociation
of additions that is exact in real arithmetic. In floating-point the
results differ only by rounding. Across 10 equivalence scenarios
sweeping all combinations of rc_dist,
rc_correlation, and rc_mean, the worst-case
element-wise deviation from the per-draw form was
,
several orders of magnitude below the
tolerance enforced by the package’s equivalence tests.
4.4.4 Optional Per-Draw Batching of sum_Pzz_cc —
Identity D
Within each draw
,
the cc sub-block of sum_Pzz accumulates per-alternative
rank-1 updates:
This can equivalently be expressed as a single matrix product:
where
and
counts the active (non-outside-option) alternatives. One
dsyrk call per draw over
columns would replace
individual dsyr rank-1 updates. The identity holds by the
same
argument as Identities A and B.
Implementation choice. The implementation retains
the per-alternative rank-1 accumulation
(sum_Pzz_cc += P_a * (zc_a * zc_a.t())). Both forms are
correct; the result flows into buf_Pzz_cc via the Identity
C scalar-times-matrix step at the end of each draw. Identity D is
recorded here to establish that the batched form is available without
changing any result; the per-alternative form is kept for
auditability.
4.4.5 Final Assembly and Symmetry
After the -loop for individual , define and let . The numerator is assembled block-by-block:
The cd block is rectangular
()
and not symmetric, so both the cd and dc sub-matrices are written
explicitly into hess_t1. The remaining finalization steps
are unchanged from the original code:
Symmetry strategy. The Hessian
is symmetric. The current code uses a full-matrix approach:
buf_Pzz_cc and buf_diff_HV_cc are accumulated
as full symmetric matrices (the existing per-alternative loop writes
both
and
positions for off-diagonal
-
entries in sum_diff_H_V_cc, and this is retained
unchanged), and the outer product
is computed in full. An alternative upper-triangle-only strategy —
accumulating only the upper triangle in the cc buffers and mirroring
once before the OpenMP critical merge — would halve the work for those
buffers. It was deferred because the asymmetric cd block requires
explicit transposition regardless, and the full-matrix path is simpler
to audit.
5. Implementation Details
5.1 Parameter Vector Structure
The full parameter vector is organized as:
| Block | Indices | Length | Description |
|---|---|---|---|
| Fixed coefficients | |||
(if rc_mean=TRUE) |
Random coefficient means | ||
| next block | or | Cholesky parameters | |
| remaining | , , or | Free ASCs |
The ASC length is zero when use_asc = FALSE,
without an outside option, and
with an outside option. The low-level parser requires at least one
fixed-coefficient column
(),
even when the substantive focus is entirely on random coefficients.
5.2 Delta Method for Variance Parameters
When reporting results, the Cholesky parameters are transformed to variance matrix elements .
The Jacobian
is computed analytically in jacobian_vech_Sigma().
For element :
This follows from the product rule applied to : , where is the matrix with a single non-zero entry .
The variance-covariance matrix of is then:
Code reference: src/mxlogit.cpp
5.3 OpenMP Parallelization
The implementation parallelizes over individuals using OpenMP: - Each
thread maintains local accumulators for log-likelihood and
gradient/Hessian - Thread results are combined using
#pragma omp critical sections - Dynamic scheduling is used
for load balancing: #pragma omp for schedule(dynamic)
5.4 Practical Notes
Negated Objectives:
mxl_loglik_gradient_parallelreturns and ;mxl_hessian_parallelreturns . The BHHH kernel instead returns the positive-semidefinite information approximation .ASC Identification: When
include_outside_option = FALSE, the first inside alternative’s ASC () is fixed to zero for identification. Wheninclude_outside_option = TRUE, all inside ASCs are free parameters (the outside option with serves as the reference).Gradient vectorization: The per-draw gradient is computed without a per-alternative loop. After forming , the and / blocks are evaluated with two BLAS dgemv calls ( and ). The delta block uses an irregular scatter and remains a loop.
Exact draw layout and source: In both modes, situation receives the contiguous global indices for ; dimension uses the th prime base and the resulting uniform is mapped through the standard-normal inverse CDF. In
draws = "store",randtoolbox::halton(n = N*S, dim = K_w, normal = TRUE)is materialized as a cube during estimation. The fitted object retains onlydraws_infometadata and post-estimation regenerates the cube; it does not retain the cube itself. This mode is deterministic and has no seed or scramble. Indraws = "generate",HaltonGencomputes the radical inverse on demand.scramble = "none"uses identity permutations and is tested against therandtoolboxsequence.scramble = "permuted"(the default) constructs one independently seeded Fisher–Yates permutation for every (dimension, digit-position) pair and shares that table across sequence indices. Evaluation stops after the last nonzero base- digit, so trailing zero digits remain unchanged. This is not Owen nested-uniform scrambling: the digit permutation does not depend on the preceding digit prefix, and the construction does not make each point marginally uniform. Consequently it carries no standard RQMC unbiasedness, variance-rate, or replicate-based error-estimation guarantee. The historical API value"owen"is a deprecated alias for"permuted"; old fitted objects carrying that serialized label remain readable. The result is deterministic conditional on the seed and independent of OpenMP scheduling. Numerical sensitivity should be assessed by increasing and, for permuted draws, varying the seed. Generate mode is available only through the convenience data workflow; the advancedinput_dataworkflow requires an expliciteta_drawscube.Finite-value guards: The likelihood/gradient kernel replaces a non-finite global negated objective by and a zero gradient, allowing the optimizer’s line search to backtrack; isolated non-finite gradient entries are zeroed. The Hessian contributes situation only when . These are numerical failure guards, not changes to the mathematical criterion in its regular finite region.
5.5 Data Layout
- has rows and is sliced by prefix sums into situation blocks.
-
may be row-aligned with
or have one row per global inside alternative; the internal
make_W_i()either slices the situation block or gathers rows by the global 1-basedalt_idx. The convenience R workflow constructs the row-aligned form. -
choice_idxis a 1-based local row position within each situation block, or 0 for an implicit outside choice.alt_idxis instead the global alternative ID used to gather ASCs and alternative-level rows. - Stored draws have dimensions
.
Generate-mode kernels receive an empty placeholder cube plus
gen_seed,gen_scramble, andgen_S.
6. Elasticity Computation
6.1 Elasticity Definitions
The elasticity measures the percentage change in choice probability with respect to a percentage change in an attribute. For the mixed logit model, we compute elasticities using simulated probabilities.
Simulated Probability:
6.2 Elasticity for Fixed Coefficients (X Variables)
For a variable in the design matrix with fixed coefficient :
Own-Elasticity (elasticity of with respect to ):
Using the chain rule and averaging over draws:
Cross-Elasticity (elasticity of with respect to where ):
6.3 Elasticity for Random Coefficients (W Variables)
For a variable in the design matrix with random coefficient, the effective coefficient for individual and draw is:
where: - For normal distribution: , - For log-normal distribution: ,
Own-Elasticity:
Cross-Elasticity:
6.4 Weighted Average of Individual Elasticities
The implementation computes weighted average individual probability elasticities:
This is not generally the elasticity of an aggregate share under a common market-level perturbation. Rows index responding alternatives and columns perturbed alternatives. The kernel sets a contribution to zero when and divides the accumulated matrix by total weight over all situations; with ordinary finite utilities, the threshold is only a numerical guard.
Code reference: mxlogit.cpp:mxl_elasticities_parallel
7. Diversion Ratios
7.1 Definition
The attribute-based diversion ratio from alternative to alternative with respect to attribute is
where is the aggregate share. It is the fraction of demand lost by that is captured by when a marginal change in ’s attribute reduces .
7.2 MNL Special Case (β cancels)
For multinomial logit, the per-individual derivatives of the choice probability are
Letting , the aggregate share derivatives are
Because is a scalar constant, it pulls out of both weighted sums. Forming the ratio,
with and cancelling. The result is independent of which attribute is perturbed — this is a special property of MNL.
7.3 MXL: β Does Not Cancel
For mixed logit the realized coefficient on a random variable for individual at draw is
with the same distribution transforms as in §6.3. The derivatives evaluated at draw are
Integrating over draws gives and similarly for the cross term. Aggregating over individuals, the diversion ratio is
Because varies across , it cannot be pulled out of the sums and does not cancel. The MXL diversion ratio therefore depends on the perturbed variable. For a variable with a fixed coefficient the dependence again vanishes ( is a constant scalar); for a random-coefficient variable it does not.
7.4 Properties
Column-sum identity. For each , . This follows from , which holds inside the draw sum and is preserved through the same weight on both sides.
Sign of
.
If
is constant negative (e.g. a fixed price coefficient), both numerator
and denominator change sign together and the ratio is unchanged — DR is
non-negative. With a random coefficient of mixed sign across
,
terms can partially cancel; the aggregate ratio is still well-defined
but can be numerically sensitive. The implementation guards against this
with an abs(denominator) > 1e-15 check.
Implementation. Cross-products and must be accumulated inside the per-draw loop, multiplied by at that point, and only then averaged across draws and weighted by . Computing or -weighted averages computed outside the draw loop is biased.
Code reference: mxlogit.cpp:mxl_diversion_ratios_parallel
8. BLP Contraction Mapping
8.1 Problem Statement
Given observed market shares , find the ASC parameters such that the model-predicted shares match the observed shares:
where is the predicted market share for alternative computed using simulated probabilities.
8.2 Simulated Market Shares
The predicted market share for alternative is:
where:
and is the probability for individual , alternative , and draw , which depends on through the utility specification.
8.3 Contraction Mapping Algorithm
The Berry–Levinsohn–Pakes fixed-point iteration is:
This can be written in vector form as:
The target must be feasible and strictly positive. The kernel checks positivity of the inside target and predicted shares but does not verify that the full target sums to one.
8.4 Implementation Details
-
No outside option.
deltamay be the full length- vector or the free length- block; the latter is padded with a leading zero. The first element is subtracted initially and after every update, and the returned vector has length with its baseline entry equal to zero. -
Outside option.
deltahas length and contains inside ASCs only. The outside utility remains zero, the update uses only the inside components of target and predicted shares, and no inside ASC is re-centered. A coherent target outside share is matched only indirectly because all shares sum to one. -
Stopping. The residual is the largest absolute
inside-delta change. On reaching
max_iter, the kernel prints a warning and returns the last completed iterate.
The public blp.choicer_mxl() method resolves the fitted
draw metadata through .mxl_gen_params(): store-mode fits
regenerate the materialized plain-Halton cube, while generate-mode fits
pass the original seed, permutation mode, and
to the contraction kernel. Share inversion therefore uses the same
deterministic integration rule as the fit.
Code reference: mxlogit.cpp:mxl_blp_contraction
9. Choice-Based Sampling and WESML Weighting
9.1 Endogenous Stratified (Choice-Based) Sampling
In random (exogenous) sampling each choice situation is drawn independently of its outcome. Under choice-based (endogenous stratified) sampling the strata are defined by the chosen alternative , and situations are drawn with stratum-specific frequencies – for example, deliberately oversampling the few individuals who chose a rare alternative. Let
Maximum simulated likelihood applied naively to such a sample is generally inconsistent for the population parameters. (A known special case: in a pure multinomial logit with a full set of alternative-specific constants, choice-based sampling biases only the constants; in general – and for the mixed logit – both the slopes and the constants are affected.)
9.2 The WESML Weighted Log-Likelihood
Manski and Lerman (1977) restore consistency by weighting each situation’s contribution by the ratio of population to sample share of its chosen alternative,
which yields the weighted simulated log-likelihood already defined in $$2.3,
The maximizer is invariant to multiplying every by a common positive constant (the objective is merely rescaled), so the weights may be normalized to mean 1 without changing the estimates.
9.3 Robust (Sandwich) Variance: the Meat
WESML is a weighted M-estimator solving , where is the per-situation score ($$3) and its Hessian ($$4). Its robust (Huber–White) asymptotic variance is the sandwich
The weight enters the bread linearly, but the meat carries the weight squared: the contribution of situation to the estimating equation is , so the variance of that contribution involves .
This is exactly why the two naive variances are wrong under weighting:
- the inverse-Hessian assumes the information-matrix equality , which fails once the are non-degenerate;
- the ordinary BHHH/OPG uses the weight to the first power, not the second.
A consistency check: rescaling all weights by a constant sends and , so – the sandwich is invariant to the weight scale, whereas is not.
9.4 Scope: Robust vs. Design-Based Variance
The estimator implemented here is the robust weighted-M-estimator (Huber–White) variance, whose meat is uncentered. This is the asymptotic variance under variable-probability sampling (each population unit sampled independently with a stratum-dependent probability). Under a fixed-quota design – a prescribed number drawn from each choice stratum, i.e. standard stratified sampling – the design-based variance centers the scores within strata and may be smaller; that stratum-centered (design-based) estimator is out of scope here. See Manski & McFadden (1981) for the design-based treatment and Cosslett (1981) for the asymptotically efficient conditional-maximum-likelihood alternative.
9.5 Implementation and Cluster-Robust Extension
The common post-estimation path computes the
matrix
of weight-free scores with mxl_scores_parallel, using the
fit’s stored or generated draw metadata, and forms
The eager fit-time path is algebraically identical and can obtain the
meat from the BHHH kernel with weights = w^2. The matrices
are combined as
.
For clusters
,
the alternative meat is
with no finite-cluster correction. Clustering changes inference, not
the cross-sectional likelihood described in §1.6. The variable-scaling
back-transform
($$
delta method ($$5.2) apply on top, exactly as for any stored
vcov. User-facing entry points:
wesml_weights() and sample_by_choice() build
the weights; run_mxlogit(..., se_method = "sandwich")
estimates with the robust variance; wesml_vcov() returns it
post hoc.
Code reference: mxl_scores_parallel() /
mxl_bhhh_parallel() in src/mxlogit.cpp;
compute_sandwich_vcov(), .score_meat(), and
.assemble_score_vcov() in R/classes.R;
wesml_weights() / sample_by_choice() in R/sampling.R.
10. Willingness to Pay
10.1 Fixed Coefficients
When the price variable has a fixed coefficient (a column of ), the WTP for any fixed attribute is the usual marginal rate of substitution, with the same analytic delta-method SE as in the MNL case (§8 of the MNL document):
10.2 Random Coefficients
For a random attribute coefficient the WTP is itself a random variable , and a scalar summary must be chosen. The summaries reported follow the package’s parameterization (§1.3):
Normal RC with estimated mean
(rc_mean = TRUE, rc_dist[k] = 0):
has mean
,
so the mean WTP is
with the linear-ratio gradient of §10.1 applied to .
Shifted log-normal RC with estimated location
(rc_mean = TRUE, rc_dist[k] = 1):
.
Since
is monotone in the normal draw
and the median of
is
,
the population median is
and the median WTP is
The median is preferred to the mean, with , because the mean is highly sensitive to the estimated variance (a thin right tail dominates it).
Shifted log-normal RC without location
(rc_mean = FALSE, rc_dist[k] = 1):
has median exactly 1, so the median WTP is
with
— uncertainty comes solely from
.
Normal RC without mean
(rc_mean = FALSE, rc_dist[k] = 0): the mean is
0 by construction; no WTP row is reported.
10.3 Random Price Coefficients Are Rejected
The implementation requires price_var to be a
fixed-coefficient column of
and rejects every random price coefficient. For a normally distributed
denominator this is substantively important: positive density
arbitrarily close to zero generally makes
diverge. That no-moment argument does not cover every
possible mixing distribution—for example, inverse moments of a
sign-constrained log-normal can be finite—but wtp() still
does not simulate the joint ratio distribution, account for its
correlation, or report its quantiles. Thus the rejection is both a
specification guard for normal price mixing and an implementation
boundary for other distributions. WTP-space estimation (Train and Weeks
2005) is not implemented in choicer v0.2.0.
Code reference: R/wtp.R
11. Consumer Surplus and the Simulated Logsum
11.1 Expected Logsum
Conditional on a coefficient realization
,
expected maximum utility over the iid type-I extreme-value errors is
,
where
is Euler’s constant. As in the other package methods,
logsum() omits this scenario-invariant additive constant.
The mixed-logit logsum integrates over the mixing distribution:
simulated over the same deterministic Halton draws used in estimation (regenerated from the stored draw metadata), with the outside option contributing in each draw’s sum when present, and the max-subtraction trick applied per draw.
Order of operations matters. The log-sum-exp function is convex, so by Jensen’s inequality
with strict inequality when the draws induce non-common variation in
utilities. A nondegenerate
alone is not sufficient for strictness: if the random contribution is
the same additive shift for every available alternative, log-sum-exp is
affine in that direction and equality holds. A dedicated C++ kernel
(mxl_logsum) computes the per-draw logsum and then averages
across draws.
11.2 Expected Consumer Surplus
With a fixed price coefficient (the marginal utility of income is then nonrandom):
A random price coefficient is rejected for the capability and specification reasons in §10.3; the divergence argument applies directly to normal price mixing but not to every sign-constrained distribution. As in MNL, the formula assumes no income effects. The routine does not enforce ; the economic interpretation as positive marginal utility of income requires the analyst to verify that sign. CS levels inherit the ASC normalization, so only differences across counterfactual scenarios are meaningful. The implementation reports point estimates for MXL (the delta-method SE of mean CS is currently provided for MNL only); Krinsky–Robb resampling is a practical interval method.
Code reference: R/surplus.R;
kernel in src/mxlogit.cpp
(mxl_logsum)
12. Goodness of Fit
The measures are model-agnostic and identical to §10 of the MNL document, computed from the simulated log-likelihood and simulated choice probabilities:
- McFadden pseudo R²: , adjusted , with counting all estimated parameters (, , Cholesky block, ASCs).
- Equal-shares null (default; exact for unbalanced choice sets and weights): .
- Market-shares null (constants-only closed form): , where is the common weight, valid only for identical choice-set composition and uniform weights. The constants-only model contains no random coefficients, so the MNL closed form applies unchanged.
- Hit rate: weighted share of choice situations whose observed choice has the highest simulated probability ; with an outside option, the kernel returns the simulated outside probability directly and the outside good competes for the maximum.
Code reference: R/gof.R
References
- Train, K. E. (2009). Discrete Choice Methods with Simulation. Cambridge University Press.
- Train, K., & Weeks, M. (2005). Discrete choice models in preference space and willingness-to-pay space. In R. Scarpa & A. Alberini (Eds.), Applications of Simulation Methods in Environmental and Resource Economics (pp. 1-16). Springer.
- McFadden, D., & Train, K. (2000). Mixed MNL models for discrete response. Journal of Applied Econometrics, 15(5), 447-470.
- Berry, S., Levinsohn, J., & Pakes, A. (1995). Automobile prices in market equilibrium. Econometrica, 63(4), 841-890.
- Bhat, C. R. (2003). Simulation estimation of mixed discrete choice models using randomized and scrambled Halton sequences. Transportation Research Part B, 37(9), 837-855.
- Gouriéroux, C., & Monfort, A. (1996). Simulation-Based Econometric Methods. Oxford University Press.
- Hajivassiliou, V. A., & Ruud, P. A. (1994). Classical estimation methods for LDV models using simulation. In R. F. Engle & D. L. McFadden (Eds.), Handbook of Econometrics, Vol. 4 (pp. 2383-2441). North-Holland.
- Lee, L.-F. (1995). Asymptotic bias in simulated maximum likelihood estimation of discrete choice models. Econometric Theory, 11(3), 437-483.
- Manski, C. F., & Lerman, S. R. (1977). The estimation of choice probabilities from choice based samples. Econometrica, 45(8), 1977-1988.
- Manski, C. F., & McFadden, D. (1981). Alternative estimators and sample designs for discrete choice analysis. In Structural Analysis of Discrete Data with Econometric Applications. MIT Press.
- Cosslett, S. R. (1981). Maximum likelihood estimator for choice-based samples. Econometrica, 49(5), 1289-1316.
- Wooldridge, J. M. (2010). Econometric Analysis of Cross Section and Panel Data (2nd ed.), Section 13.8. MIT Press.