The math behind choicer: hierarchical Bayesian multinomial logit
Source:vignettes/articles/hierarchical_mnl_math.Rmd
hierarchical_mnl_math.RmdThis article gives a self-contained description of the hierarchical
Bayesian multinomial logit (HMNL) implemented by
run_hmnlogit() and src/hmnlogit.cpp. Shared
hierarchical conditionals are in src/hb_internal.h;
sampling and RNG primitives are in src/bayes_samplers.h and
src/rng.h. Equations below describe the implementation,
including its identification convention, adaptive Metropolis targets,
retained draws, and numerical approximations.
1. Indices, data, and dimensions
Respondents are . Respondent faces tasks . Let denote the observed set of inside alternatives and let denote an implicit outside option. Choice sets may be unbalanced. For an inside row ,
- is the structural design vector; no ASC dummies are included;
- is the time-invariant alternative-level design, whose first element is an intercept;
- is the observed choice.
person_col defines respondents. If it is absent, every
task is assigned its own respondent and
.
The data engine stores inside rows only, plus task sizes, respondent
task counts, the chosen within-task position (zero for outside), and the
global alternative index of every row.
2. Utility, heterogeneity, and likelihood
For coordinate , define the map from the Gaussian chain scale to the utility scale
Write elementwise. Utilities are
where every , including the outside shock, is iid type-I extreme value with unit scale and variance . Let
Then
With the chosen inside row, or absent when outside is chosen, respondent contributes
There are two deliberately distinct random-effect levels:
and
describes cross-respondent heterogeneity in structural tastes. It never contains the alternative effects. The scalar describes dispersion of alternative quality around the maintained mean function . This separation avoids a dense -dimensional respondent covariance and supplies partial pooling and a predictive distribution for a new alternative. It is a maintained exchangeability model, not a guarantee that sparse-alternative estimates are consistent. Entry results can be sensitive to and to the prior on .
3. Identification and empirical content
The EV1 scale is fixed, so utility scale is identified by assumption. The systematic utility of the outside option is fixed to zero. Consequently, shifting every inside by a common constant changes inside-versus-outside probabilities and is not an invariance. The package therefore estimates all inside effects without a base-alternative or sum-to-zero restriction. is quality relative to the outside good; the intercept in locates average inside quality relative to outside.
Without the outside option, adding a constant to all available
alternatives would leave the softmax unchanged. For this reason v0.2.0
requires include_outside_option = TRUE. Even with the
formal anchor, little observed outside choice can make the common level
weakly informed while leaving inside-to-inside contrasts much more
precise.
Panel repetition reveals persistent respondent heterogeneity because the same governs all tasks. With , is learned through the mixture shape, covariate and choice-set variation, and the parametric Gaussian assumption. It is therefore generally less empirically disciplined than in a rich panel. Similarly, and require enough alternatives and variation in ; many observations of a few products do not substitute for cross-product variation in the second-level regression.
If a price-like regressor is correlated with
,
the likelihood is exogenous only conditional on
.
cf_residual_col appends a user-supplied first-stage
residual to
as a normal-coordinate control function. The package does not estimate
that first stage and does not propagate its estimation uncertainty.
4. Priors and posterior kernel
The hierarchy uses
Here and are precisions. The inverse-Wishart convention is
which is proper for the engine’s allowed and has mean only when . Defaults are , , , , , and . Thus the default raw prior mean of is , not .
By default . The implementation uses the Makalic–Schmidt representation, in the inverse-gamma shape–scale convention
where
means
.
Setting sd_prior$half_cauchy = FALSE instead gives
.
Up to constants, the posterior density is
with the last two factors replaced by the plain inverse-gamma prior when requested. Prior-predictive checks should cover taste magnitudes, implied shares, , the quality ladder, and entrant quality—not merely individual hyperparameters in isolation.
5. One Metropolis-within-Gibbs iteration
The chain is a systematic scan. It rebuilds , , , task log likelihoods, and respondent log likelihoods at the start of every iteration.
5.1 Respondent coefficients
For respondent , the exact conditional target is
The proposal is symmetric:
where . Thus its covariance is . is fixed once at startup. At the pooled initialization, for each task,
and . The omitted outside vector is zero but its probability remains in the denominator. For log-normal coordinate , row and column of are multiplied by , implementing the local Jacobian transformation from utility to chain scale.
Because the proposal is symmetric,
where . Non-finite candidate likelihoods are rejected. During burn-in only,
where defaults to 0.234. Adaptation stops after burn-in.
5.2 Alternative effects
The conditionals are not independent because alternatives in the same task share . They are therefore updated in a strictly serial random-walk sweep. Propose . Let , , and
Only tasks containing change, giving
With ,
On acceptance the utility and denominator caches are updated immediately, so the next alternative conditions on the new state. follows the same burn-in Robbins–Monro rule with fixed target 0.44 and the same scale clamp.
6. Initialization
The R wrapper first estimates a pooled MNL over the structural columns, with the alternative effects excluded from that pooled optimization. Normal coordinates start at that estimate. A log-normal coordinate is transformed to ; estimates below 0.05 trigger a warning and clamp. Every and starts at this chain-scale vector; and .
If is the number of choices of inside alternative and the outside count,
is the QR least-squares solution regressing on . These are starting values, not pseudo-count priors.
7. Retained quantities and diagnostics
For each chain the kernel retains thinned draws of
,
vech,
,
,
,
and the log likelihood. Chain 1 supplies the top-level summaries and
object$draws; all chains are retained in
object$chains. keep_beta_i="means" uses
Welford updates for chain-1 respondent posterior means and SDs.
"draws" additionally keeps the chain-1
cube returned on the object, although all chains’ cubes coexist
temporarily during sequential fitting. The memory guard estimates
bytes per chain and multiplies by the requested number of chains.
summary() reports rank-normalized folded
split-,
bulk ESS, tail ESS, and MCSE for
,
,
and
,
plus the worst
among all
columns of
.
Fit-time warnings test every
as well as the small blocks at
or bulk ESS below 400. vech(W) is retained in every chain
but is not included in this automatic table or warning; covariance
heterogeneity is often among the slowest and weakest-identified
quantities, so researchers should pass the per-chain w_vech
matrices to rhat()/ess() explicitly and
inspect sensitivity. The built-in thresholds are screening rules, not
proofs of convergence. Multiple chains, traces, Monte Carlo error, prior
sensitivity, and posterior predictive checks remain necessary.
8. Post-estimation mathematics and limits
All methods use evenly selected chain-1 draws. At population level, each posterior draw is paired with one simulation
so integration over taste heterogeneity is a one-draw-per-posterior-draw Monte Carlo average, not exact quadrature. At individual level, stored draws are used when available; otherwise posterior-mean is a plug-in. New alternative receives an independent draw
These post-estimation simulations use R’s RNG, so
set.seed() controls their reproducibility.
For a log-normal coordinate, the posterior-draw population mean
coefficient used by wtp() is
normal coordinates use . WTP draw ratios are and are summarized by medians and equal-tailed intervals.
For HMNL the conditional expected maximum, apart from the Euler constant common to states, is
The implementation evaluates this without forming an unsafe at the original scale. With
it computes
and obtains the inside and outside probabilities from the same scaled
denominator. Thus R-side prediction and welfare remain finite even when
a counterfactual utility is outside the direct numerical range of
exp().
logsum() averages these simulated draws.
consumer_surplus() divides by
and reports posterior medians and intervals; counterfactual CV uses the
same simulated
path for baseline and policy data. For optional non-negative task
weights
,
the aggregate CV draw is
Equal task weights are the default. This calculation is appropriate
only when the chosen price coefficient has a defensible, resolved sign
and units; the weights define aggregation and do not repair a
misspecified sampling or price process. The code requires the policy and
baseline panels to contain exactly the same choice situations, matches
them by (person_col, id_col) rather than by row position,
and then applies unnamed weights in the baseline prepared data’s sorted
task order. Alternative rows and complete tasks may therefore be
reordered without changing the welfare contrast; adding or dropping
tasks is rejected because it changes the aggregation population.
elasticities() and diversion_ratios() are
aggregate finite-difference objects, not analytic individual
derivatives. For each inside alternative
,
the selected covariate is multiplied by
,
probabilities are recomputed with common random numbers, and
The outside option is included as a receiving alternative.
ppc_shares() compares observed take rates with posterior
predictive share intervals; matching shares alone is not a comprehensive
model check.
9. Computational contract
The chain runs inside one persistent OpenMP region. Cache rebuilds and respondent proposals are work-shared; the sweep, hierarchy draws, recording, and interrupt polling are master-only. Worker code uses hand-written Cholesky and triangular solves and does not call the R API or threaded BLAS. Sufficient statistics are accumulated in fixed respondent or alternative order.
At iteration
,
make_stream(seed,r,tag) assigns tags
to respondent proposals,
to
,
and
to
.
The unused
block is reserved for HMNP coefficient draws. Chains run sequentially
with seeds seed, seed+1, and so on. Draws are
reproducible for a fixed seed and thread configuration; source comments
conservatively allow cross-thread-count differences at floating-point
reduction order, so users should not treat byte identity across
toolchains or thread counts as an API promise.
References
- Berry, S., Levinsohn, J., & Pakes, A. (1995). Automobile prices in market equilibrium. Econometrica, 63(4), 841–890.
- Gelman, A. (2006). Prior distributions for variance parameters in hierarchical models. Bayesian Analysis, 1(3), 515–534.
- Makalic, E., & Schmidt, D. F. (2016). A simple sampler for the horseshoe estimator. IEEE Signal Processing Letters, 23(1), 179–182.
- Petrin, A., & Train, K. (2010). A control function approach to endogeneity in consumer choice models. Journal of Marketing Research, 47(1), 3–13.
- Roberts, G. O., Gelman, A., & Gilks, W. R. (1997). Weak convergence and optimal scaling of random walk Metropolis algorithms. Annals of Applied Probability, 7(1), 110–120.
- Rossi, P. E., Allenby, G. M., & McCulloch, R. (2005). Bayesian Statistics and Marketing. Wiley.
- Train, K. E. (2009). Discrete Choice Methods with Simulation (2nd ed.). Cambridge University Press.
- Vehtari, A., Gelman, A., Simpson, D., Carpenter, B., & Bürkner, P.-C. (2021). Rank-normalization, folding, and localization: an improved for assessing convergence of MCMC. Bayesian Analysis, 16(2), 667–718.