run_hmnlogit: Fit a hierarchical Bayesian multinomial logit (HMNL)

View source: R/hmnlogit_utils.R

run_hmnlogitR Documentation

Fit a hierarchical Bayesian multinomial logit (HMNL)

Description

Runs the adaptive RW-Metropolis-within-Gibbs sampler for the hierarchical (random-coefficients, panel or cross-sectional) multinomial logit with a BLP-style alternative-level random effect:

U_{ijt} = x_{ijt}'\gamma_i + \delta_j + \epsilon_{ijt}, \qquad U_{iot} = \epsilon_{iot},

with i.i.d. Gumbel shocks (including on the implicit outside option, whose systematic utility is 0), \beta_i \sim N(b, W) over the structural covariates (\gamma_{ik} = \beta_{ik} or \exp(\beta_{ik}) per rc_dist), and \delta_j = z_j'\theta + \xi_j, \xi_j \sim N(0, \sigma_d^2). Partial pooling shrinks each \delta_j toward its characteristics-based mean z_j'\theta; the outside option anchors the level of \delta (mean utility relative to the outside good), so no base alternative or sum-to-zero constraint is needed.

Usage

run_hmnlogit(
  data = NULL,
  id_col = NULL,
  alt_col = NULL,
  choice_col = NULL,
  covariate_cols = NULL,
  person_col = NULL,
  alt_covariate_cols = NULL,
  outside_opt_label = NULL,
  cf_residual_col = NULL,
  input_data = NULL,
  include_outside_option = TRUE,
  rc_dist = NULL,
  prior = list(),
  mcmc = list(),
  chains = 1,
  keep_beta_i = c("means", "draws", "none"),
  keep_data = TRUE
)

Arguments

data

Data frame (convenience pathway). Supply either data (with the column names) or input_data, not both.

id_col

Name of the column identifying choice situations (tasks). Task ids only need to be unique within a respondent.

alt_col

Name of the column identifying alternatives.

choice_col

Name of the column indicating the chosen alternative (1 = chosen, 0 = not chosen).

covariate_cols

Vector of names of structural covariate columns (the random-coefficient dimensions).

person_col

Name of the respondent column grouping choice situations. NULL (default) makes each choice situation its own respondent.

alt_covariate_cols

Names of alternative-level covariate columns (constant within each alternative) forming the \delta mean function. NULL (default) gives an intercept-only design (P = 1).

outside_opt_label

Label of physical outside-option rows, removed when include_outside_option = TRUE (the outside good is implicit).

cf_residual_col

Name of a first-stage residual column (control function for an endogenous covariate), appended to X. Default NULL.

input_data

A choicer_data_hmnl object from prepare_hmnl_data() (advanced pathway).

include_outside_option

Logical; if TRUE (default) an implicit outside option with systematic utility 0 is part of every choice set.

rc_dist

Integer vector, one entry per column of covariate_cols: 0 for a normal random coefficient, 1 for log-normal (the coefficient enters utility as exp(beta_ik); hierarchy normal on the log scale). Default NULL is all-normal. Automatically aligned through dropped columns; a cf_residual_col coordinate is always normal.

prior

Named list overriding prior defaults: b_bar (0), A (0.01 I), nu (K + 3), V (nu I), theta_bar (0), A_theta (0.01 I), sd_prior (list(half_cauchy = TRUE, s_d = 1, c0 = 3, d0 = 3)).

mcmc

Named list overriding MCMC defaults: R (10000), burn (R %/% 5), thin (1), seed (drawn via sample.int() so set.seed() governs), trace (0), s_init (2.38 / sqrt(K)), accept_target (0.234).

chains

Number of independent chains (seeds offset by 1, run sequentially). Chain 1 provides the reported draws; all chains feed the rank-normalized split-R-hat table and the retained chains field (all per-chain b/w_vech/delta/theta/sigma_d2/loglik draws, consumed by ess(), mcse(), and traceplot()).

keep_beta_i

"means" (default) stores posterior means/SDs of the individual-level \beta_i; "draws" additionally stores the full (K, N, R_keep) draw cube (memory-guarded, budgeted per chain); "none" stores neither.

keep_data

Logical; keep the prepared data on the fit (default TRUE, needed by post-estimation methods).

Details

Initialization. \beta_i start at the pooled MNL maximum likelihood estimate over the structural covariates (log-normal coordinates transformed to the chain scale with a warn-and-clamp at 0.05); \delta starts at shrunk log choice-share contrasts against the outside option; \theta at the OLS regression of the initial \delta on Z.

Priors. b \sim N(b\_bar, A^{-1}), W \sim IW(\nu, V), \theta \sim N(\theta\_bar, A_\theta^{-1}), and \sigma_d \sim half-Cauchy(0, s_d) via the Makalic-Schmidt scale mixture (set sd_prior$half_cauchy = FALSE for a plain IG(c_0, d_0) on \sigma_d^2).

Endogeneity. If a price-like covariate is endogenous (correlated with \xi_j), supply a first-stage residual via cf_residual_col (Petrin & Train 2010); posterior uncertainty does NOT propagate first-stage estimation error.

For beta_i draws at very large scale beyond the memory guard's threshold, a future disk-streaming path (writing each kept slice to disk instead of retaining it in memory) is on the roadmap but not built in this phase; users needing per-respondent draws at that scale should reduce R, reduce chains, or use keep_beta_i = "means".

Value

A choicer_hmnl object (classed c("choicer_hmnl", "choicer_hb")) with posterior summaries (coefficients, se, vcov for b; theta_summary; sigma_d2_summary; W_mean; delta and xi quality-ladder tables; beta_i), the raw thinned draws (chain 1), acceptance diagnostics in accept, the rank-normalized split-R-hat table in rhat, all chains' retained draws in chains, and sampler metadata.

See Also

prepare_hmnl_data(), simulate_hmnl_data(), recovery_table(), rhat(), ess(), mcse(), traceplot()

Examples


sim <- simulate_hmnl_data(N = 100, T = 3, J = 4, seed = 42)
fit <- suppressWarnings(run_hmnlogit(sim$data, "task", "alt", "choice", c("x1", "x2"),
                    person_col = "pid", alt_covariate_cols = "z1",
                    mcmc = list(R = 500, burn = 200)))
summary(fit)
coef(fit, component = "delta")


choicer documentation built on Sept. 5, 2026, 1:07 a.m.