WESML weights for choice-based (endogenous stratified) samples
Source:R/sampling.R
wesml_weights.RdComputes 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 \(j\) is \(w = Q(j) / H(j)\), where
\(Q(j)\) is the population share of alternative \(j\) and \(H(j)\) 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).
Usage
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
)Arguments
- 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
as.character(alt)), each strictly positive. Renormalized to sum 1 if needed.- H
Optional named numeric vector of sample shares. If
NULL(default) it is computed fromdataas the fraction of choice situations choosing each alternative.- normalize
If
TRUE(default) the returned weights are scaled to mean 1. This does not affect the point estimates or the sandwich variance.- attach
If
TRUE, returndatawith a row-level weight column appended (the per-situation weight repeated across all rows of a situation), ready to pass torun_mxlogit(weights_col = ...). IfFALSE(default) return an id-keyed table of weights.- weight_name
Name of the weight column (default
".wesml_weight").- outside_opt_label, include_outside_option
Set
include_outside_option = TRUEand supplyoutside_opt_labelwhen the outside good is implicit (choice situations with no1inchoice_colare treated as having chosen the outside good).
Value
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.
Details
Strata are defined by the chosen alternative and keyed by
as.character(alt) so numeric and character alternative codes match
supplied share names unambiguously.
References
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.
Examples
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)]
#> id alt x1
#> <int> <int> <num>
#> 1: 1 1 -0.6264538
#> 2: 1 2 0.1836433
#> 3: 1 3 -0.8356286
#> 4: 2 1 1.5952808
#> 5: 2 2 0.3295078
#> ---
#> 896: 299 2 -0.0132557
#> 897: 299 3 -0.9314803
#> 898: 300 1 1.2146891
#> 899: 300 2 -2.0883404
#> 900: 300 3 -0.5261525
pop[, w1 := rnorm(.N)]
#> id alt x1 w1
#> <int> <int> <num> <num>
#> 1: 1 1 -0.6264538 -1.5414026
#> 2: 1 2 0.1836433 0.1943211
#> 3: 1 3 -0.8356286 0.2644225
#> 4: 2 1 1.5952808 -1.1187352
#> 5: 2 2 0.3295078 0.6509530
#> ---
#> 896: 299 2 -0.0132557 1.9363973
#> 897: 299 3 -0.9314803 -1.4558838
#> 898: 300 1 1.2146891 1.4819057
#> 899: 300 2 -2.0883404 1.0761196
#> 900: 300 3 -0.5261525 -0.7574884
pop[, choice := as.integer(seq_len(.N) == sample.int(.N, 1L)), by = id]
#> id alt x1 w1 choice
#> <int> <int> <num> <num> <int>
#> 1: 1 1 -0.6264538 -1.5414026 0
#> 2: 1 2 0.1836433 0.1943211 1
#> 3: 1 3 -0.8356286 0.2644225 0
#> 4: 2 1 1.5952808 -1.1187352 0
#> 5: 2 2 0.3295078 0.6509530 1
#> ---
#> 896: 299 2 -0.0132557 1.9363973 0
#> 897: 299 3 -0.9314803 -1.4558838 0
#> 898: 300 1 1.2146891 1.4819057 0
#> 899: 300 2 -2.0883404 1.0761196 1
#> 900: 300 3 -0.5261525 -0.7574884 0
# 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)
#> Key: <id>
#> id .wesml_weight
#> <int> <num>
#> 1: 1 1
#> 2: 2 1
#> 3: 3 1
#> 4: 4 1
#> 5: 5 1
#> 6: 6 1