| Title: | Discrete Choice Models for Economic Applications |
|---|---|
| Description: | Fast estimation of discrete-choice models for applied economics. Frequentist likelihoods, analytical gradients, and Hessians are implemented in C++ with 'OpenMP' parallelism, scaling efficiently to specifications with many alternative-specific constants. Compiled Gibbs samplers provide Bayesian multinomial probit and hierarchical models. Post-estimation routines cover predicted shares, own- and cross-price elasticities, diversion ratios, willingness to pay, and welfare counterfactuals. Supports multinomial logit ('MNL'), mixed logit ('MXL'), nested logit ('NL'), Bayesian multinomial probit ('MNP'), and hierarchical Bayesian multinomial logit and probit ('HMNL', 'HMNP'). |
| Authors: | Fernando Cordeiro [aut, cre, cph] |
| Maintainer: | Fernando Cordeiro <[email protected]> |
| License: | LGPL (>= 3) |
| Version: | 0.2.1.9000 |
| Built: | 2026-10-19 23:57:32 UTC |
| Source: | https://github.com/fpcordeiro/choicer |
Finds the ASC (delta) parameters such that predicted market shares match target shares, using the contraction mapping of Berry, Levinsohn, and Pakes (1995) doi:10.2307/2171802.
blp(object, target_shares, ...)blp(object, target_shares, ...)
object |
A fitted model object. |
target_shares |
Numeric vector of target market shares (length J). |
... |
Additional arguments passed to methods. |
Converged delta (ASC) vector.
library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) blp(fit, target_shares = rep(1/J, J))library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) blp(fit, target_shares = rep(1/J, J))
BLP95 contraction mapping to find delta given target shares
blp_contraction( delta, target_shares, X, beta, alt_idx, M, weights, include_outside_option = FALSE, tol = 1e-08, max_iter = 1000L )blp_contraction( delta, target_shares, X, beta, alt_idx, M, weights, include_outside_option = FALSE, tol = 1e-08, max_iter = 1000L )
delta |
J x 1 vector with initial guess for deltas (ASCs) |
target_shares |
J x 1 vector with target shares for each alternative |
X |
sum(M) x K design matrix with covariates. M[i] x K matrix for individual i |
beta |
K x 1 vector with model parameters |
alt_idx |
sum(M) x 1 vector with indices of alternatives within each choice set; 1-based indexing |
M |
N x 1 vector with number of alternatives for each individual |
weights |
N x 1 vector with weights for each observation |
include_outside_option |
whether to include outside option normalized to 0 (if so, the outside option is not included in the data) |
tol |
convergence tolerance |
max_iter |
maximum number of iterations |
vector with contraction's delta (ASCs) output
library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) beta <- coef(fit)[fit$param_map$beta] delta <- blp_contraction(rep(0, J), rep(1/J, J), fit$data$X, beta, fit$data$alt_idx, fit$data$M, fit$data$weights) deltalibrary(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) beta <- coef(fit)[fit$param_map$beta] delta <- blp_contraction(rep(0, J), rep(1/J, J), fit$data$X, beta, fit$data$alt_idx, fit$data$M, fit$data$weights) delta
BLP contraction mapping for multinomial logit model
## S3 method for class 'choicer_mnl' blp( object, target_shares, delta_init = NULL, tol = 1e-08, max_iter = 1000, ... )## S3 method for class 'choicer_mnl' blp( object, target_shares, delta_init = NULL, tol = 1e-08, max_iter = 1000, ... )
object |
A |
target_shares |
Numeric vector of target market shares.
Length |
delta_init |
Initial guess for delta (ASC) values. If |
tol |
Convergence tolerance (default 1e-8). |
max_iter |
Maximum iterations (default 1000). |
... |
Additional arguments (ignored). |
Converged delta (ASC) vector.
library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) blp(fit, target_shares = rep(1/J, J))library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) blp(fit, target_shares = rep(1/J, J))
BLP contraction mapping for mixed logit model
## S3 method for class 'choicer_mxl' blp( object, target_shares, delta_init = NULL, tol = 1e-08, max_iter = 1000, keep_draws_bytes = 2^32, ... )## S3 method for class 'choicer_mxl' blp( object, target_shares, delta_init = NULL, tol = 1e-08, max_iter = 1000, keep_draws_bytes = 2^32, ... )
object |
A |
target_shares |
Numeric vector of target market shares.
Length |
delta_init |
Initial guess for delta (ASC) values. If |
tol |
Convergence tolerance (default 1e-8). |
max_iter |
Maximum iterations (default 1000). |
keep_draws_bytes |
Most memory, in bytes, that the contraction may use
to keep the draws across its iterations; it does not change the returned
delta. When the draws are formed on the fly and those of all |
... |
Additional arguments (ignored). |
The contraction integrates each choice situation over the same
draws as predict() (for a cross-sectional fit, the estimation
draws; a panel fit's estimation draws are per decision maker), formed on
the fly, in parallel, and kept across iterations within
keep_draws_bytes. With stored draws (draws = "store") they
are the points of the cube get_halton_normals would build,
formed without it; with more than 128 random coefficients, the cube
itself, read at every iteration (and nothing more is kept).
Converged delta (ASC) vector.
library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), w1 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mxlogit( data = dt, id_col = "id", alt_col = "alt", choice_col = "choice", covariate_cols = "x1", random_var_cols = "w1", S = 50L ) blp(fit, target_shares = rep(1/J, J))library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), w1 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mxlogit( data = dt, id_col = "id", alt_col = "alt", choice_col = "choice", covariate_cols = "x1", random_var_cols = "w1", S = 50L ) blp(fit, target_shares = rep(1/J, J))
BLP contraction mapping for nested logit model
## S3 method for class 'choicer_nl' blp( object, target_shares, delta_init = NULL, damping = 1, tol = 1e-08, max_iter = 1000, ... )## S3 method for class 'choicer_nl' blp( object, target_shares, delta_init = NULL, damping = 1, tol = 1e-08, max_iter = 1000, ... )
object |
A |
target_shares |
Numeric vector of target market shares.
Length |
delta_init |
Initial guess for delta (ASC) values. If |
damping |
Contraction damping factor in (0, 1] (default 1). |
tol |
Convergence tolerance (default 1e-8). |
max_iter |
Maximum iterations (default 1000). |
... |
Additional arguments (ignored). |
Converged delta (ASC) vector.
library(data.table) set.seed(42) N <- 50; J <- 4 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, nest := rep(c(1L, 1L, 2L, 2L), N)] dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_nestlogit(dt, "id", "alt", "choice", c("x1", "x2"), "nest") blp(fit, target_shares = rep(1/J, J))library(data.table) set.seed(42) N <- 50; J <- 4 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, nest := rep(c(1L, 1L, 2L, 2L), N)] dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_nestlogit(dt, "id", "alt", "choice", c("x1", "x2"), "nest") blp(fit, target_shares = rep(1/J, J))
Extract coefficients from a choicer_fit object
## S3 method for class 'choicer_fit' coef(object, ...)## S3 method for class 'choicer_fit' coef(object, ...)
object |
A choicer_fit object. |
... |
Additional arguments (ignored). |
Named numeric vector of estimated coefficients.
library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) coef(fit)library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) coef(fit)
Extract posterior means from a hierarchical Bayes fit
## S3 method for class 'choicer_hb' coef(object, component = c("beta", "theta", "delta", "xi"), ...)## S3 method for class 'choicer_hb' coef(object, component = c("beta", "theta", "delta", "xi"), ...)
object |
A |
component |
Which block to return: |
... |
Additional arguments (ignored). |
Named numeric vector of posterior means.
sim <- simulate_hmnl_data(N = 50, T = 2, J = 3, seed = 42) fit <- suppressWarnings(run_hmnlogit(sim$data, "task", "alt", "choice", c("x1", "x2"), person_col = "pid", mcmc = list(R = 300, burn = 100))) coef(fit) coef(fit, component = "delta")sim <- simulate_hmnl_data(N = 50, T = 2, J = 3, seed = 42) fit <- suppressWarnings(run_hmnlogit(sim$data, "task", "alt", "choice", c("x1", "x2"), person_col = "pid", mcmc = list(R = 300, burn = 100))) coef(fit) coef(fit, component = "delta")
Returns the posterior means of the identified coefficients
(, computed per draw).
## S3 method for class 'choicer_mnp' coef(object, ...)## S3 method for class 'choicer_mnp' coef(object, ...)
object |
A choicer_mnp object. |
... |
Additional arguments (ignored). |
Named numeric vector of posterior means.
library(data.table) set.seed(42) N <- 100; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnprobit(dt, "id", "alt", "choice", c("x1", "x2"), mcmc = list(R = 300, burn = 100)) coef(fit)library(data.table) set.seed(42) N <- 100; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnprobit(dt, "id", "alt", "choice", c("x1", "x2"), mcmc = list(R = 300, burn = 100)) coef(fit)
For each decision maker, the mean and standard deviation of the random
coefficients conditional on the choices they were observed to make,
(Revelt and Train 2000; Train
2009, ch. 11): the frequentist counterpart of the individual-level
beta_i summaries of run_hmnlogit.
conditional_tastes(object, ...) ## Default S3 method: conditional_tastes(object, ...) ## S3 method for class 'choicer_mxl' conditional_tastes(object, ...)conditional_tastes(object, ...) ## Default S3 method: conditional_tastes(object, ...) ## S3 method for class 'choicer_mxl' conditional_tastes(object, ...)
object |
A |
... |
Unused. |
Estimand. The fit estimates the population distribution of tastes,
. Among decision makers who face and
make the choices , tastes follow the conditional distribution
where is
the product of the decision maker's logit probabilities. Its mean and
standard deviation are simulated at with the estimation
draws, as weighted averages over draws with weights
. Coefficients are on
the scale they enter utility: for a normal
coefficient and for the shifted
log-normal, with the term present only when
rc_mean = TRUE. If a variable's mean is carried instead by the same
variable in covariate_cols (with rc_mean = FALSE), only its
random part is reported. This is the utility scale; the beta_i
summaries of run_hmnlogit() are on the scale of the underlying
normal, i.e. the log of the coefficient for log-normal coordinates.
What it is not. The conditional mean is not the decision maker's
own . It is the average taste among people who would make
's choices, so it shrinks toward the population mean, the more so
the fewer choice situations contributes, and its dispersion across
decision makers understates the population dispersion. By the law of
iterated expectations the conditional means average, in large samples, to
the population mean (mean_cond vs model_mean in
population), and by the law of total variance
: the share
of taste variance revealed by choices (revealed) and the share left
unresolved (residual) should sum to about one. These are numerical
checks, not specification tests: for normal random coefficients with free
means, both identities are the likelihood's first-order conditions for
and , so they hold at a converged maximum whatever
the true taste distribution. A departure points to too few draws
S or an unconverged ; when a random coefficient's
mean is fixed at zero (rc_mean = FALSE and no fixed coefficient on
the same variable), a mean_cond far from zero can also flag that
restriction. For log-normal coefficients the variance identity holds on
the underlying normal scale, not the utility scale reported here, so
expect departures of a few percent in either direction at moderate
S. The sd is the dispersion of the conditional distribution
of tastes, not a standard error: it ignores the sampling error in
.
Cross-section. Without person_col each choice situation is
its own decision maker. A single choice reveals little about tastes, so
the conditional means stay close to the population mean (revealed
small); fit with person_col to learn about tastes from repeated
choices.
Choice probabilities are handled in log space, so every unit has a
finite conditional distribution however improbable its choices. Only a
unit whose utilities overflow at the estimates (non-finite
log-likelihood) gets NA, and it is left out of the
population summaries.
An object of class choicer_tastes: a list with
mean, sd
matrices of
conditional means and standard deviations; rows are the random
coefficients (random_var_cols), columns the likelihood
units, named by decision-maker id (person_col) or by
choice-situation id.
unit"decision maker" or "choice situation".
n_units.
SSimulation draws per unit.
weightsUnit weights used in population.
populationA data.frame with one row per random
coefficient: model_mean and model_sd, the moments of
; mean_cond and sd_cond,
the weighted mean and standard deviation of the conditional means
across units; revealed
; and residual
.
Revelt, D. and Train, K. (2000). Customer-specific taste parameters and mixed logit: households' choice of electricity supplier. Working Paper E00-274, Department of Economics, University of California, Berkeley.
Train, K. (2009). Discrete Choice Methods with Simulation, 2nd ed., Ch. 11. Cambridge University Press.
run_mxlogit (person_col),
simulate_mxl_data (true_params$gamma_i)
sim <- simulate_mxl_data(N = 150, T = 5, J = 3, seed = 1) fit <- run_mxlogit(sim$data, "id", "alt", "choice", c("x1", "x2"), c("w1", "w2"), outside_opt_label = 0L, rc_correlation = TRUE, person_col = "pid", S = 50L) ct <- conditional_tastes(fit) ct # conditional means track the realized tastes, with shrinkage cor(ct$mean["w1", ], sim$true_params$gamma_i["w1", colnames(ct$mean)])sim <- simulate_mxl_data(N = 150, T = 5, J = 3, seed = 1) fit <- run_mxlogit(sim$data, "id", "alt", "choice", c("x1", "x2"), c("w1", "w2"), outside_opt_label = 0L, rc_correlation = TRUE, person_col = "pid", S = 50L) ct <- conditional_tastes(fit) ct # conditional means track the realized tastes, with shrinkage cor(ct$mean["w1", ], sim$true_params$gamma_i["w1", colnames(ct$mean)])
Computes the expected consumer surplus per choice situation (Train 2009, Ch. 3):
where is the expected maximum utility (see
logsum) and is the (fixed) price coefficient,
so that is the marginal utility of income. The formula
assumes no income effects: utility is linear in price, and the
marginal utility of income is constant across the price changes considered.
## S3 method for class 'choicer_hmnl' consumer_surplus( object, price_var, newdata = NULL, level = 0.95, weights = NULL, n_draws = 200L, ... ) ## S3 method for class 'choicer_hmnp' consumer_surplus( object, price_var, newdata = NULL, level = 0.95, weights = NULL, ... ) consumer_surplus( object, price_var, newdata = NULL, level = 0.95, weights = NULL, ... ) ## S3 method for class 'choicer_mnl' consumer_surplus( object, price_var, newdata = NULL, level = 0.95, weights = NULL, ... ) ## S3 method for class 'choicer_mxl' consumer_surplus( object, price_var, newdata = NULL, level = 0.95, weights = NULL, ... ) ## S3 method for class 'choicer_nl' consumer_surplus( object, price_var, newdata = NULL, level = 0.95, weights = NULL, ... )## S3 method for class 'choicer_hmnl' consumer_surplus( object, price_var, newdata = NULL, level = 0.95, weights = NULL, n_draws = 200L, ... ) ## S3 method for class 'choicer_hmnp' consumer_surplus( object, price_var, newdata = NULL, level = 0.95, weights = NULL, ... ) consumer_surplus( object, price_var, newdata = NULL, level = 0.95, weights = NULL, ... ) ## S3 method for class 'choicer_mnl' consumer_surplus( object, price_var, newdata = NULL, level = 0.95, weights = NULL, ... ) ## S3 method for class 'choicer_mxl' consumer_surplus( object, price_var, newdata = NULL, level = 0.95, weights = NULL, ... ) ## S3 method for class 'choicer_nl' consumer_surplus( object, price_var, newdata = NULL, level = 0.95, weights = NULL, ... )
object |
A fitted model object ( |
price_var |
Name of the price variable. Must be a fixed-coefficient
variable (a column of the design matrix |
newdata |
Optional counterfactual data (data.frame or list), as in
|
level |
Confidence level for the normal-approximation interval around the mean CS (MNL only). Default 0.95. |
weights |
Optional numeric vector with one weight per choice situation,
used for the mean CS (and its SE), as in |
n_draws |
Number of posterior draws to integrate over (hierarchical Bayes methods). |
... |
Additional arguments passed to methods. |
Consumer surplus levels inherit the additive utility normalization
(in particular the ASC normalization), so the level is only defined up to a
constant; differences in CS between scenarios — e.g.
consumer_surplus(fit, "price", newdata = scenario) minus the baseline
— are the economically meaningful quantity.
For MNL fits, a delta-method standard error of the weighted mean CS is
reported (weights are the stored fit weights, or the resolved
newdata weights). For MXL and NL fits only point estimates are
returned (se_mean_cs = NA): the delta method for the simulated MXL
logsum and the nested logsum is deferred; simulation-based intervals
(Krinsky-Robb: resample coefficients from their asymptotic distribution
and recompute the mean CS) are a practical alternative.
The price variable must have a fixed coefficient. For mixed logit a
random price coefficient is rejected (as in wtp): with a
random denominator generally has no finite moments.
A choicer_cs object: a list with cs (per-choice-
situation surplus, length N, ordered as in logsum),
mean_cs (weighted mean),
se_mean_cs (delta-method SE; NA for MXL/NL or when the
variance-covariance matrix is unavailable), ci (confidence
interval for the mean), price_var, level, and n.
consumer_surplus(choicer_hmnl): Posterior consumer surplus for the
hierarchical logit: per-task logsum divided by the (positive) marginal
utility of income , per posterior draw. With
newdata, the return also carries the compensating variation against
the estimation data (attr(, "cv")), i.e. the posterior of
summed over tasks. Requires a fixed-sign price
coefficient; the posterior-median ratio discipline of
wtp.choicer_hb() applies. When newdata is supplied, weights is an
optional non-negative length-n_tasks vector used in the aggregate CV;
equal task weights are the default. The counterfactual must contain the
same choice situations as the estimation data, identified by
(person_col, id_col) (or id_col when person_col = NULL); rows and
tasks may be reordered. Unnamed weights follow the baseline tasks'
sorted (person_col, id_col) order used by the prepared data.
consumer_surplus(choicer_hmnp): Not available for the probit (see
logsum.choicer_hmnp()); roadmapped via simulated Emax.
Train, K. (2009). Discrete Choice Methods with Simulation, 2nd ed., Ch. 3. Cambridge University Press.
library(data.table) sim <- simulate_mnl_data(N = 1000, J = 3, beta = c(0.8, -0.6), seed = 123, outside_option = FALSE, vary_choice_set = FALSE) fit <- run_mnlogit(sim$data, "id", "alt", "choice", c("x1", "x2")) # treat x2 as the price variable cs0 <- consumer_surplus(fit, price_var = "x2") cs0 # Change in consumer surplus from a price increase on alternative 2: # levels depend on the ASC normalization, differences do not. dt_cf <- copy(sim$data)[alt == 2, x2 := x2 + 0.5] cs1 <- consumer_surplus(fit, price_var = "x2", newdata = dt_cf) delta_cs <- cs1$mean_cs - cs0$mean_cs delta_cs # negative: the price increase lowers expected surpluslibrary(data.table) sim <- simulate_mnl_data(N = 1000, J = 3, beta = c(0.8, -0.6), seed = 123, outside_option = FALSE, vary_choice_set = FALSE) fit <- run_mnlogit(sim$data, "id", "alt", "choice", c("x1", "x2")) # treat x2 as the price variable cs0 <- consumer_surplus(fit, price_var = "x2") cs0 # Change in consumer surplus from a price increase on alternative 2: # levels depend on the ASC normalization, differences do not. dt_cf <- copy(sim$data)[alt == 2, x2 := x2 + 0.5] cs1 <- consumer_surplus(fit, price_var = "x2", newdata = dt_cf) delta_cs <- cs1$mean_cs - cs0$mean_cs delta_cs # negative: the price increase lowers expected surplus
Computes a J x J matrix of diversion ratios. Entry (i, j) is the fraction of demand lost by alternative j that is captured by alternative i when alternative j becomes less attractive.
## S3 method for class 'choicer_hb' diversion_ratios(object, elast_var, eps = 0.01, n_draws = 100L, ...) diversion_ratios(object, ...)## S3 method for class 'choicer_hb' diversion_ratios(object, elast_var, eps = 0.01, n_draws = 100L, ...) diversion_ratios(object, ...)
object |
A fitted model object. |
elast_var |
Structural covariate to perturb (hierarchical Bayes methods). |
eps |
Relative perturbation size (default 0.01). |
n_draws |
Number of posterior draws to integrate over. |
... |
Additional arguments passed to methods. |
A J x J diversion ratio matrix with alternative labels.
diversion_ratios(choicer_hb): Posterior-mean diversion ratios for
hierarchical Bayes fits, from the same perturbation engine as
elasticities.choicer_hb(): is the fraction of the
share alternative j loses (when its elast_var worsens) that flows to
k — including the outside option. Columns are the perturbed
alternative j, rows the receiving alternative k; the diagonal is 0.
library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) diversion_ratios(fit)library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) diversion_ratios(fit)
Diversion ratios for multinomial logit model
## S3 method for class 'choicer_mnl' diversion_ratios(object, ...)## S3 method for class 'choicer_mnl' diversion_ratios(object, ...)
object |
A |
... |
Additional arguments (ignored). |
A J x J diversion ratio matrix with alternative labels.
library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) diversion_ratios(fit)library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) diversion_ratios(fit)
Computes the attribute-based diversion ratio matrix. Entry (k, j) is the
fraction of demand lost by alternative j that is captured by alternative k
when a marginal change in alternative j's wrt_var attribute reduces
s_j.
## S3 method for class 'choicer_mxl' diversion_ratios(object, wrt_var, is_random_coef = FALSE, ...)## S3 method for class 'choicer_mxl' diversion_ratios(object, wrt_var, is_random_coef = FALSE, ...)
object |
A |
wrt_var |
Variable used to perturb alternative j's utility: a column
name (character) or 1-based index. Indexes into X columns for fixed
coefficients, or W columns for random coefficients (when
|
is_random_coef |
Logical. |
... |
Additional arguments (ignored). |
Unlike MNL, the MXL diversion ratio depends on which variable is perturbed:
the realised coefficient varies across individuals and
draws and does not cancel in the ratio. For a variable with a fixed
coefficient the result is independent of the variable ( cancels);
for a random-coefficient variable it is not.
A J x J diversion ratio matrix with alternative labels. Cross-products are averaged across simulation draws inside the integration to avoid Jensen-style bias.
library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), w1 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mxlogit( data = dt, id_col = "id", alt_col = "alt", choice_col = "choice", covariate_cols = "x1", random_var_cols = "w1", S = 50L ) diversion_ratios(fit, "x1") diversion_ratios(fit, "w1", is_random_coef = TRUE)library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), w1 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mxlogit( data = dt, id_col = "id", alt_col = "alt", choice_col = "choice", covariate_cols = "x1", random_var_cols = "w1", S = 50L ) diversion_ratios(fit, "x1") diversion_ratios(fit, "w1", is_random_coef = TRUE)
Diversion ratios for nested logit model
## S3 method for class 'choicer_nl' diversion_ratios(object, ...)## S3 method for class 'choicer_nl' diversion_ratios(object, ...)
object |
A |
... |
Additional arguments (ignored). |
A J x J diversion ratio matrix with alternative labels.
library(data.table) set.seed(42) N <- 50; J <- 4 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, nest := rep(c(1L, 1L, 2L, 2L), N)] dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_nestlogit(dt, "id", "alt", "choice", c("x1", "x2"), "nest") diversion_ratios(fit)library(data.table) set.seed(42) N <- 50; J <- 4 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, nest := rep(c(1L, 1L, 2L, 2L), N)] dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_nestlogit(dt, "id", "alt", "choice", c("x1", "x2"), "nest") diversion_ratios(fit)
Computes a J x J matrix of aggregate elasticities. Entry (i, j) is the percentage change in the probability of choosing alternative i when the attribute of alternative j changes by 1\
## S3 method for class 'choicer_hb' elasticities(object, elast_var, eps = 0.01, n_draws = 100L, ...) elasticities(object, ...)## S3 method for class 'choicer_hb' elasticities(object, elast_var, eps = 0.01, n_draws = 100L, ...) elasticities(object, ...)
object |
A fitted model object. |
elast_var |
Structural covariate to perturb (hierarchical Bayes methods). |
eps |
Relative perturbation size (default 0.01). |
n_draws |
Number of posterior draws to integrate over. |
... |
Additional arguments passed to methods. |
A J x J elasticity matrix with alternative labels.
elasticities(choicer_hb): Posterior-mean aggregate arc elasticities for
hierarchical Bayes fits: each inside alternative's elast_var is
perturbed by eps (default 1%) and shares are recomputed per posterior
draw with a common random-coefficient path, giving
. Rows are responding
alternatives (including the outside option), columns the perturbed
alternative.
library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) elasticities(fit, "x1")library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) elasticities(fit, "x1")
Elasticities for multinomial logit model
## S3 method for class 'choicer_mnl' elasticities(object, elast_var, ...)## S3 method for class 'choicer_mnl' elasticities(object, elast_var, ...)
object |
A |
elast_var |
Variable for elasticity computation: a column name (character) or 1-based index into the design matrix X. |
... |
Additional arguments (ignored). |
A J x J elasticity matrix with alternative labels.
library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) elasticities(fit, "x1")library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) elasticities(fit, "x1")
Elasticities for mixed logit model
## S3 method for class 'choicer_mxl' elasticities(object, elast_var, is_random_coef = FALSE, ...)## S3 method for class 'choicer_mxl' elasticities(object, elast_var, is_random_coef = FALSE, ...)
object |
A |
elast_var |
Variable for elasticity computation: a column name (character)
or 1-based index. Indexes into X columns for fixed coefficients, or W columns
for random coefficients (when |
is_random_coef |
Logical. |
... |
Additional arguments (ignored). |
A J x J elasticity matrix with alternative labels.
library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), w1 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mxlogit( data = dt, id_col = "id", alt_col = "alt", choice_col = "choice", covariate_cols = "x1", random_var_cols = "w1", S = 50L ) elasticities(fit, "x1") elasticities(fit, "w1", is_random_coef = TRUE)library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), w1 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mxlogit( data = dt, id_col = "id", alt_col = "alt", choice_col = "choice", covariate_cols = "x1", random_var_cols = "w1", S = 50L ) elasticities(fit, "x1") elasticities(fit, "w1", is_random_coef = TRUE)
Elasticities for nested logit model
## S3 method for class 'choicer_nl' elasticities(object, elast_var, ...)## S3 method for class 'choicer_nl' elasticities(object, elast_var, ...)
object |
A |
elast_var |
Variable for elasticity computation: a column name (character) or 1-based index into the design matrix X. |
... |
Additional arguments (ignored). |
A J x J elasticity matrix with alternative labels.
library(data.table) set.seed(42) N <- 50; J <- 4 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, nest := rep(c(1L, 1L, 2L, 2L), N)] dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_nestlogit(dt, "id", "alt", "choice", c("x1", "x2"), "nest") elasticities(fit, "x1")library(data.table) set.seed(42) N <- 50; J <- 4 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, nest := rep(c(1L, 1L, 2L, 2L), N)] dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_nestlogit(dt, "id", "alt", "choice", c("x1", "x2"), "nest") elasticities(fit, "x1")
Computes the rank-normalized bulk and tail effective sample size (ESS) of
Vehtari, Gelman, Simpson, Carpenter & Buerkner (2021, Bayesian
Analysis) for each column of a matrix of posterior draws. ess_bulk
measures the effective number of independent draws available for
estimating the posterior mean/median; ess_tail is the minimum of the
5th- and 95th-percentile indicator ESS, relevant for tail-quantile /
credible-interval precision. Autocovariance is computed via
fft (Geyer's initial monotone sequence estimator of
the integrated autocorrelation time).
ess(draws)ess(draws)
draws |
A matrix of posterior draws (rows = iterations, columns = parameters) for a single chain, or a list of such matrices (one per chain, identical dimensions). |
A numeric matrix, one row per parameter, two columns
("bulk", "tail"); NA for parameters with zero variance or a
non-finite result.
set.seed(42) draws <- matrix(rnorm(2000), ncol = 2, dimnames = list(NULL, c("a", "b"))) ess(draws)set.seed(42) draws <- matrix(rnorm(2000), ncol = 2, dimnames = list(NULL, c("a", "b"))) ess(draws)
Create halton normal draws in appropriate format for mixed logit estimation
get_halton_normals(S, N, K_w)get_halton_normals(S, N, K_w)
S |
Number of draws per draw unit |
N |
number of draw units: choice situations, or decision makers for a
panel fit ( |
K_w |
dimension of random coefficients (number of columns in W matrix) |
Draw unit receives the consecutive points
of the -dimensional Halton sequence
of randtoolbox::halton(), mapped to standard normals. The cube
takes bytes and is filled a block of units at a time, so it
never holds a second copy of the sequence. Store mode supports at most
points (), the largest starting index
halton(start = ) accepts; draws = "generate" in
run_mxlogit has no such limit and never materializes the cube.
predict(), logsum(), consumer_surplus(),
elasticities(), diversion_ratios(), blp() and
gof() on a store-mode fit with up to 128 random coefficients do not
build their cube (one block per choice situation) with this function: they
form the same draws on the fly, from the same uniforms mapped by R's
qnorm() (bit for bit where randtoolbox and choicer are compiled
with the same floating-point contraction, as on CRAN's platforms).
K_w x S x N array with halton standard normal draws
draws <- get_halton_normals(S = 50, N = 10, K_w = 2) dim(draws) # 2 x 50 x 10draws <- get_halton_normals(S = 50, N = 10, K_w = 2) dim(draws) # 2 x 50 x 10
Computes McFadden's pseudo R-squared (plain and adjusted) and the in-sample hit rate for a fitted model.
gof(object, null = c("equal_shares", "market_shares"), ...) ## S3 method for class 'choicer_fit' gof(object, null = c("equal_shares", "market_shares"), ...)gof(object, null = c("equal_shares", "market_shares"), ...) ## S3 method for class 'choicer_fit' gof(object, null = c("equal_shares", "market_shares"), ...)
object |
A fitted model object ( |
null |
Null model for the pseudo R-squared: |
... |
Additional arguments passed to methods. |
Two null models are available for the pseudo R-squared
(adjusted:
with the number of estimated
parameters):
"equal_shares" (default): every alternative in individual
's choice set is equally likely, so
. This is exact for
unbalanced choice sets and arbitrary weights.
"market_shares": the maximized log-likelihood of an
ASC-only model, with the
choice counts and the observed market shares (including the
outside option when present). This closed form is valid only for
balanced choice sets and uniform weights; otherwise an error suggests
refitting an ASC-only model.
The hit rate is the weighted share of individuals whose observed choice has
the highest predicted probability. When the model includes an outside
option, the outside good competes for the predicted maximum (its
probability is ), and an individual predicted to
choose the outside good is a hit when they actually did.
Both the null log-likelihood and the hit rate require the stored estimation
data; models fitted with keep_data = FALSE return NA fields with a
message.
A choicer_gof object: a list with loglik,
loglik_null, null, mcfadden_r2,
mcfadden_r2_adj, hit_rate, nobs, and
n_params.
library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) gof(fit) gof(fit, null = "market_shares")library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) gof(fit) gof(fit, null = "market_shares")
Returns a logLik object, which enables AIC() and BIC() automatically.
## S3 method for class 'choicer_fit' logLik(object, ...)## S3 method for class 'choicer_fit' logLik(object, ...)
object |
A choicer_fit object. |
... |
Additional arguments (ignored). |
A logLik object with df and nobs attributes.
library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) logLik(fit) AIC(fit) BIC(fit)library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) logLik(fit) AIC(fit) BIC(fit)
Computes the expected maximum utility ("logsum" or inclusive value) for each choice situation, up to the additive constant of the extreme-value error:
MNL: .
MXL: , simulated by
averaging the log-sum-exp across the deterministic Halton draws
(regenerated from object$draws_info). Taking the log-sum-exp of
draw-averaged utilities would understate the expectation (Jensen's
inequality), so a dedicated kernel (mxl_logsum) is used.
NL: with the nest inclusive
value
(singleton nests have ).
When the model includes an outside option, its normalized utility
contributes an term to the sum.
## S3 method for class 'choicer_hmnl' logsum(object, newdata = NULL, n_draws = 200L, ...) ## S3 method for class 'choicer_hmnp' logsum(object, newdata = NULL, ...) logsum(object, newdata = NULL, ...) ## S3 method for class 'choicer_mnl' logsum(object, newdata = NULL, ...) ## S3 method for class 'choicer_mxl' logsum(object, newdata = NULL, ...) ## S3 method for class 'choicer_nl' logsum(object, newdata = NULL, ...)## S3 method for class 'choicer_hmnl' logsum(object, newdata = NULL, n_draws = 200L, ...) ## S3 method for class 'choicer_hmnp' logsum(object, newdata = NULL, ...) logsum(object, newdata = NULL, ...) ## S3 method for class 'choicer_mnl' logsum(object, newdata = NULL, ...) ## S3 method for class 'choicer_mxl' logsum(object, newdata = NULL, ...) ## S3 method for class 'choicer_nl' logsum(object, newdata = NULL, ...)
object |
A fitted model object ( |
newdata |
Optional counterfactual data: a data.frame in the fit-time
long format or a list with |
n_draws |
Number of posterior draws to integrate over (hierarchical Bayes methods; thinned evenly from the kept draws). |
... |
Additional arguments passed to methods. |
Logsum levels depend on the ASC normalization (and, more generally,
on any additive utility normalization), so only logsum differences
between scenarios (e.g. via newdata) are meaningful.
Numeric vector with one logsum per choice situation. With a
data.frame newdata, choice situations are ordered by id (by
decision maker first for a panel mixed logit whose person_col is
present in newdata), as in predict().
logsum(choicer_hmnl): Posterior expected logsum for the hierarchical logit:
per choice situation, against the
outside-option anchor, averaged over posterior draws with one
draw each. Returns the per-task posterior
mean vector.
logsum(choicer_hmnp): The probit expected maximum has no closed form;
simulated-Emax surplus for the HMNP is on the roadmap.
library(data.table) sim <- simulate_mnl_data(N = 500, J = 3, beta = c(0.8, -0.6), seed = 1, outside_option = FALSE, vary_choice_set = FALSE) fit <- run_mnlogit(sim$data, "id", "alt", "choice", c("x1", "x2")) head(logsum(fit))library(data.table) sim <- simulate_mnl_data(N = 500, J = 3, beta = c(0.8, -0.6), seed = 1, outside_option = FALSE, vary_choice_set = FALSE) fit <- run_mnlogit(sim$data, "id", "alt", "choice", c("x1", "x2")) head(logsum(fit))
Consumes a choicer_mc object and returns per-parameter asymptotic
diagnostics: Monte Carlo bias (with MC standard error), empirical SD of
the estimates, mean of the reported standard errors, SE-to-SD ratio
(information-matrix-equality check), Wald coverage at nominal 90 / 95 /
99 percent with Wilson confidence bands, moments of the studentized
statistic z = (theta_hat - theta_0) / se, and four normality tests on
z (Shapiro-Wilk, Anderson-Darling via goftest::ad.test, a hand-coded
Jarque-Bera statistic, and a one-sample Kolmogorov-Smirnov test against
N(0, 1)).
mc_asymptotics( mc, level = 0.95, se_col = "se", conv_threshold = 0.99, se_ratio_threshold_floor = 0.1 )mc_asymptotics( mc, level = 0.95, se_col = "se", conv_threshold = 0.99, se_ratio_threshold_floor = 0.1 )
mc |
A |
level |
Confidence level for the Wilson bands on coverage rates.
Defaults to |
se_col |
Name of the column in |
conv_threshold |
Numeric in |
se_ratio_threshold_floor |
Numeric scalar. Minimum half-width for
the |
Six logical pass / fail flags are attached to every parameter row:
pass_bias requires |bias_mc_se| < 3; pass_se_ratio requires
|se_ratio - 1| to lie within max(se_ratio_threshold_floor, 3 * 1.4 / sqrt(R_used)) (a noise-aware band that widens at small
R_used and tightens to the floor at large R_used); pass_cov95
requires the nominal 95 percent level to lie in the Wilson band for
empirical coverage; pass_skew requires |skew_z| < 0.3; pass_kurt
requires excess kurtosis of z in [-0.5, 1.0]; pass_convergence
requires the per-parameter convergence rate (R_used / R_total) to
meet conv_threshold.
Non-converged replications are excluded per parameter (reported in
R_excluded). Winsorized (5 percent / 95 percent) versions of bias,
sd_emp, and mean_se are reported in parallel columns
(bias_w, sd_emp_w, mean_se_w) so silent outlier exclusion is
transparent to the reader. Two robust SE-to-SD ratios accompany the
Hessian-mean-based se_ratio: se_ratio_med (median SE divided by
the empirical SD) and se_ratio_w (winsorized mean SE divided by the
winsorized empirical SD); both stay near 1 when 1-2 replications
produce near-singular Hessians that inflate mean_se. The companion
se_med column reports the median per-replication SE used by
se_ratio_med. Neither robust ratio drives a pass_* flag — they
are purely informational.
Winsorized z-moment counterparts (mean_z_w, sd_z_w, skew_z_w,
kurt_excess_z_w) are reported alongside the raw z-moments and feed an
additional pass_z_w flag (Winsorized skew within the same band as
pass_skew AND Winsorized excess kurtosis within the same band as
pass_kurt). A companion pass_cov95_w flag is TRUE when either
pass_cov95 is TRUE OR the per-rep Winsorized z-CI (the empirical
2.5 / 97.5 percentiles of the Winsorized z) covers truth-zero. These
two flags are designed for boundary scenarios (e.g., near-zero variance
components) where a small number of reps with vanishing SE inflate the
raw z-moments without indicating an estimator defect.
An object of class choicer_mc_asymptotics — a data.table
with one row per unique parameter and columns documented above — with
meta attached as an attribute (attr(x, "meta")).
sim_fun <- function(seed) simulate_mnl_data(N = 1000, J = 3, seed = seed) fit_fun <- function(sim) run_mnlogit( data = sim$data, id_col = "id", alt_col = "alt", choice_col = "choice", covariate_cols = c("x1", "x2"), outside_opt_label = 0L, include_outside_option = FALSE, use_asc = TRUE, control = list(print_level = 0L) ) mc <- monte_carlo(sim_fun, fit_fun, R = 50L, seed = 1L, progress = FALSE) mc_asymptotics(mc)sim_fun <- function(seed) simulate_mnl_data(N = 1000, J = 3, seed = seed) fit_fun <- function(sim) run_mnlogit( data = sim$data, id_col = "id", alt_col = "alt", choice_col = "choice", covariate_cols = c("x1", "x2"), outside_opt_label = 0L, include_outside_option = FALSE, use_asc = TRUE, control = list(print_level = 0L) ) mc <- monte_carlo(sim_fun, fit_fun, R = 50L, seed = 1L, progress = FALSE) mc_asymptotics(mc)
Monte Carlo standard error (MCSE) of the posterior mean or median, using
the rank-normalized bulk/tail ESS from ess.
kind = "mean": MCSE = SD / sqrt(ess_bulk). kind =
"median": MCSE = sqrt(pi/2) * SD / sqrt(ess_tail) (the closed-form
normal asymptotic-efficiency approximation; 2/pi is the asymptotic
relative efficiency of the sample median vs. the mean under normality).
mcse(draws, kind = c("mean", "median"))mcse(draws, kind = c("mean", "median"))
draws |
A matrix of posterior draws (rows = iterations, columns = parameters) for a single chain, or a list of such matrices (one per chain, identical dimensions). |
kind |
|
Named numeric vector, one value per parameter (NA when the
underlying ESS or pooled SD is undefined).
set.seed(42) draws <- matrix(rnorm(2000), ncol = 2, dimnames = list(NULL, c("a", "b"))) mcse(draws) mcse(draws, kind = "median")set.seed(42) draws <- matrix(rnorm(2000), ncol = 2, dimnames = list(NULL, c("a", "b"))) mcse(draws) mcse(draws, kind = "median")
Stated choices of intercity travel mode for 210 travellers, each choosing among the same four modes: air, train, bus and car. This is the classic Greene & Hensher (1997) data set, reshaped into choicer's long layout (one row per traveller-by-alternative). It is a convenient, recognizable example for multinomial and nested logit models and the demand/welfare toolkit (elasticities, diversion ratios, willingness-to-pay, counterfactuals).
mode_choicemode_choice
A data frame with 840 rows (210 travellers x 4 modes) and 9 columns:
Integer traveller (choice situation) identifier, 1-210.
Factor giving the travel mode: "air", "train",
"bus" or "car". Use as the alternative column.
Integer indicator, 1 for the chosen mode and 0 otherwise. Exactly one mode is chosen per traveller.
Terminal waiting time in minutes (0 for car).
In-vehicle travel time in minutes.
In-vehicle cost component, in currency units.
Generalized cost measure, in currency units.
Household income (traveller level, in thousands).
Size of the travelling party (traveller level).
wait, travel, vcost and gcost vary across modes
within a traveller, while income and size are traveller-level
attributes that are constant across modes. A standard specification regresses
the choice on wait, travel and vcost with
alternative-specific constants; vcost then plays the role of price for
willingness-to-pay and consumer-surplus calculations.
The sample is choice-based: the survey over-sampled the less popular
modes (air, train, bus) and under-sampled car, so sample choice shares do
not estimate population mode shares. With a full set of
alternative-specific constants the slope coefficients remain consistently
estimated under this design (Manski and Lerman, 1977), and
willingness-to-pay ratios are unaffected; the constants, and any shares,
elasticities or surplus levels computed from fitted probabilities, inherit
the sampling design. To target population quantities, attach WESML weights
with wesml_weights using external population shares; see
vignette("wesml", package = "choicer").
Greene, W. H. and Hensher, D. A. (1997). Reshaped from the TravelMode
data distributed with the AER package
(https://CRAN.R-project.org/package=AER). The same data appear in
Greene's Econometric Analysis and in several other choice-modelling
packages.
Manski, C. F. and Lerman, S. R. (1977). The estimation of choice probabilities from choice based samples. Econometrica, 45(8), 1977-1988.
data(mode_choice) head(mode_choice) table(mode_choice$mode[mode_choice$choice == 1L])data(mode_choice) head(mode_choice) table(mode_choice$mode[mode_choice$choice == 1L])
Replicates a (DGP -> fit) cycle R times with independent seeds and
collects per-parameter estimates, standard errors, bias, and coverage.
Returns a choicer_mc object; call summary() for aggregated statistics
(mean estimate, bias, RMSE, coverage rate, convergence rate).
monte_carlo( sim_fun, fit_fun, R = 100, seed = 1L, parallel = FALSE, progress = TRUE, ... )monte_carlo( sim_fun, fit_fun, R = 100, seed = 1L, parallel = FALSE, progress = TRUE, ... )
sim_fun |
Function of |
fit_fun |
Function of a |
R |
Number of replications. |
seed |
Base integer seed. Replication |
parallel |
Logical; if |
progress |
Logical; print a one-line progress update per iteration in
serial mode. Ignored when |
... |
Unused. |
Each iteration calls sim_fun(seed = seed + r - 1L), then fit_fun(sim).
Write sim_fun as a closure that captures N, J, and other DGP settings
and forwards seed. Write fit_fun as a closure that takes a
choicer_sim and returns a fitted choicer_fit object, wrapping any
data-preparation, draws, or optimizer-control setup.
A choicer_mc object: a list with elements replications (a long
data.table with one row per estimated parameter per replication) and
meta (run metadata).
sim_fun <- function(seed) simulate_mnl_data(N = 1000, J = 4, seed = seed) fit_fun <- function(sim) run_mnlogit( data = sim$data, id_col = "id", alt_col = "alt", choice_col = "choice", covariate_cols = c("x1", "x2"), outside_opt_label = 0L, include_outside_option = FALSE, use_asc = TRUE, control = list(print_level = 0L) ) mc <- monte_carlo(sim_fun, fit_fun, R = 5, seed = 1L, progress = FALSE) summary(mc)sim_fun <- function(seed) simulate_mnl_data(N = 1000, J = 4, seed = seed) fit_fun <- function(sim) run_mnlogit( data = sim$data, id_col = "id", alt_col = "alt", choice_col = "choice", covariate_cols = c("x1", "x2"), outside_opt_label = 0L, include_outside_option = FALSE, use_asc = TRUE, control = list(print_level = 0L) ) mc <- monte_carlo(sim_fun, fit_fun, R = 5, seed = 1L, progress = FALSE) summary(mc)
Finds the ASC (delta) parameters such that predicted market shares match target shares, using the contraction mapping of Berry, Levinsohn, and Pakes (1995).
mxl_blp_contraction( delta, target_shares, X, W, beta, mu, L_params, alt_idx, M, weights, eta_draws, rc_dist, rc_correlation = TRUE, rc_mean = FALSE, include_outside_option = FALSE, tol = 1e-08, max_iter = 1000L, gen_seed = -1L, gen_scramble = 1L, gen_S = 0L )mxl_blp_contraction( delta, target_shares, X, W, beta, mu, L_params, alt_idx, M, weights, eta_draws, rc_dist, rc_correlation = TRUE, rc_mean = FALSE, include_outside_option = FALSE, tol = 1e-08, max_iter = 1000L, gen_seed = -1L, gen_scramble = 1L, gen_S = 0L )
delta |
J-1 or J vector with initial guess for deltas (ASCs) |
target_shares |
J vector with target market shares |
X |
design matrix for fixed coefficients; sum(M_i) x K_x |
W |
design matrix for random coefficients; sum(M_i) x K_w or J x K_w |
beta |
K_x vector with fixed coefficients |
mu |
K_w vector with mean parameters (raw, will be transformed if log-normal) |
L_params |
Cholesky parameters vector |
alt_idx |
sum(M) x 1 vector with indices of alternatives; 1-based indexing |
M |
N x 1 vector with number of alternatives for each individual |
weights |
N x 1 vector with weights for each observation |
eta_draws |
Array with draws; K_w x S x N |
rc_dist |
K_w vector indicating distribution (0=normal, 1=log-normal) |
rc_correlation |
whether random coefficients are correlated |
rc_mean |
whether mu parameters represent means (TRUE) or are zero (FALSE) |
include_outside_option |
whether outside option is included |
tol |
convergence tolerance (default 1e-8) |
max_iter |
maximum iterations (default 1000) |
gen_seed |
Integer. |
gen_scramble |
Integer mode of the draws formed on the fly: |
gen_S |
Integer number of draws per individual, used only when |
With gen_seed >= 0 the draws are formed again at every
evaluation of the shares. blp() on a fitted model runs the
same contraction but keeps them across iterations within its
keep_draws_bytes (see blp.choicer_mxl).
vector with converged delta (ASC) values
library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), w1 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] d <- prepare_mxl_data(dt, "id", "alt", "choice", "x1", "w1") eta <- get_halton_normals(50, d$N, ncol(d$W)) fit <- run_mxlogit(input_data = d, eta_draws = eta) pm <- fit$param_map delta <- mxl_blp_contraction(rep(0, J), rep(1/J, J), d$X, d$W, coef(fit)[pm$beta], rep(0, ncol(d$W)), coef(fit)[pm$sigma], d$alt_idx, d$M, d$weights, eta, rc_dist = rep(0L, ncol(d$W)), rc_correlation = FALSE, rc_mean = FALSE) deltalibrary(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), w1 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] d <- prepare_mxl_data(dt, "id", "alt", "choice", "x1", "w1") eta <- get_halton_normals(50, d$N, ncol(d$W)) fit <- run_mxlogit(input_data = d, eta_draws = eta) pm <- fit$param_map delta <- mxl_blp_contraction(rep(0, J), rep(1/J, J), d$X, d$W, coef(fit)[pm$beta], rep(0, ncol(d$W)), coef(fit)[pm$sigma], d$alt_idx, d$M, d$weights, eta, rc_dist = rep(0L, ncol(d$W)), rc_correlation = FALSE, rc_mean = FALSE) delta
choicer_sim objectWraps simulated data, true parameter values, and DGP settings into a
classed list. Returned by simulate_mnl_data(), simulate_mxl_data(),
and simulate_nl_data(), and consumed by recovery_table().
new_choicer_sim(data, true_params, settings, model)new_choicer_sim(data, true_params, settings, model)
data |
A |
true_params |
Named list of true DGP parameters
(e.g. |
settings |
Named list of DGP settings (e.g. |
model |
Character scalar: |
A list of class choicer_sim.
Damped iterative fixed point recovering delta given target shares, using the
NL probability structure. damping = 1 reproduces the plain BLP update.
nl_blp_contraction( delta, target_shares, X, beta, lambda, alt_idx, nest_idx, M, weights, include_outside_option = FALSE, damping = 1, tol = 1e-08, max_iter = 1000L )nl_blp_contraction( delta, target_shares, X, beta, lambda, alt_idx, nest_idx, M, weights, include_outside_option = FALSE, damping = 1, tol = 1e-08, max_iter = 1000L )
delta |
J x 1 vector with initial guess for deltas (ASCs). |
target_shares |
vector with target shares (outside-option share first when present). |
X |
sum(M) x K design matrix with covariates. |
beta |
K x 1 vector with fixed coefficients. |
lambda |
full nest dissimilarity vector of length n_nests (singletons = 1). |
alt_idx |
sum(M) x 1 vector with indices of alternatives; 1-based indexing. |
nest_idx |
J x 1 vector with nest indices for each alternative; 1-based indexing. |
M |
N x 1 vector with number of alternatives for each individual. |
weights |
N x 1 vector with weights for each observation. |
include_outside_option |
whether to include outside option normalized to V=0, lambda=1. |
damping |
damping factor for the update (default 1.0 = plain BLP). |
tol |
convergence tolerance. |
max_iter |
maximum number of iterations. |
vector with contraction's delta (ASCs) output.
library(data.table) set.seed(42) N <- 50; J <- 4 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, nest := ifelse(alt <= 2, "A", "B")] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_nestlogit(dt, "id", "alt", "choice", c("x1", "x2"), "nest") beta <- coef(fit)[fit$param_map$beta] lambda <- rep(1, length(unique(fit$data$nest_idx))) lambda[as.integer(names(which(table(fit$data$nest_idx) > 1)))] <- coef(fit)[fit$param_map$lambda] delta <- nl_blp_contraction(rep(0, J), rep(1/J, J), fit$data$X, beta, lambda, fit$data$alt_idx, fit$data$nest_idx, fit$data$M, fit$data$weights) deltalibrary(data.table) set.seed(42) N <- 50; J <- 4 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, nest := ifelse(alt <= 2, "A", "B")] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_nestlogit(dt, "id", "alt", "choice", c("x1", "x2"), "nest") beta <- coef(fit)[fit$param_map$beta] lambda <- rep(1, length(unique(fit$data$nest_idx))) lambda[as.integer(names(which(table(fit$data$nest_idx) > 1)))] <- coef(fit)[fit$param_map$lambda] delta <- nl_blp_contraction(rep(0, J), rep(1/J, J), fit$data$X, beta, lambda, fit$data$alt_idx, fit$data$nest_idx, fit$data$M, fit$data$weights) delta
Extract number of observations from a choicer_fit object
## S3 method for class 'choicer_fit' nobs(object, ...)## S3 method for class 'choicer_fit' nobs(object, ...)
object |
A choicer_fit object. |
... |
Additional arguments (ignored). |
Integer number of choice situations.
library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) nobs(fit)library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) nobs(fit)
Number of choice situations behind a hierarchical Bayes fit
## S3 method for class 'choicer_hb' nobs(object, ...)## S3 method for class 'choicer_hb' nobs(object, ...)
object |
A |
... |
Additional arguments (ignored). |
Integer count of choice situations (tasks).
Extract number of observations from a choicer_mnp object
## S3 method for class 'choicer_mnp' nobs(object, ...)## S3 method for class 'choicer_mnp' nobs(object, ...)
object |
A choicer_mnp object. |
... |
Additional arguments (ignored). |
Integer number of choice situations.
library(data.table) set.seed(42) N <- 100; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnprobit(dt, "id", "alt", "choice", c("x1", "x2"), mcmc = list(R = 300, burn = 100)) nobs(fit)library(data.table) set.seed(42) N <- 100; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnprobit(dt, "id", "alt", "choice", c("x1", "x2"), mcmc = list(R = 300, burn = 100)) nobs(fit)
Computes counterfactual choice probabilities, integrating over the
posterior draws and (at the population level) over the random-coefficient
distribution: for each kept draw one
is drawn and the model probabilities are
averaged. Alternatives in newdata that were not in the estimation
sample receive a posterior-predictive
— the entry
counterfactual unlocked by the random-effects . Price or
subsidy counterfactuals are just modified covariate columns in newdata.
## S3 method for class 'choicer_hb' predict( object, newdata = NULL, level = c("population", "individual"), n_draws = 200L, aggregate = TRUE, ... )## S3 method for class 'choicer_hb' predict( object, newdata = NULL, level = c("population", "individual"), n_draws = 200L, aggregate = TRUE, ... )
object |
A |
newdata |
Data frame with the estimation columns (choice column not
required). |
level |
|
n_draws |
Number of posterior draws to integrate over (thinned evenly from the kept draws; default 200). |
aggregate |
If |
... |
Ignored. |
HMNL probabilities are closed-form logit; HMNP probabilities use the
1-D Gauss-Hermite representation of the iid-probit integral
.
With aggregate = TRUE, a data.table with columns
alternative, share (posterior mean), sd, lower, upper (95%
equal-tailed interval); the posterior share draws are attached as
attr(, "draws"). With aggregate = FALSE, a numeric vector of
posterior-mean choice probabilities, one per prediction row.
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))) predict(fit) # posterior shares, estimation data cf <- sim$data cf$x1 <- cf$x1 + 0.5 # a counterfactual attribute change predict(fit, newdata = cf)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))) predict(fit) # posterior shares, estimation data cf <- sim$data cf$x1 <- cf$x1 + 0.5 # a counterfactual attribute change predict(fit, newdata = cf)
Computes choice probabilities or aggregate market shares, either for the
data used at fit time (default) or for counterfactual newdata.
## S3 method for class 'choicer_mnl' predict( object, type = c("probabilities", "shares"), newdata = NULL, weights = NULL, ... )## S3 method for class 'choicer_mnl' predict( object, type = c("probabilities", "shares"), newdata = NULL, weights = NULL, ... )
object |
A choicer_mnl object. |
type |
One of "probabilities" (individual-level choice probabilities) or "shares" (aggregate market shares). |
newdata |
Optional data for counterfactual prediction. Either:
When |
weights |
Optional numeric vector with one weight per choice situation,
used for |
... |
Additional arguments (ignored). |
For "probabilities": a list with choice_prob and utility,
one-column matrices with one row per row of the data; with a data.frame
newdata, rows are ordered by id, then by fit-time alternative code
(alt_int in object$alt_mapping). For "shares": the market shares as
a one-column matrix with one row per alternative of object$alt_mapping,
in its order (the outside option's first when it is modelled), 0 for an
alternative that newdata does not offer.
library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) predict(fit, type = "shares") predict(fit, type = "probabilities") # Counterfactual: increase x1 for alternative 2 dt_cf <- copy(dt)[alt == 2, x1 := x1 + 1] predict(fit, type = "shares", newdata = dt_cf)library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) predict(fit, type = "shares") predict(fit, type = "probabilities") # Counterfactual: increase x1 for alternative 2 dt_cf <- copy(dt)[alt == 2, x1 := x1 + 1] predict(fit, type = "shares", newdata = dt_cf)
Computes simulated choice probabilities or aggregate market shares using
deterministic Halton draws, either for the data used at fit time (default)
or for counterfactual newdata.
## S3 method for class 'choicer_mxl' predict( object, type = c("probabilities", "shares"), newdata = NULL, weights = NULL, ... )## S3 method for class 'choicer_mxl' predict( object, type = c("probabilities", "shares"), newdata = NULL, weights = NULL, ... )
object |
A choicer_mxl object. |
type |
Either "probabilities" (per-observation simulated choice probabilities) or "shares" (aggregate simulated market shares). |
newdata |
Optional data for counterfactual prediction. Either:
When |
weights |
Optional numeric vector with one weight per choice situation,
used for |
... |
Additional arguments (ignored). |
For "probabilities": a list with choice_prob and utility,
one-column matrices averaged across simulation draws with one row per
row of the data, and with the outside option choice_prob_outside, one
row per choice situation; with a data.frame newdata, rows are ordered
by id, then by fit-time alternative code (alt_int in
object$alt_mapping), and for a panel fit whose person_col is present
in newdata, by decision maker first, which reproduces the in-sample row
order. For "shares": the simulated market
shares as a one-column matrix with one row per alternative of
object$alt_mapping, in its order (the outside option's first when it
is modelled), 0 for an alternative that newdata does not offer.
Predictions are unconditional: each choice situation integrates over the
population taste distribution (see conditional_tastes() for tastes
conditional on observed choices).
library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), w1 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mxlogit( data = dt, id_col = "id", alt_col = "alt", choice_col = "choice", covariate_cols = "x1", random_var_cols = "w1", S = 50L ) predict(fit, type = "shares") predict(fit, type = "probabilities")library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), w1 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mxlogit( data = dt, id_col = "id", alt_col = "alt", choice_col = "choice", covariate_cols = "x1", random_var_cols = "w1", S = 50L ) predict(fit, type = "shares") predict(fit, type = "probabilities")
Computes choice probabilities or aggregate market shares, either for the
data used at fit time (default) or for counterfactual newdata.
## S3 method for class 'choicer_nl' predict( object, type = c("probabilities", "shares"), newdata = NULL, weights = NULL, ... )## S3 method for class 'choicer_nl' predict( object, type = c("probabilities", "shares"), newdata = NULL, weights = NULL, ... )
object |
A choicer_nl object. |
type |
One of "probabilities" (individual-level choice probabilities) or "shares" (aggregate market shares). |
newdata |
Optional data for counterfactual prediction. Either:
When |
weights |
Optional numeric vector with one weight per choice situation,
used for |
... |
Additional arguments (ignored). |
For "probabilities": a list with choice_prob and utility,
one-column matrices with one row per row of the data; with a data.frame
newdata, rows are ordered by id, then by fit-time alternative code
(alt_int in object$alt_mapping). For "shares": the market shares as
a one-column matrix with one row per alternative of object$alt_mapping,
in its order (the outside option's first when it is modelled), 0 for an
alternative that newdata does not offer.
library(data.table) set.seed(42) N <- 50; J <- 4 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, nest := rep(c(1L, 1L, 2L, 2L), N)] dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_nestlogit(dt, "id", "alt", "choice", c("x1", "x2"), "nest") predict(fit, type = "shares") predict(fit, type = "probabilities")library(data.table) set.seed(42) N <- 50; J <- 4 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, nest := rep(c(1L, 1L, 2L, 2L), N)] dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_nestlogit(dt, "id", "alt", "choice", c("x1", "x2"), "nest") predict(fit, type = "shares") predict(fit, type = "probabilities")
Prepares and validates panel (or cross-sectional) choice data for the
hierarchical Bayesian multinomial logit. The model has two random-effect
levels: respondent-level structural tastes
over the covariate_cols, and a global alternative-level effect
, ,
with mean-function design built from alt_covariate_cols.
prepare_hmnl_data( data, id_col, alt_col, choice_col, covariate_cols, person_col = NULL, alt_covariate_cols = NULL, outside_opt_label = NULL, cf_residual_col = NULL, include_outside_option = TRUE, rc_dist = NULL )prepare_hmnl_data( data, id_col, alt_col, choice_col, covariate_cols, person_col = NULL, alt_covariate_cols = NULL, outside_opt_label = NULL, cf_residual_col = NULL, include_outside_option = TRUE, rc_dist = NULL )
data |
Data frame containing choice data. |
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. |
alt_covariate_cols |
Names of alternative-level covariate columns
(constant within each alternative) forming the |
outside_opt_label |
Label of physical outside-option rows, removed
when |
cf_residual_col |
Name of a first-stage residual column (control
function for an endogenous covariate), appended to |
include_outside_option |
Logical; if |
rc_dist |
Integer vector, one entry per column of |
Structure. The design matrix X carries structural covariates
only — no alternative-specific-constant dummies. The alternative effect
is indexed by alt_of_row (integer codes 1..J), so
memory and compute scale with the number of rows, not with J extra
design columns.
Outside option. With include_outside_option = TRUE (the
default) the outside good is modelled implicitly, following the
prepare_mnl_data() convention: physical outside rows (identified by
outside_opt_label) are removed, the estimation kernels add the outside
term (systematic utility 0), and a choice situation whose inside rows are
all 0 in choice_col is coded as "outside chosen" (choice_pos = 0).
The outside option anchors the location of (mean utility
relative to the outside good).
Cross-section vs panel. person_col groups choice situations
into respondents sharing one . With person_col = NULL
(default) every choice situation is its own respondent (Ti all 1) —
the cross-sectional random-coefficients mode.
Control function. cf_residual_col (a user-supplied first-stage
residual, Petrin & Train 2010) is appended to X as an ordinary
covariate; its provenance is recorded in data_spec. The first stage is
NOT run here — supplying a valid residual is the user's responsibility.
A list of class c("choicer_data_hmnl", "list") containing:
X: Structural design matrix (total_rows x K_struct, double), no
ASC columns; cf_residual_col last when supplied.
alt_of_row: Integer alternative code per row (1..J).
alt_idx: Alias of alt_of_row for the pooled-MLE init.
Z: Alternative-level design (J x P), intercept first.
M: Inside alternatives per choice situation.
choice_pos: 1-based within-task position of the chosen row;
0 = outside option chosen.
Ti: Choice situations per respondent.
person_ids, N_persons, n_tasks, J, K_struct, P.
include_outside_option: Logical flag.
alt_mapping: Data.table mapping alternatives to summary
statistics (outside option is alt_int = 0).
param_map: Named list of index vectors (beta, theta),
robust to collinearity drops.
rc_dist: Integer vector aligned with the columns of X.
dropped_cols, dropped_z_cols: Dropped column names, if any.
data_spec: Column-name metadata (incl. person_col,
outside_opt_label, cf_residual_col, alt_covariate_cols).
No column the model uses (the id, alternative, choice, covariate, weight,
cluster, nest or decision-maker column) may have a name starting with
.choicer_, which choicer reserves for its working columns, and the
alternative column may not be named alt_int, N_OBS, N_CHOICES,
TAKE_RATE or MKT_SHARE, the names of the other columns of
alt_mapping. Either is an error that names the column. Columns the model
does not use may have any name.
prepare_hmnp_data() for the hierarchical probit counterpart.
library(data.table) set.seed(42) N <- 20; T <- 3; J <- 4 dt <- data.table( pid = rep(1:N, each = T * J), task = rep(seq_len(N * T), each = J), alt = rep(1:J, N * T) ) dt[, `:=`(x1 = rnorm(.N), x2 = runif(.N, -1, 1))] dt[, quality := 0.1 * alt] # alternative-level covariate dt[, choice := 0L] # leave some tasks all-zero: outside option chosen dt[, choice := if (runif(1) < 0.8) sample(c(1L, rep(0L, J - 1))) else 0L, by = task] input <- prepare_hmnl_data(dt, "task", "alt", "choice", c("x1", "x2"), person_col = "pid", alt_covariate_cols = "quality") str(input$Z) input$alt_mappinglibrary(data.table) set.seed(42) N <- 20; T <- 3; J <- 4 dt <- data.table( pid = rep(1:N, each = T * J), task = rep(seq_len(N * T), each = J), alt = rep(1:J, N * T) ) dt[, `:=`(x1 = rnorm(.N), x2 = runif(.N, -1, 1))] dt[, quality := 0.1 * alt] # alternative-level covariate dt[, choice := 0L] # leave some tasks all-zero: outside option chosen dt[, choice := if (runif(1) < 0.8) sample(c(1L, rep(0L, J - 1))) else 0L, by = task] input <- prepare_hmnl_data(dt, "task", "alt", "choice", c("x1", "x2"), person_col = "pid", alt_covariate_cols = "quality") str(input$Z) input$alt_mapping
Prepares and validates panel (or cross-sectional) choice data for the
hierarchical Bayesian multinomial probit with iid
utility shocks. The model shares its two-level random-effect structure
with prepare_hmnl_data(): respondent-level structural tastes
over the covariate_cols (normal only — the
probit keeps full conjugacy), and a global alternative-level effect
, .
prepare_hmnp_data( data, id_col, alt_col, choice_col, covariate_cols, person_col = NULL, alt_covariate_cols = NULL, outside_opt_label = NULL, cf_residual_col = NULL, include_outside_option = TRUE )prepare_hmnp_data( data, id_col, alt_col, choice_col, covariate_cols, person_col = NULL, alt_covariate_cols = NULL, outside_opt_label = NULL, cf_residual_col = NULL, include_outside_option = TRUE )
data |
Data frame containing choice data. |
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. |
alt_covariate_cols |
Names of alternative-level covariate columns
(constant within each alternative) forming the |
outside_opt_label |
Label of physical outside-option rows, removed
when |
cf_residual_col |
Name of a first-stage residual column (control
function for an endogenous covariate), appended to |
include_outside_option |
Logical; if |
The returned structure is identical to prepare_hmnl_data() (both preps
share one internal engine), except there is no rc_dist field. Unlike
prepare_mnp_data(), utilities are NOT differenced against a base
alternative: the iid-shock model works in un-differenced utility space,
so unbalanced choice sets are supported and the outside option is
implicit (its latent utility is a stochastic draw in
the kernel, systematic utility 0).
A list of class c("choicer_data_hmnp", "list") with the same
components as prepare_hmnl_data() (minus rc_dist).
No column the model uses (the id, alternative, choice, covariate, weight,
cluster, nest or decision-maker column) may have a name starting with
.choicer_, which choicer reserves for its working columns, and the
alternative column may not be named alt_int, N_OBS, N_CHOICES,
TAKE_RATE or MKT_SHARE, the names of the other columns of
alt_mapping. Either is an error that names the column. Columns the model
does not use may have any name.
prepare_hmnl_data() for the component-by-component description.
library(data.table) set.seed(42) N <- 20; T <- 3; J <- 4 dt <- data.table( pid = rep(1:N, each = T * J), task = rep(seq_len(N * T), each = J), alt = rep(1:J, N * T) ) dt[, `:=`(x1 = rnorm(.N), x2 = runif(.N, -1, 1))] dt[, choice := 0L] dt[, choice := if (runif(1) < 0.8) sample(c(1L, rep(0L, J - 1))) else 0L, by = task] input <- prepare_hmnp_data(dt, "task", "alt", "choice", c("x1", "x2"), person_col = "pid") input$Ti[1:5] input$alt_mappinglibrary(data.table) set.seed(42) N <- 20; T <- 3; J <- 4 dt <- data.table( pid = rep(1:N, each = T * J), task = rep(seq_len(N * T), each = J), alt = rep(1:J, N * T) ) dt[, `:=`(x1 = rnorm(.N), x2 = runif(.N, -1, 1))] dt[, choice := 0L] dt[, choice := if (runif(1) < 0.8) sample(c(1L, rep(0L, J - 1))) else 0L, by = task] input <- prepare_hmnp_data(dt, "task", "alt", "choice", c("x1", "x2"), person_col = "pid") input$Ti[1:5] input$alt_mapping
Prepares and validates inputs for multinomial logit estimation routine.
prepare_mnl_data( data, id_col, alt_col, choice_col, covariate_cols, weights = NULL, outside_opt_label = NULL, include_outside_option = FALSE, weights_col = NULL, cluster_col = NULL )prepare_mnl_data( data, id_col, alt_col, choice_col, covariate_cols, weights = NULL, outside_opt_label = NULL, include_outside_option = FALSE, weights_col = NULL, cluster_col = NULL )
data |
Data frame containing choice data. |
id_col |
Name of the column identifying choice situations (individuals). |
alt_col |
Name of the column identifying alternatives. |
choice_col |
Name of the column indicating chosen alternative (1 = chosen, 0 = not chosen). |
covariate_cols |
Vector of names of columns to be used as covariates. |
weights |
Optional vector of weights for each choice situation. If |
outside_opt_label |
The label of the outside option or of the base
alternative, given in the class of the alternative column. With
|
include_outside_option |
Logical indicating whether to include an outside option in the model. |
weights_col |
Optional name of a column in |
cluster_col |
Optional name of a column in |
A list containing:
X: Design matrix (sum(M) x K, double).
alt_idx: Integer vector of alternative indices.
choice_idx: Integer vector of chosen alternative indices.
M: Integer vector with number of alternatives per choice situation.
N: Number of choice situations.
weights: Vector of weights.
cluster: Vector of cluster labels (or NULL).
situation_ids: Choice-situation ids in prepared (sorted) order.
include_outside_option: Logical flag.
alt_mapping: Data.table mapping alternatives to summary statistics.
dropped_cols: Names of columns dropped due to collinearity, if any.
No column the model uses (the id, alternative, choice, covariate, weight,
cluster, nest or decision-maker column) may have a name starting with
.choicer_, which choicer reserves for its working columns, and the
alternative column may not be named alt_int, N_OBS, N_CHOICES,
TAKE_RATE or MKT_SHARE, the names of the other columns of
alt_mapping. Either is an error that names the column. Columns the model
does not use may have any name.
library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] input <- prepare_mnl_data(dt, "id", "alt", "choice", c("x1", "x2")) str(input$X) input$alt_mappinglibrary(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] input <- prepare_mnl_data(dt, "id", "alt", "choice", c("x1", "x2")) str(input$X) input$alt_mapping
Prepares and validates inputs for Bayesian multinomial probit estimation.
Covariates are differenced against the base alternative, so the design
matrix has one row per (choice situation, non-base alternative) pair.
Balanced choice sets are required: every choice situation must contain
the same alternatives.
prepare_mnp_data( data, id_col, alt_col, choice_col, covariate_cols, base_alt = NULL, use_asc = TRUE )prepare_mnp_data( data, id_col, alt_col, choice_col, covariate_cols, base_alt = NULL, use_asc = TRUE )
data |
Data frame containing choice data. |
id_col |
Name of the column identifying choice situations (individuals). |
alt_col |
Name of the column identifying alternatives. |
choice_col |
Name of the column indicating chosen alternative (1 = chosen, 0 = not chosen). |
covariate_cols |
Vector of names of columns to be used as covariates. |
base_alt |
Label of the base (reference) alternative used for utility
differencing. If |
use_asc |
Logical indicating whether to include alternative-specific
constants (one intercept per non-base alternative), named
|
A list containing:
X: Stacked differenced design matrix ((N * p) x K, double),
covariate columns first, then ASC columns when use_asc = TRUE.
y: Integer vector of choices (0 = base alternative, j in 1..p
for the j-th non-base alternative), one per choice situation.
p: Number of utility differences (J - 1).
J: Number of alternatives.
N: Number of choice situations.
K: Number of columns of X.
alt_mapping: Data.table mapping alternatives to summary statistics
(the base alternative is alt_int = 1).
base_alt: Resolved label of the base alternative.
param_map: Named list of integer index vectors (beta, asc).
use_asc: Logical flag.
dropped_cols: Names of columns dropped due to collinearity, if any.
data_spec: List with column name metadata.
No column the model uses (the id, alternative, choice, covariate, weight,
cluster, nest or decision-maker column) may have a name starting with
.choicer_, which choicer reserves for its working columns, and the
alternative column may not be named alt_int, N_OBS, N_CHOICES,
TAKE_RATE or MKT_SHARE, the names of the other columns of
alt_mapping. Either is an error that names the column. Columns the model
does not use may have any name.
library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] input <- prepare_mnp_data(dt, "id", "alt", "choice", c("x1", "x2")) str(input$X) input$alt_mappinglibrary(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] input <- prepare_mnp_data(dt, "id", "alt", "choice", c("x1", "x2")) str(input$X) input$alt_mapping
Prepares and validates inputs for mixed logit estimation routine.
prepare_mxl_data( data, id_col, alt_col, choice_col, covariate_cols, random_var_cols, weights = NULL, outside_opt_label = NULL, include_outside_option = FALSE, rc_correlation = FALSE, weights_col = NULL, cluster_col = NULL, person_col = NULL )prepare_mxl_data( data, id_col, alt_col, choice_col, covariate_cols, random_var_cols, weights = NULL, outside_opt_label = NULL, include_outside_option = FALSE, rc_correlation = FALSE, weights_col = NULL, cluster_col = NULL, person_col = NULL )
data |
Data frame containing choice data |
id_col |
Name of the column identifying choice situations |
alt_col |
Name of the column identifying alternatives |
choice_col |
Name of the column indicating chosen alternative (1 = chosen, 0 = not chosen) |
covariate_cols |
Vector of names of columns to be used as covariates |
random_var_cols |
Vector of names of columns to be used as random variables |
weights |
Optional vector of weights, one per choice situation in the
prepared order (ascending id; see Details). If NULL, equal weights are
used. All weights
must be finite and strictly positive. With |
outside_opt_label |
The label of the outside option or of the base
alternative, given in the class of the alternative column. With
|
include_outside_option |
Logical indicating whether to include an outside option in the model. |
rc_correlation |
Logical indicating whether random coefficients are correlated. Default is FALSE. |
weights_col |
Optional name of a column in |
cluster_col |
Optional name of a column in |
person_col |
Optional name of the column identifying decision makers
(respondents). When supplied, all choice situations of a decision maker
share one draw of the random coefficients (panel likelihood);
|
Rows are ordered by choice-situation id and, within a situation, by
alternative. With person_col, rows are ordered by decision maker
first, then by situation id and alternative, so that each decision maker's
situations are contiguous. A positional weights vector is read in
the prepared order, which is ascending id in the cross-section; with
person_col it is accepted only when the prepared order is also
ascending id, and an error otherwise points to weights_col, which is
aligned by id and is the safer interface.
A choicer_data_mxl object (list) containing:
X: Fixed-coefficient design matrix (sum(M) x K_x, double).
W: Random-coefficient design matrix (sum(M) x K_w, double).
alt_idx: Integer vector of alternative indices.
choice_idx: Integer vector of chosen alternative indices.
M: Integer vector with number of alternatives per choice situation.
N: Number of choice situations.
weights: Vector of weights.
cluster: Vector of cluster labels (or NULL).
situation_ids: Choice-situation ids in prepared (sorted) order.
Ti: Number of choice situations of each decision maker, in
prepared order (NULL without person_col).
person_ids: Decision-maker ids in prepared order (NULL
without person_col).
include_outside_option: Logical flag.
rc_correlation: Logical flag.
alt_mapping: data.table mapping alternatives to summary statistics.
dropped_cols: Names of columns dropped due to collinearity, if any.
data_spec: List with column-name metadata (incl. person_col).
No column the model uses (the id, alternative, choice, covariate, weight,
cluster, nest or decision-maker column) may have a name starting with
.choicer_, which choicer reserves for its working columns, and the
alternative column may not be named alt_int, N_OBS, N_CHOICES,
TAKE_RATE or MKT_SHARE, the names of the other columns of
alt_mapping. Either is an error that names the column. Columns the model
does not use may have any name.
library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), w1 = rnorm(.N), w2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] input <- prepare_mxl_data(dt, "id", "alt", "choice", "x1", c("w1", "w2")) str(input$X) str(input$W)library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), w1 = rnorm(.N), w2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] input <- prepare_mxl_data(dt, "id", "alt", "choice", "x1", c("w1", "w2")) str(input$X) str(input$W)
Validates inputs, builds design matrices, and constructs nest structure
for nested logit estimation. Calls prepare_mnl_data internally
for base data preparation, then adds nest-specific fields.
prepare_nl_data( data, id_col, alt_col, choice_col, covariate_cols, nest_col, weights = NULL, outside_opt_label = NULL, include_outside_option = FALSE, weights_col = NULL, cluster_col = NULL )prepare_nl_data( data, id_col, alt_col, choice_col, covariate_cols, nest_col, weights = NULL, outside_opt_label = NULL, include_outside_option = FALSE, weights_col = NULL, cluster_col = NULL )
data |
Data frame containing choice data. |
id_col |
Name of the column identifying choice situations (individuals). |
alt_col |
Name of the column identifying alternatives. |
choice_col |
Name of the column indicating chosen alternative (1 = chosen, 0 = not chosen). |
covariate_cols |
Vector of names of columns to be used as covariates. |
nest_col |
Name of the column mapping each alternative to its nest. Every alternative must belong to exactly one nest. |
weights |
Optional vector of weights for each choice situation. If |
outside_opt_label |
The label of the outside option or of the base
alternative, given in the class of the alternative column. With
|
include_outside_option |
Logical indicating whether to include an outside option in the model. |
weights_col |
Optional name of a column in |
cluster_col |
Optional name of a column in |
A choicer_data_nl object (list) containing:
All fields from prepare_mnl_data (X, alt_idx,
choice_idx, M, N, weights, cluster,
situation_ids, include_outside_option, alt_mapping,
dropped_cols).
nest_idx: Integer vector of length J mapping each alternative
(in alt_mapping row order) to its nest.
data_spec: List with column name metadata including nest_col.
No column the model uses (the id, alternative, choice, covariate, weight,
cluster, nest or decision-maker column) may have a name starting with
.choicer_, which choicer reserves for its working columns, and the
alternative column may not be named alt_int, N_OBS, N_CHOICES,
TAKE_RATE or MKT_SHARE, the names of the other columns of
alt_mapping. Either is an error that names the column. Columns the model
does not use may have any name.
library(data.table) set.seed(42) N <- 50; J <- 4 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, nest := ifelse(alt <= 2, "A", "B")] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] input <- prepare_nl_data(dt, "id", "alt", "choice", c("x1", "x2"), "nest") input$nest_idx input$alt_mappinglibrary(data.table) set.seed(42) N <- 50; J <- 4 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, nest := ifelse(alt <= 2, "A", "B")] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] input <- prepare_nl_data(dt, "id", "alt", "choice", c("x1", "x2"), "nest") input$nest_idx input$alt_mapping
Print a consumer surplus summary
## S3 method for class 'choicer_cs' print(x, digits = 4, ...)## S3 method for class 'choicer_cs' print(x, digits = 4, ...)
x |
A |
digits |
Number of significant digits to print. |
... |
Additional arguments (ignored). |
The object invisibly.
Prints a brief summary of the fitted model.
## S3 method for class 'choicer_fit' print(x, ...)## S3 method for class 'choicer_fit' print(x, ...)
x |
A choicer_fit object. |
... |
Additional arguments (ignored). |
The object invisibly.
library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) print(fit)library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) print(fit)
Print goodness-of-fit measures
## S3 method for class 'choicer_gof' print(x, ...)## S3 method for class 'choicer_gof' print(x, ...)
x |
A |
... |
Additional arguments (ignored). |
The object invisibly.
Print a hierarchical Bayes fit
## S3 method for class 'choicer_hb' print(x, ...)## S3 method for class 'choicer_hb' print(x, ...)
x |
A |
... |
Additional arguments (ignored). |
The object invisibly.
sim <- simulate_hmnl_data(N = 50, T = 2, J = 3, seed = 42) fit <- suppressWarnings(run_hmnlogit(sim$data, "task", "alt", "choice", c("x1", "x2"), person_col = "pid", mcmc = list(R = 300, burn = 100))) print(fit)sim <- simulate_hmnl_data(N = 50, T = 2, J = 3, seed = 42) fit <- suppressWarnings(run_hmnlogit(sim$data, "task", "alt", "choice", c("x1", "x2"), person_col = "pid", mcmc = list(R = 300, burn = 100))) print(fit)
Prints a brief summary of the fitted Bayesian multinomial probit model.
## S3 method for class 'choicer_mnp' print(x, ...)## S3 method for class 'choicer_mnp' print(x, ...)
x |
A choicer_mnp object. |
... |
Additional arguments (ignored). |
The object invisibly.
library(data.table) set.seed(42) N <- 100; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnprobit(dt, "id", "alt", "choice", c("x1", "x2"), mcmc = list(R = 300, burn = 100)) print(fit)library(data.table) set.seed(42) N <- 100; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnprobit(dt, "id", "alt", "choice", c("x1", "x2"), mcmc = list(R = 300, burn = 100)) print(fit)
Print conditional tastes
## S3 method for class 'choicer_tastes' print(x, digits = 3, ...)## S3 method for class 'choicer_tastes' print(x, digits = 3, ...)
x |
A |
digits |
Number of decimal places for the population table. |
... |
Additional arguments (ignored). |
The object invisibly.
Print a WTP table
## S3 method for class 'choicer_wtp' print(x, digits = 4, ...)## S3 method for class 'choicer_wtp' print(x, digits = 4, ...)
x |
A |
digits |
Number of significant digits to print. |
... |
Additional arguments passed to |
The object invisibly.
Print the summary of a hierarchical Bayes fit
## S3 method for class 'summary.choicer_hb' print(x, ...)## S3 method for class 'summary.choicer_hb' print(x, ...)
x |
A |
... |
Additional arguments (ignored). |
The object invisibly.
Print summary for multinomial logit model
## S3 method for class 'summary.choicer_mnl' print(x, ...)## S3 method for class 'summary.choicer_mnl' print(x, ...)
x |
A summary.choicer_mnl object. |
... |
Additional arguments (ignored). |
The object invisibly.
library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) print(summary(fit))library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) print(summary(fit))
Print summary for Bayesian multinomial probit model
## S3 method for class 'summary.choicer_mnp' print(x, ...)## S3 method for class 'summary.choicer_mnp' print(x, ...)
x |
A summary.choicer_mnp object. |
... |
Additional arguments (ignored). |
The object invisibly.
library(data.table) set.seed(42) N <- 100; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnprobit(dt, "id", "alt", "choice", c("x1", "x2"), mcmc = list(R = 300, burn = 100)) print(summary(fit))library(data.table) set.seed(42) N <- 100; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnprobit(dt, "id", "alt", "choice", c("x1", "x2"), mcmc = list(R = 300, burn = 100)) print(summary(fit))
Print summary for mixed logit model
## S3 method for class 'summary.choicer_mxl' print(x, ...)## S3 method for class 'summary.choicer_mxl' print(x, ...)
x |
A summary.choicer_mxl object. |
... |
Additional arguments (ignored). |
The object invisibly.
library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), w1 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mxlogit( data = dt, id_col = "id", alt_col = "alt", choice_col = "choice", covariate_cols = "x1", random_var_cols = "w1", S = 50L ) print(summary(fit))library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), w1 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mxlogit( data = dt, id_col = "id", alt_col = "alt", choice_col = "choice", covariate_cols = "x1", random_var_cols = "w1", S = 50L ) print(summary(fit))
Print summary for nested logit model
## S3 method for class 'summary.choicer_nl' print(x, ...)## S3 method for class 'summary.choicer_nl' print(x, ...)
x |
A summary.choicer_nl object. |
... |
Additional arguments (ignored). |
The object invisibly.
library(data.table) set.seed(42) N <- 50; J <- 4 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, nest := ifelse(alt <= 2, "A", "B")] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_nestlogit( data = dt, id_col = "id", alt_col = "alt", choice_col = "choice", covariate_cols = c("x1", "x2"), nest_col = "nest" ) print(summary(fit))library(data.table) set.seed(42) N <- 50; J <- 4 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, nest := ifelse(alt <= 2, "A", "B")] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_nestlogit( data = dt, id_col = "id", alt_col = "alt", choice_col = "choice", covariate_cols = c("x1", "x2"), nest_col = "nest" ) print(summary(fit))
Compares fitted coefficients to a set of true parameter values on the same scale as the estimator's internal parameterization. Returns one row per estimated parameter with true value, estimate, standard error, bias, relative bias (%), z-score against the truth, Wald CI, and a coverage indicator.
recovery_table(object, truth = NULL, level = 0.95, ...) ## S3 method for class 'choicer_fit' recovery_table(object, truth = NULL, level = 0.95, ...) ## S3 method for class 'choicer_mnp' recovery_table(object, truth = NULL, level = 0.95, ...) ## S3 method for class 'choicer_mc' recovery_table(object, truth = NULL, level = 0.95, ...) ## S3 method for class 'choicer_hb' recovery_table(object, truth = NULL, level = 0.95, ...)recovery_table(object, truth = NULL, level = 0.95, ...) ## S3 method for class 'choicer_fit' recovery_table(object, truth = NULL, level = 0.95, ...) ## S3 method for class 'choicer_mnp' recovery_table(object, truth = NULL, level = 0.95, ...) ## S3 method for class 'choicer_mc' recovery_table(object, truth = NULL, level = 0.95, ...) ## S3 method for class 'choicer_hb' recovery_table(object, truth = NULL, level = 0.95, ...)
object |
A |
truth |
Either a |
level |
Confidence level for the Wald CI and coverage indicator.
Default |
... |
Unused. |
For MXL fits the sigma block compares the raw Cholesky parameters
(L_params), not the reconstructed covariance matrix. For log-normal
random-coefficient means the raw mu estimate is compared directly; callers
who want recovery on the DGP scale (exp(mu)) should transform both sides
before calling.
When the estimator has normalized the first inside alternative's ASC to
zero (which happens for MNL/MXL with include_outside_option = FALSE and
no outside option baked into the fit), the first entry of truth$delta is
dropped before the comparison so lengths match.
See class-specific methods.
recovery_table(choicer_fit): Returns a choicer_recovery object (a
data.table) with columns parameter, group, true, estimate,
se, bias, rel_bias_pct, z_vs_true, lower_ci, upper_ci,
covers.
recovery_table(choicer_mnp): Method for Bayesian MNP fits (choicer_mnp).
The estimate column holds posterior means of the identified draws and
se holds their posterior standard deviations, so lower_ci /
upper_ci are normal-approximation credible intervals. In addition to
the beta and asc blocks, a sigma block compares the identified
covariance of the utility differences (lower triangle in the
estimator's row-major Sigma_ij order); its first row is the
sigma_11 = 1 normalization and is exact by construction. truth must
be on the identified scale, as returned by simulate_mnp_data().
recovery_table(choicer_mc): For a choicer_mc object, delegates to
summary(object, level) and returns a choicer_mc_summary. Inspect
object$replications directly for per-rep detail.
recovery_table(choicer_hb): Method for hierarchical Bayes fits
(choicer_hmnl / choicer_hmnp). estimate holds posterior means and
se posterior standard deviations, so lower_ci / upper_ci are
normal-approximation credible intervals. Blocks: beta (population
means b vs truth$beta), w (diag(W) vs diag(truth$W)), theta
(delta mean function), sigma_d (the SD, compared through the sqrt of
the sigma_d^2 draws), and delta (per-alternative effects vs the
realized truth$delta). For an HMNP fit, truth must be on the
identified scale, as returned by simulate_hmnp_data().
sim <- simulate_mnl_data(N = 2000, J = 4, seed = 123) fit <- run_mnlogit( data = sim$data, id_col = "id", alt_col = "alt", choice_col = "choice", covariate_cols = c("x1", "x2"), outside_opt_label = 0L, include_outside_option = FALSE, use_asc = TRUE ) recovery_table(fit, sim)sim <- simulate_mnl_data(N = 2000, J = 4, seed = 123) fit <- run_mnlogit( data = sim$data, id_col = "id", alt_col = "alt", choice_col = "choice", covariate_cols = c("x1", "x2"), outside_opt_label = 0L, include_outside_option = FALSE, use_asc = TRUE ) recovery_table(fit, sim)
convergence diagnosticComputes the split- (potential scale reduction factor) of
Gelman et al. for each column of a matrix of posterior draws. Every chain
is split in half, so the diagnostic detects non-stationarity within a
single chain as well as disagreement across chains; values near 1 indicate
convergence, and values above roughly 1.05 warrant a longer run.
rhat(draws, rank = FALSE)rhat(draws, rank = FALSE)
draws |
A matrix of posterior draws (rows = iterations, columns = parameters) for a single chain, or a list of such matrices (one per chain, identical dimensions). |
rank |
Logical; if |
Named numeric vector with one per parameter
(NA for parameters with zero variance).
set.seed(42) draws <- matrix(rnorm(2000), ncol = 2, dimnames = list(NULL, c("a", "b"))) rhat(draws) # ~1: white noise is stationary drifting <- cbind(a = cumsum(rnorm(1000))) rhat(drifting) # >> 1: a random walk is not rhat(draws, rank = TRUE) # rank-normalized variantset.seed(42) draws <- matrix(rnorm(2000), ncol = 2, dimnames = list(NULL, c("a", "b"))) rhat(draws) # ~1: white noise is stationary drifting <- cbind(a = cumsum(rnorm(1000))) rhat(drifting) # >> 1: a random walk is not rhat(draws, rank = TRUE) # rank-normalized variant
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:
with i.i.d. Gumbel shocks (including on the implicit outside option, whose
systematic utility is 0), over the structural
covariates ( or per
rc_dist), and ,
. Partial pooling shrinks each
toward its characteristics-based mean ;
the outside option anchors the level of (mean utility
relative to the outside good), so no base alternative or sum-to-zero
constraint is needed.
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 )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 )
data |
Data frame (convenience pathway). Supply either |
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. |
alt_covariate_cols |
Names of alternative-level covariate columns
(constant within each alternative) forming the |
outside_opt_label |
Label of physical outside-option rows, removed
when |
cf_residual_col |
Name of a first-stage residual column (control
function for an endogenous covariate), appended to |
input_data |
A |
include_outside_option |
Logical; if |
rc_dist |
Integer vector, one entry per column of |
prior |
Named list overriding prior defaults: |
mcmc |
Named list overriding MCMC defaults: |
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 |
keep_beta_i |
|
keep_data |
Logical; keep the prepared data on the fit (default
|
Initialization. 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); starts at shrunk log choice-share contrasts against
the outside option; at the OLS regression of the initial
on Z.
Priors. , ,
, and
half-Cauchy via the Makalic-Schmidt
scale mixture (set sd_prior$half_cauchy = FALSE for a plain
on ).
Endogeneity. If a price-like covariate is endogenous (correlated
with ), 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".
A choicer_hmnl object (classed c("choicer_hmnl", "choicer_hb")) with posterior summaries (coefficients, se,
vcov for ; 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.
No column the model uses (the id, alternative, choice, covariate, weight,
cluster, nest or decision-maker column) may have a name starting with
.choicer_, which choicer reserves for its working columns, and the
alternative column may not be named alt_int, N_OBS, N_CHOICES,
TAKE_RATE or MKT_SHARE, the names of the other columns of
alt_mapping. Either is an error that names the column. Columns the model
does not use may have any name.
prepare_hmnl_data(), simulate_hmnl_data(),
recovery_table(), rhat(), ess(), mcse(), traceplot()
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")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")
Runs the fully conjugate Albert-Chib Gibbs sampler for the hierarchical multinomial probit with iid normal utility shocks in un-differenced utility space:
choice by argmax within the task including the stochastic implicit
outside option, (normal coordinates only —
log-normal would break conjugacy), and
, .
run_hmnprobit( 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, prior = list(), mcmc = list(), chains = 1, keep_beta_i = c("means", "draws", "none"), keep_data = TRUE )run_hmnprobit( 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, prior = list(), mcmc = list(), chains = 1, keep_beta_i = c("means", "draws", "none"), keep_data = TRUE )
data |
Data frame (convenience pathway). Supply either |
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. |
alt_covariate_cols |
Names of alternative-level covariate columns
(constant within each alternative) forming the |
outside_opt_label |
Label of physical outside-option rows, removed
when |
cf_residual_col |
Name of a first-stage residual column (control
function for an endogenous covariate), appended to |
input_data |
A |
include_outside_option |
Logical; if |
prior |
As in |
mcmc |
Named list overriding MCMC defaults: |
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 |
keep_beta_i |
|
keep_data |
Logical; keep the prepared data on the fit (default
|
Identification. The probit likelihood is invariant to a common
rescaling of utilities and , so the chain runs on the
non-identified parameterization (free , better mixing via
parameter expansion) and every kept draw is normalized by the matching
power of the CURRENT : reported ,
, , ,
. Raw chains are kept in draws$*_raw. The
outside option anchors the location of exactly as in
run_hmnlogit().
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".
A choicer_hmnp object (classed c("choicer_hmnp", "choicer_hb")); the same layout as run_hmnlogit()'s return, with all
reported summaries on the identified scale, raw chains in
draws$*_raw, the non-identified draws$sigma2 trace, and all chains'
retained draws (identified scale) in chains.
No column the model uses (the id, alternative, choice, covariate, weight,
cluster, nest or decision-maker column) may have a name starting with
.choicer_, which choicer reserves for its working columns, and the
alternative column may not be named alt_int, N_OBS, N_CHOICES,
TAKE_RATE or MKT_SHARE, the names of the other columns of
alt_mapping. Either is an error that names the column. Columns the model
does not use may have any name.
prepare_hmnp_data(), simulate_hmnp_data(), run_hmnlogit(),
ess(), mcse(), traceplot()
sim <- simulate_hmnp_data(N = 100, T = 3, J = 4, seed = 42) fit <- suppressWarnings(run_hmnprobit(sim$data, "task", "alt", "choice", c("x1", "x2"), person_col = "pid", alt_covariate_cols = "z1", mcmc = list(R = 500, burn = 200))) summary(fit)sim <- simulate_hmnp_data(N = 100, T = 3, J = 4, seed = 42) fit <- suppressWarnings(run_hmnprobit(sim$data, "task", "alt", "choice", c("x1", "x2"), person_col = "pid", alt_covariate_cols = "z1", mcmc = list(R = 500, burn = 200))) summary(fit)
Estimates a multinomial logit model via maximum likelihood.
run_mnlogit( data = NULL, id_col = NULL, alt_col = NULL, choice_col = NULL, covariate_cols = NULL, input_data = NULL, optimizer = NULL, control = list(), weights = NULL, weights_col = NULL, outside_opt_label = NULL, include_outside_option = FALSE, use_asc = TRUE, keep_data = TRUE, scale_vars = c("bhhh", "none", "sd", "mad", "iqr"), se_method = c("hessian", "bhhh", "sandwich", "cluster"), cluster_col = NULL, nloptr_opts = NULL )run_mnlogit( data = NULL, id_col = NULL, alt_col = NULL, choice_col = NULL, covariate_cols = NULL, input_data = NULL, optimizer = NULL, control = list(), weights = NULL, weights_col = NULL, outside_opt_label = NULL, include_outside_option = FALSE, use_asc = TRUE, keep_data = TRUE, scale_vars = c("bhhh", "none", "sd", "mad", "iqr"), se_method = c("hessian", "bhhh", "sandwich", "cluster"), cluster_col = NULL, nloptr_opts = NULL )
data |
Data frame containing choice data (convenience workflow).
Mutually exclusive with |
id_col |
Name of the column identifying choice situations (individuals). |
alt_col |
Name of the column identifying alternatives. |
choice_col |
Name of the column indicating chosen alternative (1 = chosen, 0 = not chosen). |
covariate_cols |
Vector of names of columns to be used as covariates.
With |
input_data |
List output from |
optimizer |
Optimizer to use: |
control |
List of optimizer-specific control parameters passed to the
chosen optimizer (e.g., |
weights |
Optional vector of weights for each choice situation. If |
weights_col |
Optional name of a column in |
outside_opt_label |
The label of the outside option or of the base
alternative, given in the class of the alternative column. With
|
include_outside_option |
Logical indicating whether to include an outside option in the model. |
use_asc |
Logical indicating whether to include alternative-specific
constants (ASCs) in the model. An alternative's constant has no finite
maximum-likelihood estimate when the alternative is never chosen in the
data, or is chosen in every choice situation that offers it (the
likelihood keeps rising as the constant falls, or grows); when the
outside option or the base alternative is never chosen, or chosen
wherever it is offered, the other constants have none together. The fit
then warns (class |
keep_data |
Logical. If |
scale_vars |
How the optimizer's coordinates are scaled. The choice
does not change the estimator; it changes how fast, and whether, the
optimizer reaches the maximum. |
se_method |
Method for computing standard errors: |
cluster_col |
Optional name of a column in |
nloptr_opts |
Deprecated. Use |
Two workflows are supported:
Supply data and column names. Data
preparation (prepare_mnl_data) is handled automatically.
Call prepare_mnl_data yourself and pass the
result via input_data.
A choicer_mnl object (inherits from choicer_fit).
Standard S3 methods available: summary(), coef(), vcov(),
logLik(), AIC(), BIC(), nobs(), predict().
The variance is computed once the optimizer has stopped. If that step
fails with an error (an allocation in R, say), the fit returns its
estimates without it (vcov NULL, NA standard
errors, the error's message in variance_error) and warns, naming
the vcov(fit, type = ) that computes the variance later from a
fit that keeps its data (keep_data = TRUE). An allocation that
fails inside the compiled Hessian or BHHH loops still terminates R.
No column the model uses (the id, alternative, choice, covariate, weight,
cluster, nest or decision-maker column) may have a name starting with
.choicer_, which choicer reserves for its working columns, and the
alternative column may not be named alt_int, N_OBS, N_CHOICES,
TAKE_RATE or MKT_SHARE, the names of the other columns of
alt_mapping. Either is an error that names the column. Columns the model
does not use may have any name.
library(data.table) set.seed(42) N <- 100; J <- 3; beta_true <- c(1.0, -0.5) dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, V := drop(as.matrix(.SD) %*% beta_true), .SDcols = c("x1","x2")] dt[, prob := exp(V) / sum(exp(V)), by = id] dt[, choice := as.integer(alt == sample(alt, 1, prob = prob)), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) summary(fit) coef(fit) AIC(fit) predict(fit, type = "shares")library(data.table) set.seed(42) N <- 100; J <- 3; beta_true <- c(1.0, -0.5) dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, V := drop(as.matrix(.SD) %*% beta_true), .SDcols = c("x1","x2")] dt[, prob := exp(V) / sum(exp(V)), by = id] dt[, choice := as.integer(alt == sample(alt, 1, prob = prob)), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) summary(fit) coef(fit) AIC(fit) predict(fit, type = "shares")
Estimates a multinomial probit model by Gibbs sampling with data
augmentation (Albert & Chib 1993; McCulloch & Rossi 1994). The model is
specified in utility differences against a base alternative: for choice
situation with alternatives, with .
run_mnprobit( data = NULL, id_col = NULL, alt_col = NULL, choice_col = NULL, covariate_cols = NULL, input_data = NULL, base_alt = NULL, use_asc = TRUE, prior = list(), mcmc = list(), keep_data = TRUE )run_mnprobit( data = NULL, id_col = NULL, alt_col = NULL, choice_col = NULL, covariate_cols = NULL, input_data = NULL, base_alt = NULL, use_asc = TRUE, prior = list(), mcmc = list(), keep_data = TRUE )
data |
Data frame containing choice data (convenience workflow).
Mutually exclusive with |
id_col |
Name of the column identifying choice situations (individuals). |
alt_col |
Name of the column identifying alternatives. |
choice_col |
Name of the column indicating chosen alternative (1 = chosen, 0 = not chosen). |
covariate_cols |
Vector of names of columns to be used as covariates. |
input_data |
List output from |
base_alt |
Label of the base (reference) alternative used for utility
differencing. If |
use_asc |
Logical indicating whether to include alternative-specific
constants (one intercept per non-base alternative in the differenced
utilities), named |
prior |
Named list of prior settings, merged over defaults:
|
mcmc |
Named list of MCMC settings, merged over defaults:
|
keep_data |
Logical. If |
Two workflows are supported:
Supply data and column names. Data
preparation (prepare_mnp_data) is handled automatically.
Call prepare_mnp_data yourself and pass the
result via input_data.
Identification. The multinomial probit likelihood is invariant to
a common rescaling . The
sampler runs on the non-identified parameterization (unrestricted
with an inverse-Wishart prior) and identified quantities are
computed by normalizing each kept draw by :
and . This is
the McCulloch & Rossi (1994) default, which keeps all Gibbs conditionals
conjugate and mixes better than the fully identified sampler of McCulloch,
Polson & Rossi (2000). Reported coefficients, standard deviations, and
credible intervals are posterior summaries of the identified draws.
Reproducibility. The sampler uses its own thread-safe RNG with
one stream per (iteration, observation), so results are reproducible
independent of the number of OpenMP threads (see
set_num_threads()). When mcmc$seed is not supplied, a
master seed is drawn from R's RNG, so set.seed() controls the run.
Scope. Balanced choice sets are required: every choice situation
must contain the same alternatives. To model an outside option,
include it as explicit rows with zero covariates and set base_alt
to its label.
A choicer_mnp object. S3 methods available:
summary(), coef() (posterior means of identified
coefficients), vcov() (posterior covariance of identified
coefficient draws), nobs(). Posterior draws are stored in
$draws (beta / sigma on the identified scale,
beta_raw / sigma_raw unnormalized).
No column the model uses (the id, alternative, choice, covariate, weight,
cluster, nest or decision-maker column) may have a name starting with
.choicer_, which choicer reserves for its working columns, and the
alternative column may not be named alt_int, N_OBS, N_CHOICES,
TAKE_RATE or MKT_SHARE, the names of the other columns of
alt_mapping. Either is an error that names the column. Columns the model
does not use may have any name.
Albert, J. H., & Chib, S. (1993). Bayesian Analysis of Binary and Polychotomous Response Data. Journal of the American Statistical Association, 88(422), 669-679.
McCulloch, R., & Rossi, P. E. (1994). An exact likelihood analysis of the multinomial probit model. Journal of Econometrics, 64(1-2), 207-240.
library(data.table) set.seed(42) N <- 200; J <- 3; beta_true <- c(1.0, -0.5) dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, U := drop(as.matrix(.SD) %*% beta_true) + rnorm(.N), .SDcols = c("x1", "x2")] dt[, choice := as.integer(U == max(U)), by = id] fit <- run_mnprobit(dt, "id", "alt", "choice", c("x1", "x2"), mcmc = list(R = 500, burn = 100)) summary(fit) coef(fit)library(data.table) set.seed(42) N <- 200; J <- 3; beta_true <- c(1.0, -0.5) dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, U := drop(as.matrix(.SD) %*% beta_true) + rnorm(.N), .SDcols = c("x1", "x2")] dt[, choice := as.integer(U == max(U)), by = id] fit <- run_mnprobit(dt, "id", "alt", "choice", c("x1", "x2"), mcmc = list(R = 500, burn = 100)) summary(fit) coef(fit)
Estimates a mixed logit model via simulated maximum likelihood.
run_mxlogit( data = NULL, id_col = NULL, alt_col = NULL, choice_col = NULL, covariate_cols = NULL, random_var_cols = NULL, input_data = NULL, eta_draws = NULL, S = 100L, rc_dist = NULL, rc_mean = FALSE, rc_correlation = FALSE, use_asc = TRUE, theta_init = NULL, lower = NULL, upper = NULL, optimizer = NULL, control = list(), se_method = c("hessian", "bhhh", "sandwich", "cluster"), scale_vars = c("bhhh", "none", "sd", "mad", "iqr"), weights = NULL, outside_opt_label = NULL, include_outside_option = FALSE, draws = c("store", "generate"), seed = NULL, scramble = c("permuted", "none", "owen"), keep_data = TRUE, nloptr_opts = NULL, weights_col = NULL, cluster_col = NULL, person_col = NULL, polish = c("none", "newton", "bhhh"), polish_control = list() )run_mxlogit( data = NULL, id_col = NULL, alt_col = NULL, choice_col = NULL, covariate_cols = NULL, random_var_cols = NULL, input_data = NULL, eta_draws = NULL, S = 100L, rc_dist = NULL, rc_mean = FALSE, rc_correlation = FALSE, use_asc = TRUE, theta_init = NULL, lower = NULL, upper = NULL, optimizer = NULL, control = list(), se_method = c("hessian", "bhhh", "sandwich", "cluster"), scale_vars = c("bhhh", "none", "sd", "mad", "iqr"), weights = NULL, outside_opt_label = NULL, include_outside_option = FALSE, draws = c("store", "generate"), seed = NULL, scramble = c("permuted", "none", "owen"), keep_data = TRUE, nloptr_opts = NULL, weights_col = NULL, cluster_col = NULL, person_col = NULL, polish = c("none", "newton", "bhhh"), polish_control = list() )
data |
Data frame containing choice data (convenience workflow).
Mutually exclusive with |
id_col |
Name of the column identifying choice situations. |
alt_col |
Name of the column identifying alternatives. |
choice_col |
Name of the column indicating chosen alternative (1/0). |
covariate_cols |
Vector of column names for fixed covariates. None
may take a name the model gives its parameters, or prints for them in
|
random_var_cols |
Vector of column names for random coefficients. |
input_data |
List output from |
eta_draws |
Array of shape K_w x S x U with standard normal draws, one
K_w x S block per likelihood unit: U is the number of decision makers
when |
S |
Integer number of Halton draws per decision maker, or per choice
situation without |
rc_dist |
Integer vector indicating distribution of random coefficients (0 = normal, 1 = log-normal). Default: all normal. |
rc_mean |
Logical indicating whether to estimate means for random coefficients. |
rc_correlation |
Logical indicating whether random coefficients are
correlated (convenience workflow). Ignored when |
use_asc |
Logical indicating whether to include alternative-specific
constants: one per inside alternative with the outside option, otherwise
one per alternative but the first ( |
theta_init |
Initial parameter vector in natural-scale units. If
|
lower, upper
|
Optional parameter bounds for the optimizer, in
natural-scale units (mapped to the optimizer's coordinates when
|
optimizer |
Optimizer to use: |
control |
List of optimizer-specific control parameters. With
|
se_method |
Method for computing standard errors. One of
|
scale_vars |
How the optimizer's coordinates are scaled. The choice
does not change the estimator; it changes how fast, and whether, the
optimizer reaches the maximum. |
weights |
Optional weight vector (convenience workflow), one weight per
choice situation in ascending-id order (see
|
outside_opt_label |
(Convenience workflow.) The label of the outside
option or of the base alternative, given in the class of the alternative
column. With |
include_outside_option |
Logical whether to include an outside option (convenience workflow). |
draws |
Draw storage mode. One of |
seed |
Integer master seed for the on-the-fly generator. Used only when
|
scramble |
Scrambling mode for on-the-fly Halton draws. One of
|
keep_data |
Logical. If |
nloptr_opts |
Deprecated. Use |
weights_col |
Optional name of a column in |
cluster_col |
Optional name of a column in |
person_col |
Optional name of the column in |
polish |
A Newton phase after the optimizer (see the section
below): |
polish_control |
List of settings of the Newton phase, any of
|
Two workflows are supported:
Supply data and column names. Data preparation
(prepare_mxl_data) and Halton draw generation
(get_halton_normals) are handled automatically.
Call prepare_mxl_data and
get_halton_normals yourself, then pass the results via
input_data and eta_draws.
Cross-section vs panel. With person_col, each decision
maker draws one taste vector from the mixing
distribution and keeps it in all of their choice
situations . The likelihood integrates the product
of their conditional logit probabilities (Revelt and Train 1998),
simulated with S draws per decision maker, so repeated choices
speak to each decision maker's tastes, and
conditional_tastes recovers what they reveal. Without
person_col (the default), each choice situation is an independent
draw from the mixing distribution: . That is the right model when tastes
are redrawn in every situation (or each decision maker chooses once). On
panel data with stable tastes it is a composite (pseudo-) likelihood: it
still targets the population mixing distribution, but it ignores the
within-person correlation of choices, so it is less efficient, its
standard errors must be clustered by decision maker (cluster_col),
and its log-likelihood, AIC and BIC are not comparable with those of the
panel fit.
A choicer_mxl object (inherits from choicer_fit).
Standard S3 methods available: summary(), coef(),
vcov(), logLik(), AIC(), BIC(),
nobs(). A panel fit (person_col) also carries
n_persons, the number of decision makers; nobs() remains
the number of choice situations, which is also the in BIC's
penalty. The variance is computed once the optimizer has
stopped. If that step fails with an error (the kernels' memory check,
see set_num_threads, say), the fit returns its estimates
without it (vcov NULL, NA standard errors, the
error's message in variance_error) and warns, naming the
vcov(fit, type = ) that computes the variance later from a fit
that keeps its data (keep_data = TRUE); the memory check's message
names the threads that fit or how to lift its limit. With polish,
fit$optimizer$polish records the Newton phase: method,
converged, iterations (steps taken) and damped,
decrement (NA where the curvature on the parameters moved
was not positive definite) and lambda (its damping) at the last
curvature evaluated, message (why it stopped),
evaluations (of the objective and the curvature), active,
held and flat (the parameters on a bound, held, and left
out of the last steps for want of usable curvature), improvement
(the log-likelihood gained), error, elapsed_time (the
polish's seconds, which fit$optimizer$elapsed_time includes), and
optimizer, the optimizer's own convergence,
message, iterations and elapsed_time. A converged
polish sets convergence to the optimizer's success code (1 for
nloptr, 0 for optim and a custom optimizer) and leads message
with its verdict; otherwise both keep the optimizer's, the polish's
reason appended to the message. A polish that stops with an error (the
Hessian's memory check, say) keeps its last accepted point and warns
(class choicer_polish_failed).
The polish does not change the estimator. From wherever the optimizer
stopped (at its tolerance or at maxeval), it finishes the climb to
the maximum the optimizer approached, which first-order methods such as
L-BFGS reach slowly when curvatures differ by orders of magnitude
(thousands of constants, say), and certifies it. It converges when the
Newton decrement
, with
the gradient and the curvature on the parameters it moves, falls
below tol_decrement. On a positive definite Hessian,
is the distance from the estimates to the
maximum of the log-likelihood's quadratic model in Hessian standard
errors: at the default , every linear combination of
the estimates lies within of its standard
error of that maximum. BHHH is positive semi-definite everywhere and
cheaper per step, but converges linearly; where the Hessian is
positive definite, its is that distance in
the standard errors of the sandwich
(the robust standard errors of an unweighted fit), but on its own it shows
a stationary point, not a maximum. "bhhh" needs at least as many
likelihood units as the parameters it moves.
Where the curvature is not positive definite the steps are damped
(Levenberg-Marquardt); they respect lower/upper and pass a
line search. The constants of inside alternatives without a finite
estimate (see use_asc) are held at the optimizer's values, and the
certificate concerns the other parameters given them. Where the base
alternative or the outside option is the one without, the other constants
diverge together, and the polish does not report convergence, unless the
reference is never chosen and the constant of an alternative that is
chosen is held or bounded above, which stops them. A random coefficient
whose variance's maximum is at zero drives its log-Cholesky diagonal
toward by Newton steps of to 1, each
shrinking the decrement by a factor of about : "newton" may
certify a point where the variance is negligible but that diagonal, and
its standard error, depend on tol_decrement; "bhhh", whose
curvature in that direction vanishes faster, comes to hold the diagonal
and stops unconverged. A parameter without usable curvature (no
information at the point, or a curvature that has all but vanished, giving
a step more than 100 times its scale in the optimizer's coordinates) is
held for the step and stops the polish unconverged. Under
scale_vars = "none" those scales are the parameters' natural units,
so a badly scaled column far from its maximum can be held as if its
curvature had vanished; the default "bhhh" scaling avoids this. The
standard errors are computed at the polished estimates, by
se_method.
Each step costs a curvature evaluation and a line search. A smaller
maxeval (nloptr) or maxit (optim) in control hands
the polish a point sooner, which saves time where the optimizer's last
iterations creep; from farther away the steps are shortened (and damped
where the curvature is not positive definite), and more of them are
needed.
No column the model uses (the id, alternative, choice, covariate, weight,
cluster, nest or decision-maker column) may have a name starting with
.choicer_, which choicer reserves for its working columns, and the
alternative column may not be named alt_int, N_OBS, N_CHOICES,
TAKE_RATE or MKT_SHARE, the names of the other columns of
alt_mapping. Either is an error that names the column. Columns the model
does not use may have any name.
Revelt, D. and Train, K. (1998). Mixed logit with repeated choices: households' choices of appliance efficiency level. Review of Economics and Statistics 80(4), 647-657.
conditional_tastes, run_hmnlogit (the
hierarchical Bayes counterpart)
library(data.table) set.seed(42) N <- 100; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), w1 = rnorm(.N), w2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mxlogit( data = dt, id_col = "id", alt_col = "alt", choice_col = "choice", covariate_cols = "x1", random_var_cols = c("w1", "w2"), S = 50L ) summary(fit)library(data.table) set.seed(42) N <- 100; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), w1 = rnorm(.N), w2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mxlogit( data = dt, id_col = "id", alt_col = "alt", choice_col = "choice", covariate_cols = "x1", random_var_cols = c("w1", "w2"), S = 50L ) summary(fit)
Estimates a nested logit model via maximum likelihood.
run_nestlogit( data = NULL, id_col = NULL, alt_col = NULL, choice_col = NULL, covariate_cols = NULL, nest_col = NULL, input_data = NULL, use_asc = TRUE, theta_init = NULL, param_names = NULL, optimizer = NULL, control = list(), weights = NULL, weights_col = NULL, outside_opt_label = NULL, include_outside_option = FALSE, keep_data = TRUE, se_method = c("hessian", "numeric", "bhhh", "sandwich", "cluster"), cluster_col = NULL, nloptr_opts = NULL, scale_vars = c("none", "sd", "mad", "iqr", "bhhh") )run_nestlogit( data = NULL, id_col = NULL, alt_col = NULL, choice_col = NULL, covariate_cols = NULL, nest_col = NULL, input_data = NULL, use_asc = TRUE, theta_init = NULL, param_names = NULL, optimizer = NULL, control = list(), weights = NULL, weights_col = NULL, outside_opt_label = NULL, include_outside_option = FALSE, keep_data = TRUE, se_method = c("hessian", "numeric", "bhhh", "sandwich", "cluster"), cluster_col = NULL, nloptr_opts = NULL, scale_vars = c("none", "sd", "mad", "iqr", "bhhh") )
data |
Data frame containing choice data (convenience workflow).
Mutually exclusive with |
id_col |
Name of the column identifying choice situations. |
alt_col |
Name of the column identifying alternatives. |
choice_col |
Name of the column indicating chosen alternative (1/0). |
covariate_cols |
Vector of column names for covariates. None may be
named like a generated parameter: |
nest_col |
Name of the column mapping each alternative to its nest (convenience workflow). |
input_data |
List containing prepared input data for estimation
(advanced workflow). Mutually exclusive with |
use_asc |
Logical indicating whether to include alternative specific
constants (ASCs). An alternative's constant has no finite
maximum-likelihood estimate when the alternative is chosen in every
choice situation that offers it, or is never chosen in the data (the
likelihood keeps rising as the constant grows, or falls); when the
outside option or the base alternative is chosen wherever it is offered,
or never chosen, the other constants have none together. For a
never-chosen alternative, the base included, this holds while the
parameter of its nest is at most 1. The fit then warns (class
|
theta_init |
Optional initial parameter vector in natural units,
ordered as the coefficients, the nest parameters ( |
param_names |
Optional vector of parameter names, which must be
unique. If |
optimizer |
Optimizer to use: |
control |
List of optimizer-specific control parameters. With
|
weights |
Optional weight vector (convenience workflow). If |
weights_col |
Optional name of a column in |
outside_opt_label |
(Convenience workflow.) The label of the outside
option or of the base alternative, given in the class of the alternative
column. With |
include_outside_option |
Logical whether to include an outside option (convenience workflow). |
keep_data |
Logical. If |
se_method |
Method for computing standard errors: |
cluster_col |
Optional name of a column in |
nloptr_opts |
Deprecated. Use |
scale_vars |
How the optimizer's coordinates are scaled. The choice
does not change the estimator; it changes how fast, and whether, the
optimizer reaches the maximum. One of |
Two workflows are supported:
Supply data and column names (including
nest_col). Data preparation (prepare_nl_data) is
handled automatically.
Call prepare_nl_data (or build the input
list manually) and pass it via input_data.
A choicer_nl object (inherits from choicer_fit).
Standard S3 methods available: summary(), coef(),
vcov(), logLik(), AIC(), BIC(),
nobs(). The variance is computed once the optimizer has stopped.
If that step fails with an error (an allocation in R, say), the fit
returns its estimates without it (vcov NULL, NA
standard errors, the error's message in variance_error) and warns,
naming the vcov(fit, type = ) that computes the variance later
from a fit that keeps its data (keep_data = TRUE). An allocation
that fails inside the compiled Hessian or BHHH loops still terminates R.
No column the model uses (the id, alternative, choice, covariate, weight,
cluster, nest or decision-maker column) may have a name starting with
.choicer_, which choicer reserves for its working columns, and the
alternative column may not be named alt_int, N_OBS, N_CHOICES,
TAKE_RATE or MKT_SHARE, the names of the other columns of
alt_mapping. Either is an error that names the column. Columns the model
does not use may have any name.
library(data.table) set.seed(42) N <- 100; J <- 4 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, nest := ifelse(alt <= 2, "A", "B")] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_nestlogit( data = dt, id_col = "id", alt_col = "alt", choice_col = "choice", covariate_cols = c("x1", "x2"), nest_col = "nest" ) summary(fit)library(data.table) set.seed(42) N <- 100; J <- 4 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, nest := ifelse(alt <= 2, "A", "B")] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_nestlogit( data = dt, id_col = "id", alt_col = "alt", choice_col = "choice", covariate_cols = c("x1", "x2"), nest_col = "nest" ) summary(fit)
Subsamples whole choice situations from a population data set according to
fixed per-stratum quotas, where strata are defined by the chosen
alternative. The input data set is treated as the population, so the
population shares are known exactly; the returned sample carries a
ready-to-use WESML weight column (see wesml_weights).
sample_by_choice( data, id_col, alt_col, choice_col, n_per_alt = NULL, frac_per_alt = NULL, seed = NULL, weight_name = ".wesml_weight", outside_opt_label = NULL, include_outside_option = FALSE )sample_by_choice( data, id_col, alt_col, choice_col, n_per_alt = NULL, frac_per_alt = NULL, seed = NULL, weight_name = ".wesml_weight", outside_opt_label = NULL, include_outside_option = FALSE )
data, id_col, alt_col, choice_col
|
As in |
n_per_alt |
Either a single integer applied to every stratum, or a named
integer vector of per-stratum counts (names matched to
|
frac_per_alt |
Either a single fraction in |
seed |
Optional integer seed for reproducible sampling. |
weight_name |
Name of the attached weight column (default
|
outside_opt_label, include_outside_option
|
As in
|
Sampling is by choice situation (id), never by row: all alternative-rows of a sampled situation are kept together. Sampling is without replacement.
A data.table subsample with the weight column appended and
"Q", "H", and "choice_sampling" attributes (the last
records the scheme, shares, quotas, and meat = "robust").
Manski, C. F. and Lerman, S. R. (1977). Econometrica 45(8), 1977-1988.
library(data.table) set.seed(1) N <- 600L; J <- 3L pop <- data.table(id = rep(seq_len(N), each = J), alt = rep(1:J, N)) pop[, x1 := rnorm(.N)] pop[, w1 := rnorm(.N)] pop[, choice := as.integer(seq_len(.N) == sample.int(.N, 1L)), by = id] s <- sample_by_choice(pop, "id", "alt", "choice", n_per_alt = 50L, seed = 1L) attr(s, "choice_sampling")$H # realized sample shares head(s[[".wesml_weight"]])library(data.table) set.seed(1) N <- 600L; J <- 3L pop <- data.table(id = rep(seq_len(N), each = J), alt = rep(1:J, N)) pop[, x1 := rnorm(.N)] pop[, w1 := rnorm(.N)] pop[, choice := as.integer(seq_len(.N) == sample.int(.N, 1L)), by = id] s <- sample_by_choice(pop, "id", "alt", "choice", n_per_alt = 50L, seed = 1L) attr(s, "choice_sampling")$H # realized sample shares head(s[[".wesml_weight"]])
Set the number of OpenMP threads used by choicer
set_num_threads(n_threads)set_num_threads(n_threads)
n_threads |
Positive integer number of threads. |
The setting applies to every choicer kernel run afterwards in the
session (it calls omp_set_num_threads()); thread_info() reports it.
Each thread of the mixed logit's compiled routines (behind the
log-likelihood and its gradient, the Hessian, the BHHH matrix, the robust
and clustered meats and the conditional tastes) needs its own working
memory, besides what they share. Before allocating it, they compare an
upper estimate of the call's total with the machine's total physical
memory and, when it would not fit, stop with an error that gives the
number of threads that fits; they do not lower the thread count to make
it fit. Memory already in use (the data, store-mode draws, other
processes) is not counted, nor is the inversion in R of the resulting
matrices, so passing the check does not promise that the call fits;
where the physical memory cannot be read and the option is unset, there
is no check.
options(choicer.max_memory = <bytes>) sets the limit instead, for a
container or a cluster job with less memory than the machine, and Inf
lifts the check.
Invisibly returns NULL.
Generates synthetic panel choice data from the hierarchical (random
coefficients + alternative-level random effects) logit DGP: respondents
i = 1..N face T choice situations each, with utilities
i.i.d. Gumbel shocks (including a shock on the outside option, whose
systematic utility is 0), with
or per rc_dist,
and with
. Covariates are Uniform(-1, 1); the
alternative-level covariates z* are constant within each alternative.
simulate_hmnl_data( N = 500, T = 10, J = 4, beta = c(0.8, -0.6), W = NULL, theta = c(0.5, -0.4), sigma_d = 0.5, Z = NULL, rc_dist = NULL, include_outside = TRUE, seed = 123, vary_choice_set = FALSE )simulate_hmnl_data( N = 500, T = 10, J = 4, beta = c(0.8, -0.6), W = NULL, theta = c(0.5, -0.4), sigma_d = 0.5, Z = NULL, rc_dist = NULL, include_outside = TRUE, seed = 123, vary_choice_set = FALSE )
N |
Number of respondents. |
T |
Number of choice situations per respondent. |
J |
Number of inside alternatives. |
beta |
Population means of the structural random coefficients
(length |
W |
Covariance of the random coefficients ( |
theta |
Mean-function coefficients for
|
sigma_d |
Standard deviation of the alternative-level effects
|
Z |
Optional |
rc_dist |
Integer vector (length |
include_outside |
Logical; if |
seed |
Random seed ( |
vary_choice_set |
Logical; if |
Log-normal coordinates are reported on the chain (log) scale in
true_params$beta — the scale on which the estimator's hierarchy
operates — while entering utility as exp(beta_ik).
A choicer_sim object. true_params contains beta, W,
theta, sigma_d, the realized delta and xi vectors, the full
mean-function design Z (intercept first), and rc_dist.
sim <- simulate_hmnl_data(N = 100, T = 4, J = 4, seed = 123) print(sim) sim$true_params$deltasim <- simulate_hmnl_data(N = 100, T = 4, J = 4, seed = 123) print(sim) sim$true_params$delta
Generates synthetic panel choice data from the hierarchical probit DGP with iid normal utility shocks:
choice by argmax within the task. The outside option is stochastic — it
carries its own shock on top of systematic utility
0, exactly as in the estimator. (normal
only) and ,
, as in simulate_hmnl_data().
simulate_hmnp_data( N = 500, T = 10, J = 4, beta = c(0.8, -0.6), W = NULL, theta = c(0.5, -0.4), sigma_d = 0.5, Z = NULL, include_outside = TRUE, seed = 123, vary_choice_set = FALSE, sigma = 1 )simulate_hmnp_data( N = 500, T = 10, J = 4, beta = c(0.8, -0.6), W = NULL, theta = c(0.5, -0.4), sigma_d = 0.5, Z = NULL, include_outside = TRUE, seed = 123, vary_choice_set = FALSE, sigma = 1 )
N |
Number of respondents. |
T |
Number of choice situations per respondent. |
J |
Number of inside alternatives. |
beta |
Population means of the structural random coefficients
(length |
W |
Covariance of the random coefficients ( |
theta |
Mean-function coefficients for
|
sigma_d |
Standard deviation of the alternative-level effects
|
Z |
Optional |
include_outside |
Logical; if |
seed |
Random seed ( |
vary_choice_set |
Logical; if |
sigma |
Standard deviation of the iid utility shocks (DGP scale). |
The iid-probit likelihood identifies parameters only up to the common
scale , so true_params is reported on the identified
scale: beta , W , theta
, sigma_d , delta
, xi . With the default
sigma = 1 the DGP scale and the identified scale coincide.
A choicer_sim object. true_params contains beta, W,
theta, sigma_d, the realized delta and xi, and the full
mean-function design Z — all on the identified scale (see Details).
sim <- simulate_hmnp_data(N = 100, T = 4, J = 4, seed = 123) print(sim) sim$true_params$deltasim <- simulate_hmnp_data(N = 100, T = 4, J = 4, seed = 123) print(sim) sim$true_params$delta
Generates synthetic choice data with i.i.d. Gumbel errors, optionally with varying choice-set sizes and an outside option (alt = 0). Choices are determined by argmax of utility; covariates are drawn as Uniform(-1, 1).
simulate_mnl_data( N = 5000, J = 5, beta = c(0.8, -0.6), delta = NULL, seed = 123, outside_option = TRUE, vary_choice_set = TRUE )simulate_mnl_data( N = 5000, J = 5, beta = c(0.8, -0.6), delta = NULL, seed = 123, outside_option = TRUE, vary_choice_set = TRUE )
N |
Number of choice situations. |
J |
Number of inside alternatives. |
beta |
Fixed coefficients for |
delta |
Alternative-specific constants for inside alternatives
(length |
seed |
Random seed. Pass |
outside_option |
Logical; if |
vary_choice_set |
Logical; if |
A choicer_sim object.
sim <- simulate_mnl_data(N = 1000, J = 5, seed = 123) print(sim)sim <- simulate_mnl_data(N = 1000, J = 5, seed = 123) print(sim)
Generates synthetic choice data from the MNP data-generating process
estimated by run_mnprobit(): latent utility differences against the base
alternative (alternative 1),
with alternative chosen iff
and the base chosen iff all
. Covariates are Uniform(-1, 1). Choice sets are balanced
(every individual faces all J alternatives), as the MNP estimator
requires; there is no outside-option flag — model an outside good as a
zero-covariate base alternative instead.
simulate_mnp_data( N = 5000, J = 3, beta = c(0.8, -0.6), delta = NULL, Sigma = matrix(c(1, 0.5, 0.5, 1.5), nrow = 2), seed = 123 )simulate_mnp_data( N = 5000, J = 3, beta = c(0.8, -0.6), delta = NULL, Sigma = matrix(c(1, 0.5, 0.5, 1.5), nrow = 2), seed = 123 )
N |
Number of choice situations. |
J |
Number of alternatives (alternative 1 is the base). |
beta |
Fixed coefficients for |
delta |
ASCs of the differenced utilities, one per non-base
alternative (length |
Sigma |
Covariance matrix of the differenced errors
( |
seed |
Random seed ( |
The MNP likelihood only identifies parameters up to scale, so
true_params is reported on the identified scale (normalized by
): beta , delta
, and Sigma — the scale on which run_mnprobit() reports its posterior.
With the default Sigma () the DGP scale and the
identified scale coincide.
A choicer_sim object. true_params contains beta, delta,
and Sigma on the identified scale (see Details).
sim <- simulate_mnp_data(N = 1000, J = 3, seed = 123) print(sim)sim <- simulate_mnp_data(N = 1000, J = 3, seed = 123) print(sim)
Generates synthetic choice data with random coefficients drawn from a
multivariate normal (optionally log-normal per dimension) and an additional
mean shifter mu. Random coefficients are parameterized via the lower
Cholesky factor of Sigma. Covariates are Uniform(-1, 1) by default;
columns named in price_cols are drawn as -Uniform(0.1, 3) to mimic
strictly-negative price variables. With T > 1 the data are a panel:
each of the N decision makers draws one taste vector and keeps it in all
of their T choice situations (the model of run_mxlogit(person_col = )).
simulate_mxl_data( N = 5000, J = 4, beta = c(0.8, -0.6), delta = NULL, mu = NULL, Sigma = matrix(c(1, 0.5, 0.5, 1.5), nrow = 2), rc_dist = NULL, rc_correlation = NULL, price_cols = NULL, seed = 123, outside_option = TRUE, vary_choice_set = TRUE, T = 1L )simulate_mxl_data( N = 5000, J = 4, beta = c(0.8, -0.6), delta = NULL, mu = NULL, Sigma = matrix(c(1, 0.5, 0.5, 1.5), nrow = 2), rc_dist = NULL, rc_correlation = NULL, price_cols = NULL, seed = 123, outside_option = TRUE, vary_choice_set = TRUE, T = 1L )
N |
Number of decision makers; equals the number of choice situations
when |
J |
Number of inside alternatives. |
beta |
Fixed coefficients for |
delta |
ASCs for inside alternatives (length |
mu |
Mean shifter for random coefficients (length |
Sigma |
Covariance matrix of random coefficients (square, |
rc_dist |
Integer vector (length |
rc_correlation |
Logical; if |
price_cols |
Character vector of |
seed |
Random seed ( |
outside_option |
Logical; include outside option with |
vary_choice_set |
Logical; if |
T |
Number of choice situations per decision maker (a single integer
|
Random coefficients are constructed to match the estimator's
parameterization in src/mxlogit.cpp. For every dimension the raw draw
is L %*% eta where eta ~ N(0, I). A normal random coefficient
(rc_dist = 0) is then gamma_k = mu_k + (L %*% eta)_k. A log-normal
random coefficient (rc_dist = 1) follows the shifted log-normal
beta_k = exp(mu_k) + exp((L %*% eta)_k) – not the textbook
exp(mu_k + sigma_k * eta) – so mu_k in true_params$mu is on the
same scale the estimator recovers and recovery_table() can compare
like-for-like.
A choicer_sim object. true_params includes beta, delta,
Sigma, L_params (packed Cholesky parameters), mu, rc_dist,
rc_correlation, and gamma_i: the K_w x N matrix of realized random
coefficients (rows are the w* columns, columns the decision makers), on
the scale they enter utility: the realized tastes, which the conditional
means from conditional_tastes() can be compared with (they track them
with shrinkage). settings records T.
sim <- simulate_mxl_data(N = 1000, J = 4, seed = 123) print(sim) # panel: 200 decision makers x 5 choice situations panel <- simulate_mxl_data(N = 200, T = 5, J = 4, seed = 123) head(panel$data)sim <- simulate_mxl_data(N = 1000, J = 4, seed = 123) print(sim) # panel: 200 decision makers x 5 choice situations panel <- simulate_mxl_data(N = 200, T = 5, J = 4, seed = 123) head(panel$data)
Generates synthetic choice data with nested logit probabilities computed
analytically (log-sum-exp over inclusive values), then samples choices from
the implied multinomial. The outside option (j = 0) sits in a singleton
nest with lambda = 1.
simulate_nl_data( N = 10000, beta = c(1.5, -0.8), delta = c(`1` = 0.5, `2` = 0.3, `3` = -0.2, `4` = -0.5, `5` = 0.4), nests = list(c(1, 2), c(3, 4, 5)), lambdas = c(0.8, 0.2), seed = 123 )simulate_nl_data( N = 10000, beta = c(1.5, -0.8), delta = c(`1` = 0.5, `2` = 0.3, `3` = -0.2, `4` = -0.5, `5` = 0.4), nests = list(c(1, 2), c(3, 4, 5)), lambdas = c(0.8, 0.2), seed = 123 )
N |
Number of choice situations. |
beta |
Fixed coefficients for covariates |
delta |
Named numeric vector of ASCs for inside alternatives. |
nests |
List of integer vectors defining nest membership for inside alternatives. |
lambdas |
Numeric vector of dissimilarity parameters, one per nest. |
seed |
Random seed ( |
A choicer_sim object. true_params includes beta, delta,
lambdas; settings includes the nest_structure. The returned
data retains a nest column (integer, with 0L for the outside
option) for convenient use with run_nestlogit().
Unlike simulate_mnl_data() and simulate_mxl_data(), this
function does not expose outside_option or vary_choice_set flags.
The outside option (j = 0) is always present as a singleton nest with
lambda = 1, and every individual faces the full set of inside
alternatives. Add these flags if downstream use cases need them.
sim <- simulate_nl_data(N = 2000, seed = 123) print(sim)sim <- simulate_nl_data(N = 2000, seed = 123) print(sim)
Posterior summaries (mean, SD, equal-tailed credible interval) for the
population coefficients , the mean-function coefficients
, the alternative-effect variance (and, for
the HMNP, the raw shock variance trace), plus the /
quality ladder, acceptance diagnostics, and a consolidated
convergence-diagnostic table (rank-normalized R-hat, ESS bulk/tail, MCSE)
built from all retained chains (see rhat(), ess(), mcse()).
## S3 method for class 'choicer_hb' summary(object, prob = 0.95, ...)## S3 method for class 'choicer_hb' summary(object, prob = 0.95, ...)
object |
A |
prob |
Probability mass of the equal-tailed credible interval (default 0.95). |
... |
Additional arguments (ignored). |
A summary.choicer_hb object.
sim <- simulate_hmnl_data(N = 50, T = 2, J = 3, seed = 42) fit <- suppressWarnings(run_hmnlogit(sim$data, "task", "alt", "choice", c("x1", "x2"), person_col = "pid", mcmc = list(R = 300, burn = 100))) summary(fit)sim <- simulate_hmnl_data(N = 50, T = 2, J = 3, seed = 42) fit <- suppressWarnings(run_hmnlogit(sim$data, "task", "alt", "choice", c("x1", "x2"), person_col = "pid", mcmc = list(R = 300, burn = 100))) summary(fit)
Computes and returns a coefficient summary table with standard errors, z-values, p-values, and significance codes. Triggers lazy Hessian computation if standard errors have not been computed yet.
## S3 method for class 'choicer_mnl' summary(object, gof = TRUE, ...)## S3 method for class 'choicer_mnl' summary(object, gof = TRUE, ...)
object |
A choicer_mnl object. |
gof |
Logical; compute goodness-of-fit measures (McFadden R-squared, hit rate) for the summary footer. Involves an in-sample prediction pass (for mixed logit, a full simulation over draws); set to FALSE to skip. |
... |
Additional arguments (ignored). |
A summary.choicer_mnl object (list with coefficients table and
metadata, including a gof element with goodness-of-fit measures from
gof; its fields are NA when the model was fitted with
keep_data = FALSE).
library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) summary(fit)library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) summary(fit)
Posterior summaries (mean, SD, equal-tailed credible interval) of the identified coefficient and covariance draws.
## S3 method for class 'choicer_mnp' summary(object, prob = 0.95, ...)## S3 method for class 'choicer_mnp' summary(object, prob = 0.95, ...)
object |
A choicer_mnp object. |
prob |
Probability mass of the equal-tailed credible interval (default 0.95). |
... |
Additional arguments (ignored). |
A summary.choicer_mnp object (list with coefficient and Sigma posterior tables plus metadata).
library(data.table) set.seed(42) N <- 100; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnprobit(dt, "id", "alt", "choice", c("x1", "x2"), mcmc = list(R = 300, burn = 100)) summary(fit)library(data.table) set.seed(42) N <- 100; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnprobit(dt, "id", "alt", "choice", c("x1", "x2"), mcmc = list(R = 300, burn = 100)) summary(fit)
Computes coefficient summary with delta-method transformation for variance parameters (Cholesky to covariance scale) and log-normal mean parameters. Triggers lazy Hessian computation if standard errors have not been computed yet.
## S3 method for class 'choicer_mxl' summary(object, gof = TRUE, ...)## S3 method for class 'choicer_mxl' summary(object, gof = TRUE, ...)
object |
A choicer_mxl object. |
gof |
Logical; compute goodness-of-fit measures (McFadden R-squared, hit rate) for the summary footer. Involves an in-sample prediction pass (for mixed logit, a full simulation over draws); set to FALSE to skip. |
... |
Additional arguments (ignored). |
A summary.choicer_mxl object (includes a gof element with
goodness-of-fit measures from gof; its fields are NA when
the model was fitted with keep_data = FALSE).
library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), w1 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mxlogit( data = dt, id_col = "id", alt_col = "alt", choice_col = "choice", covariate_cols = "x1", random_var_cols = "w1", S = 50L ) summary(fit)library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), w1 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mxlogit( data = dt, id_col = "id", alt_col = "alt", choice_col = "choice", covariate_cols = "x1", random_var_cols = "w1", S = 50L ) summary(fit)
Triggers lazy Hessian computation if standard errors have not been computed yet.
## S3 method for class 'choicer_nl' summary(object, gof = TRUE, ...)## S3 method for class 'choicer_nl' summary(object, gof = TRUE, ...)
object |
A choicer_nl object. |
gof |
Logical; compute goodness-of-fit measures (McFadden R-squared, hit rate) for the summary footer. Involves an in-sample prediction pass (for mixed logit, a full simulation over draws); set to FALSE to skip. |
... |
Additional arguments (ignored). |
A summary.choicer_nl object (includes a gof element with
goodness-of-fit measures from gof; its fields are NA when
the model was fitted with keep_data = FALSE).
library(data.table) set.seed(42) N <- 50; J <- 4 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, nest := ifelse(alt <= 2, "A", "B")] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_nestlogit( data = dt, id_col = "id", alt_col = "alt", choice_col = "choice", covariate_cols = c("x1", "x2"), nest_col = "nest" ) summary(fit)library(data.table) set.seed(42) N <- 50; J <- 4 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, nest := ifelse(alt <= 2, "A", "B")] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_nestlogit( data = dt, id_col = "id", alt_col = "alt", choice_col = "choice", covariate_cols = c("x1", "x2"), nest_col = "nest" ) summary(fit)
Query choicer OpenMP thread settings
thread_info()thread_info()
A list with OpenMP availability, active/max thread settings, CPU thread capacity reported by OpenMP, thread limits, and relevant environment variables.
Generic dispatching on the fit's class. See
traceplot.choicer_hb() for the choicer_hmnl / choicer_hmnp method.
traceplot(object, ...)traceplot(object, ...)
object |
A fitted model object. |
... |
Additional arguments passed to methods. |
The object, invisibly.
Overlaid per-chain traceplots (base graphics, no new dependency) for a
choicer_hmnl / choicer_hmnp fit's population coefficients (b), delta
mean-function coefficients (theta), alternative-effect variance
(sigma_d2), and, opt-in, a representative subset of the (potentially
~200-column) alternative effects (delta).
## S3 method for class 'choicer_hb' traceplot(object, block = c("b", "theta", "sigma_d2"), which = NULL, ...)## S3 method for class 'choicer_hb' traceplot(object, block = c("b", "theta", "sigma_d2"), which = NULL, ...)
object |
A |
block |
Character vector, any non-empty subset of |
which |
Only consulted when |
... |
Additional arguments (ignored). |
object, invisibly.
sim <- simulate_hmnl_data(N = 60, T = 2, J = 4, seed = 1) fit <- suppressWarnings(run_hmnlogit(sim$data, "task", "alt", "choice", c("x1", "x2"), person_col = "pid", mcmc = list(R = 300, burn = 100), chains = 2)) traceplot(fit)sim <- simulate_hmnl_data(N = 60, T = 2, J = 4, seed = 1) fit <- suppressWarnings(run_hmnlogit(sim$data, "task", "alt", "choice", c("x1", "x2"), person_col = "pid", mcmc = list(R = 300, burn = 100), chains = 2)) traceplot(fit)
With no arguments, returns the variance-covariance matrix implied by the
fit's own se_method (triggering lazy computation if needed). Passing
type recomputes a different variance estimator post hoc from the
stored data — no refit needed (requires keep_data = TRUE):
"hessian"Inverse of the analytical negated Hessian (the
numerical one for a nested logit fitted with
se_method = "numeric").
"bhhh"Inverse of the BHHH/OPG information
.
"robust"Huber-White sandwich
— also the valid WESML
variance under choice-based weighting.
"cluster"Cluster-robust sandwich
with
the within-cluster sum of weighted
scores. Requires cluster (or a fit made with
cluster_col). No small-sample correction is applied.
Here indexes likelihood units: choice situations, or
decision makers for a mixed logit fitted with person_col (panel
likelihood). For repeated choices by the same decision maker in a
cross-sectional fit, cluster on the decision maker.
## S3 method for class 'choicer_fit' vcov(object, type = NULL, cluster = NULL, ...)## S3 method for class 'choicer_fit' vcov(object, type = NULL, cluster = NULL, ...)
object |
A choicer_fit object. |
type |
|
cluster |
Cluster labels for
Defaults to the labels stored at fit time via |
... |
Additional arguments (ignored). |
Note (mixed logit): without person_col, clustering repairs the
inference, not the likelihood. The cross-sectional
likelihood treats each choice situation as an independent draw from the
mixing distribution; on panel data it is a composite likelihood that
still targets the population taste distribution , just inefficiently. type = "cluster" makes the point
estimates' standard errors robust to within-person dependence but does
not recover the efficiency of the panel likelihood (person_col).
With person_col the scores are per decision maker, so
type = "robust" is already clustered by decision maker; cluster
labels must then nest decision makers (be constant within each), and
type = "cluster" adds something only for coarser groups such as
households or markets.
Named variance-covariance matrix, or NULL if unavailable: when
the information is singular, or when the variance failed at fit time (the
fit warned, and its variance_error holds the error; see
run_mnlogit). For such a fit, type computes the
variance from the stored data and returns it; the fit itself keeps its
NA standard errors. Removing the record,
fit$variance_error <- NULL, lets summary() and the other
methods compute the variance each time they need it.
library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, person := rep(1:10, each = 5)[id]] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) vcov(fit) # as fitted (hessian) vcov(fit, type = "robust") # Huber-White, post hoc # named by situation id -> safe regardless of order cl <- dt[, person[1L], by = id] vcov(fit, type = "cluster", cluster = setNames(cl$V1, cl$id))library(data.table) set.seed(42) N <- 50; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, person := rep(1:10, each = 5)[id]] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnlogit(dt, "id", "alt", "choice", c("x1", "x2")) vcov(fit) # as fitted (hessian) vcov(fit, type = "robust") # Huber-White, post hoc # named by situation id -> safe regardless of order cl <- dt[, person[1L], by = id] vcov(fit, type = "cluster", cluster = setNames(cl$V1, cl$id))
Posterior covariance of the population coefficients
## S3 method for class 'choicer_hb' vcov(object, ...)## S3 method for class 'choicer_hb' vcov(object, ...)
object |
A |
... |
Additional arguments (ignored). |
K x K posterior covariance matrix of the b draws.
Returns the posterior covariance matrix of the identified coefficient draws (computed eagerly at fit time; no Hessian is involved).
## S3 method for class 'choicer_mnp' vcov(object, ...)## S3 method for class 'choicer_mnp' vcov(object, ...)
object |
A choicer_mnp object. |
... |
Additional arguments (ignored). |
Named posterior covariance matrix.
library(data.table) set.seed(42) N <- 100; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnprobit(dt, "id", "alt", "choice", c("x1", "x2"), mcmc = list(R = 300, burn = 100)) vcov(fit)library(data.table) set.seed(42) N <- 100; J <- 3 dt <- data.table(id = rep(1:N, each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), x2 = rnorm(.N))] dt[, choice := 0L] dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id] fit <- run_mnprobit(dt, "id", "alt", "choice", c("x1", "x2"), mcmc = list(R = 300, burn = 100)) vcov(fit)
Recomputes the robust Huber-White sandwich variance
for a fitted multinomial (MNL), mixed (MXL) or
nested (NL) logit, where the bread
is the weighted negated Hessian and the meat
is the weight-squared outer product of the
per-individual scores. This is the appropriate variance under choice-based
(endogenous stratified) / WESML weighting, where the inverse-Hessian and the
ordinary BHHH variance are invalid. It can be called on any fitted model
(e.g. one estimated with se_method = "hessian") to obtain robust
standard errors post hoc, without refitting.
wesml_vcov(object, ...) ## S3 method for class 'choicer_mxl' wesml_vcov(object, type = c("vcov", "se"), ...) ## S3 method for class 'choicer_mnl' wesml_vcov(object, type = c("vcov", "se"), ...) ## S3 method for class 'choicer_nl' wesml_vcov(object, type = c("vcov", "se"), ...)wesml_vcov(object, ...) ## S3 method for class 'choicer_mxl' wesml_vcov(object, type = c("vcov", "se"), ...) ## S3 method for class 'choicer_mnl' wesml_vcov(object, type = c("vcov", "se"), ...) ## S3 method for class 'choicer_nl' wesml_vcov(object, type = c("vcov", "se"), ...)
object |
A fitted |
... |
Unused. |
type |
Either |
If the stored weights are uniform (all equal), a warning is emitted: the returned variance is then the ordinary robust (Huber-White) variance, not a WESML-weighted variance. Refit with WESML weights for a choice-based-sampling correction.
A variance-covariance matrix (type = "vcov") or a named
numeric vector of standard errors (type = "se"), in the raw
parameter space.
wesml_weights, sample_by_choice,
run_mxlogit
library(data.table) set.seed(1) N <- 200L; J <- 3L dt <- data.table(id = rep(seq_len(N), each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), w1 = rnorm(.N))] dt[, choice := as.integer(seq_len(.N) == sample.int(.N, 1L)), by = id] fit <- run_mxlogit(dt, "id", "alt", "choice", "x1", "w1", S = 50L) wesml_vcov(fit, "se")library(data.table) set.seed(1) N <- 200L; J <- 3L dt <- data.table(id = rep(seq_len(N), each = J), alt = rep(1:J, N)) dt[, `:=`(x1 = rnorm(.N), w1 = rnorm(.N))] dt[, choice := as.integer(seq_len(.N) == sample.int(.N, 1L)), by = id] fit <- run_mxlogit(dt, "id", "alt", "choice", "x1", "w1", S = 50L) wesml_vcov(fit, "se")
Computes Manski-Lerman (1977) Weighted Exogenous Sample Maximum Likelihood
(WESML) weights for a choice-based sample. The weight for a choice situation
whose chosen alternative is is , where
is the population share of alternative and its
sample share among choosers. Using these weights in
run_mxlogit restores consistency under choice-based sampling;
pair them with se_method = "sandwich" for valid (robust) standard
errors (the plain inverse-Hessian is invalid under weighting).
wesml_weights( data, id_col, alt_col, choice_col, Q, H = NULL, normalize = TRUE, attach = FALSE, weight_name = ".wesml_weight", outside_opt_label = NULL, include_outside_option = FALSE )wesml_weights( data, id_col, alt_col, choice_col, Q, H = NULL, normalize = TRUE, attach = FALSE, weight_name = ".wesml_weight", outside_opt_label = NULL, include_outside_option = FALSE )
data |
A long-format choice data set (data.frame or data.table), one row per alternative per choice situation. |
id_col, alt_col, choice_col
|
Column names identifying the choice situation, the alternative, and the 0/1 chosen indicator. |
Q |
Named numeric vector of population shares, one entry per chosen
stratum (names matched to |
H |
Optional named numeric vector of sample shares. If |
normalize |
If |
attach |
If |
weight_name |
Name of the weight column (default |
outside_opt_label, include_outside_option
|
Set
|
Strata are defined by the chosen alternative and keyed by
as.character(alt) so numeric and character alternative codes match
supplied share names unambiguously.
Either an id-keyed data.table with columns id_col and
weight_name (default), or, when attach = TRUE, a copy of
data with the weight column appended. The result carries "Q",
"H", and "choice_sampling" attributes recording provenance.
Manski, C. F. and Lerman, S. R. (1977). The Estimation of Choice Probabilities from Choice Based Samples. Econometrica 45(8), 1977-1988. Train, K. E. (2009). Discrete Choice Methods with Simulation, Section 3.7. Cambridge University Press.
sample_by_choice, run_mxlogit,
wesml_vcov
library(data.table) set.seed(1) N <- 300L; J <- 3L pop <- data.table(id = rep(seq_len(N), each = J), alt = rep(1:J, N)) pop[, x1 := rnorm(.N)] pop[, w1 := rnorm(.N)] pop[, choice := as.integer(seq_len(.N) == sample.int(.N, 1L)), by = id] # Population shares of the chosen alternative Q <- prop.table(table(pop[choice == 1, alt])) wt <- wesml_weights(pop, "id", "alt", "choice", Q = Q) head(wt)library(data.table) set.seed(1) N <- 300L; J <- 3L pop <- data.table(id = rep(seq_len(N), each = J), alt = rep(1:J, N)) pop[, x1 := rnorm(.N)] pop[, w1 := rnorm(.N)] pop[, choice := as.integer(seq_len(.N) == sample.int(.N, 1L)), by = id] # Population shares of the chosen alternative Q <- prop.table(table(pop[choice == 1, alt])) wt <- wesml_weights(pop, "id", "alt", "choice", Q = Q) head(wt)
Computes willingness-to-pay (WTP) ratios with delta-method standard errors
from a fitted choice model. For an attribute coefficient
and a price coefficient , the WTP is
the marginal rate of substitution between the attribute and price. Standard
errors use the delta method with analytic gradients
and
, applied to the
corresponding 2x2 block of vcov(object).
## S3 method for class 'choicer_hb' wtp(object, price_var, attr_vars = NULL, level = 0.95, ...) wtp(object, price_var, attr_vars = NULL, level = 0.95, ...) ## S3 method for class 'choicer_fit' wtp(object, price_var, attr_vars = NULL, level = 0.95, ...) ## S3 method for class 'choicer_mxl' wtp(object, price_var, attr_vars = NULL, level = 0.95, ...)## S3 method for class 'choicer_hb' wtp(object, price_var, attr_vars = NULL, level = 0.95, ...) wtp(object, price_var, attr_vars = NULL, level = 0.95, ...) ## S3 method for class 'choicer_fit' wtp(object, price_var, attr_vars = NULL, level = 0.95, ...) ## S3 method for class 'choicer_mxl' wtp(object, price_var, attr_vars = NULL, level = 0.95, ...)
object |
A fitted model object ( |
price_var |
Name of the price variable. Must be a fixed-coefficient
variable (a column of the design matrix |
attr_vars |
Character vector of attributes to report. Defaults to all
fixed-coefficient variables other than |
level |
Confidence level for the normal-approximation interval
|
... |
Additional arguments passed to methods. |
For mixed logit models, random coefficients are included via their
estimated location parameters. The package's log-normal random coefficient
is the shifted log-normal
(see
run_mxlogit()), so:
Normal random coefficient (rc_mean = TRUE): mean WTP
, labeled Mu_x.
Log-normal random coefficient (rc_mean = TRUE):
median WTP , since the
median of is 1. (The mean,
, is highly sensitive to the
estimated variance; the median is the more robust summary.) These rows
are labeled by the attribute name and flagged as medians when printed.
Log-normal random coefficient with rc_mean = FALSE:
has median 1, so the median WTP is
with uncertainty driven solely by .
Normal random coefficients with rc_mean = FALSE have mean 0 by
construction and are excluded from the table.
The price variable must have a fixed coefficient. A random price
coefficient is rejected: the ratio of two random coefficients generally has
no finite moments (the denominator has positive density at 0), so mean or
median WTP computed from location parameters would be meaningless. In
choicer, use a fixed price coefficient. WTP-space estimation is not
currently implemented; it is an alternative specification available in
other software rather than an option supplied by this function.
A data.frame of class choicer_wtp with one row per
attribute and columns Estimate, Std_Error, z_value,
CI_lower, CI_upper. Attributes price_var and
level record the inputs; median_rows lists rows that are
median (rather than mean) WTP. Standard errors are NA when the
variance-covariance matrix is unavailable.
wtp(choicer_hb): Posterior willingness-to-pay for hierarchical Bayes fits:
the per-draw ratio of population-mean utility coefficients,
(for log-normal
coordinates ). Ratio posteriors
are heavy-tailed, so the point estimate is the posterior median
with equal-tailed quantile intervals — never a posterior mean or a
delta-method SE. A warning is raised when the price coefficient's sign
is not resolved by the posterior. If the price variable was flagged as
endogenous-without-a-control-function at prep time, WTP inherits that
caveat (see cf_residual_col in prepare_hmnl_data()).
library(data.table) sim <- simulate_mnl_data(N = 1000, J = 4, beta = c(0.8, -0.6), seed = 123, outside_option = FALSE, vary_choice_set = FALSE) fit <- run_mnlogit(sim$data, "id", "alt", "choice", c("x1", "x2")) # treat x2 as the price variable wtp(fit, price_var = "x2") wtp(fit, price_var = "x2", attr_vars = c("x1", "ASC_2"), level = 0.90)library(data.table) sim <- simulate_mnl_data(N = 1000, J = 4, beta = c(0.8, -0.6), seed = 123, outside_option = FALSE, vary_choice_set = FALSE) fit <- run_mnlogit(sim$data, "id", "alt", "choice", c("x1", "x2")) # treat x2 as the price variable wtp(fit, price_var = "x2") wtp(fit, price_var = "x2", attr_vars = c("x1", "ASC_2"), level = 0.90)