The math behind choicer: nested logit
Source:vignettes/articles/nested_logit_math.Rmd
nested_logit_math.RmdThis document provides a detailed mathematical description of the
nested logit (NL) model as implemented in
src/nestlogit.cpp.
Table of Contents
- Notation
- Model Definition
- Log-Likelihood Function
- Gradient Computation
- Hessian Computation
- Implementation Details
- Post-Estimation Quantities
- Choice-Based Sampling and WESML Weighting
Notation
| Symbol | Description |
|---|---|
| Index for individuals (choice situations) | |
| Index for inside alternatives available to individual | |
| Choice set of inside alternatives available in situation | |
| The alternative chosen by individual | |
| Weight for individual | |
| Row vector of covariates for individual and alternative () | |
| Coefficient vector () | |
| Alternative-specific constant (ASC) for alternative | |
| Systematic (deterministic) utility | |
| Global set of inside alternatives belonging to nest ; situation contributes | |
| The nest containing alternative | |
| Inclusive value (dissimilarity) coefficient for nest | |
| Inclusive value for nest | |
| Probability of choosing conditional on choosing nest | |
| Marginal probability of choosing nest | |
| Probability that individual chooses alternative |
1. Model Definition
1.1 Utility Specification
The utility that individual derives from alternative is:
where the systematic utility is:
The error term follows a Generalized Extreme Value (GEV) distribution that induces within-nest correlation.
1.2 Nest Structure
The inside alternatives are partitioned into mutually exclusive and exhaustive nests . An outside option (alternative 0) with may optionally be included, and it is always assigned its own singleton nest with .
1.3 Inclusive Value Coefficients
Each nest has a dissimilarity parameter that governs within-nest substitution:
- corresponds to independent (MNL-like) alternatives within the nest.
- indicates positive within-nest correlation (the typical case).
- is mathematically evaluable in the implemented probability formula but lies outside the standard globally RUM-consistent nested-GEV restriction . It should not automatically be interpreted as a valid negative within-nest correlation parameter.
The optimizer in run_nestlogit() currently imposes the
lower bound
but does not impose
.
An estimate above one should therefore be read as a diagnostic about the
nesting tree or maintained assumptions, not as evidence of especially
strong within-nest substitution.
Singleton nests (nests with exactly one alternative) have fixed to 1 and are not estimated. Only non-singleton nests contribute parameters to . The low-level parser requires at least one globally non-singleton nest; a specification in which every nest is a singleton is rejected rather than estimated as an MNL through this entry point.
Code reference: src/nestlogit.cpp
1.4 Alternative-Specific Constants (ASCs)
The ASC identification follows the same convention as MNL:
-
Without outside option
(
include_outside_option = FALSE): The first inside alternative’s ASC is fixed to zero (). The parameter vector contains free ASC parameters. -
With outside option
(
include_outside_option = TRUE): The outside option serves as the reference with . All inside alternatives have free ASC parameters.
Code reference: src/nestlogit.cpp
2. Log-Likelihood Function
2.1 Probability Decomposition
The nested logit choice probability decomposes as:
The two components are derived from the GEV generating function.
2.2 Inclusive Value
The inclusive value for nest is the log-sum of scaled utilities within the nest:
The rest of the article suppresses the subscript and writes . Nests with no available alternative in have log inclusive value and contribute zero to the upper-level denominator.
2.3 Conditional Choice Probability
The probability of choosing alternative given that nest is chosen:
In log form:
2.4 Nest (Marginal) Probability
The probability of choosing nest :
If an outside option is included, its contribution enters the denominator as .
In log form:
2.5 Joint Choice Probability
Taking logs of the joint probability:
where (plus 1 if an outside option is present).
Code reference: src/nestlogit.cpp
2.6 Log-Likelihood
The log-likelihood is the weighted sum of log-probabilities of the observed choices:
where and is the alternative chosen by individual .
Code reference: src/nestlogit.cpp
2.7 Log-Sum-Exp Trick for Numerical Stability
Two log-sum-exp stabilizations are applied.
Within-nest inclusive value. To compute without overflow, the implementation subtracts the maximum scaled utility in each nest:
where .
Across-nest denominator. The denominator is similarly stabilized by subtracting before exponentiation.
Code reference: src/nestlogit.cpp
2.8 Relation to Other Nested-Logit Parameterizations
The probabilities in §§2.3–2.4 are the utility-normalized GEV form
used by choicer (McFadden 1978; Train 2009, Ch. 4): utility
is scaled by
inside the conditional probability, and the inclusive value is
multiplied by
in the nest probability. Some software uses a normalization in which its
reported systematic index enters the within-nest logit unscaled. These
conventions can represent different definitions of utility coefficients
and error scales; they are not generally numerically identical under a
common-coefficient restriction, and their reported
and
cannot be compared without deriving the normalization mapping. It is too
strong to label every unscaled convention non-RUM; the precise point is
which utility, inclusive-value, and scale normalization is being
estimated (Koppelman & Wen 1998; Hensher & Greene 2002; Heiss
2002).
3. Gradient Computation
3.1 Gradient with Respect to (Utility Scores)
To derive the gradients with respect to and , we first compute the derivative of the log-probability of the chosen alternative with respect to the systematic utility of each alternative .
Let denote the chosen nest (i.e., ). The log-probability of the chosen alternative is:
Derivative of the conditional term. Since and :
Derivative of the nest term. Using :
Combined. Adding both terms:
This is implemented as the vector grad_vec of length
:
Code reference: src/nestlogit.cpp
3.2 Gradient with Respect to
Since , the contribution from individual is:
The full gradient is accumulated as a single BLAS matrix-vector product, identically to MNL.
Code reference: src/nestlogit.cpp
3.3 Gradient with Respect to
Since
,
the gradient entries are the corresponding elements of
grad_vec, scattered to the appropriate positions in
:
The same free-ASC convention as MNL applies (first inside alternative’s ASC excluded when no outside option).
Code reference: src/nestlogit.cpp
3.4 Gradient with Respect to
Define the within-nest probability-weighted mean utility:
For the chosen nest (). The log-probability decomposes as:
Using :
Combining:
For a non-chosen nest (). The conditional probability is independent of , so only the nest probability contributes:
The common factor
is labeled term_in_brackets in the code.
Code reference: src/nestlogit.cpp
4. Hessian Computation
This section documents the Hessian of the negated
log-likelihood. The function
nl_loglik_hessian_parallel returns
,
the same quantity that invert_hessian() expects (positive
semi-definite at the MLE). The sign convention matches the numeric
oracle nl_loglik_numeric_hessian (which differences the
negated gradient), so both functions are interchangeable as inputs to
invert_hessian().
Two implementations are available:
-
nl_loglik_hessian_parallel— default (se_method = "hessian"): single-pass analytical Hessian derived below. Validated against the numeric oracle at a maximum absolute difference of across the package’s test fixtures, well below the tolerance those tests enforce. At extreme , the oracle’s own finite-difference accuracy degrades; the analytical Hessian remains finite and symmetric throughout. -
nl_loglik_numeric_hessian— retained oracle (se_method = "numeric"): central finite differences on the analytical gradient with step . Use for diagnostic comparison or whenever a direct verification of the analytical path is required.
4.1 Notation and Scope
All notation follows §§0–3. Subscripts (individual), (alternative local indices within ’s choice set, 0-based), and / (nest indices, 0-based) are used throughout. Additional symbols specific to this section:
| Symbol | Description |
|---|---|
| 0-based index of the chosen nest ( when outside option is chosen) | |
| 0-based local index of the chosen inside alternative | |
| — -weighted mean utility in nest | |
| — the “bracket term” from §3.4 | |
| — conditional second moment | |
| — -weighted variance of in nest | |
| — -weighted mean of in nest (-vector) | |
| — -weighted mean of in nest (-vector) | |
| — -weighted second moment of () | |
| — -weighted second moment of () | |
| — -weighted global mean of for individual (-vector) |
The negated per-individual log-likelihood contribution is . The full Hessian is the sum where .
4.2 V-Space Hessian
Because is linear in and , the second derivatives with respect to these parameters factor through the V-space Hessian. Define:
Starting from the gradient formula (§3.1):
differentiating with respect to yields:
Partial derivative of with respect to . Write , . Expanding via the product rule and using :
Partial derivative of with respect to . Non-zero only when :
Combined V-space Hessian (correct formula). Negating and combining:
The chosen-nest correction is nonzero only when both and are in the chosen nest (and ). It arises from the factor in coupling the conditional probability gradient back to .
Structural notes and MNL limit:
- For : (cross-nest entries are the negative product of marginal probabilities, the familiar multinomial covariance term).
- MNL limit ( for all ): , the standard multinomial Hessian of . Own diagonal ; off-diagonal . The chosen-nest correction vanishes because .
- When the outside option is chosen () or when (singleton chosen nest), for all pairs.
Implementation note: The implementation materializes as an explicit matrix, which is efficient for typical choice set sizes (). The outer-product decomposition used for the beta-beta block (§4.3) avoids forming this matrix explicitly for the accumulation.
Code reference: src/nestlogit.cpp
4.3 Beta-Beta Block
Since :
The matrix product is decomposed into three terms that can be accumulated in a single nest-level pass, exploiting the outer-product structure of :
Term A — universal outer product (subtracted):
This arises from the term universal to all pairs: .
Term B — per-nest within-nest correction (added), summed over all nests :
For singleton nests (): , so the contribution reduces to .
Term C — chosen-nest correction (subtracted), only when :
Here is the -weighted covariance of within the chosen nest.
Full beta-beta block (Hessian of the negated log-likelihood; positive semi-definite at the MLE):
MNL limit check. At for all : Term B ; Term C vanishes; the formula yields the standard MNL expression .
Code reference: src/nestlogit.cpp
4.4 Beta-Delta and Delta-Delta Blocks
Since , these blocks are direct projections of onto free-ASC alternatives.
Delta-delta block (for free-ASC alternatives and ):
Beta-delta block (for covariate index and free-ASC alternative ):
Both blocks reuse the same matrix computed in §4.2. No additional auxiliary quantities are required.
ASC normalization. Without an outside option, the
first inside alternative’s ASC is fixed to zero: free-ASC alternatives
satisfy alt_idx0[a] > 0, mapped to theta positions
delta_start_idx + alt_idx0[a] - 1.
Code reference: src/nestlogit.cpp
4.5 Lambda-V Cross Derivative
The lambda parameters enter nonlinearly through both and the nest probabilities, so cross-derivatives between and must be computed via the chain rule. Define:
Key intermediates (derived from §3.4):
For non-chosen nests (), using :
The first term is a universal “shift” proportional to ; the second is the within-nest correction active only for .
For the chosen nest (, only when ), using :
The extra term for arises from differentiating the component of the chosen-nest gradient.
4.6 Lambda-Beta and Lambda-Delta Blocks
Using and :
Both are filled symmetrically. Singleton nests (theta index ) contribute no rows or columns to these blocks.
Code reference: src/nestlogit.cpp
4.7 Lambda-Lambda Block
Differentiating with respect to , using:
Off-diagonal (any combination of chosen/non-chosen nests):
This formula holds uniformly regardless of whether or equals . It can be negative (whenever and share the same sign), reflecting correlation between nest-level inclusive values.
Diagonal (non-chosen nest):
The first term is a Fisher-information-type squared-gradient term; the second is positive and captures curvature from ’s dependence on through the within-nest utility variance.
Diagonal (chosen nest, only when ):
The chosen-nest diagonal differs from the non-chosen formula because the term in contributes when differentiated. Since the chosen alternative tends to have above-average utility within its nest ( in expectation), the last term is typically negative, making the chosen-nest diagonal somewhat smaller than the non-chosen counterpart.
When the outside option is chosen (), all lambda diagonals use the non-chosen formula.
Code reference: src/nestlogit.cpp
4.8 Single-Pass Implementation and Auxiliary Accumulations
All six blocks are accumulated in a single parallel pass over individuals. The per-nest auxiliary quantities below are accumulated in an inner loop over alternatives at cost before any block is computed.
Per-nest scalars (zero-initialized per individual, indexed by nest ):
| Quantity | Formula | Blocks that use it |
|---|---|---|
| , lambda-lambda, lambda-V cross | ||
| for lambda-lambda diagonal | ||
| lambda-lambda (all entries), lambda-V cross | ||
| lambda-lambda diagonal |
Per-nest K-vectors:
| Quantity | Formula | Blocks that use it |
|---|---|---|
| beta-beta Term B | ||
| beta-beta Terms B and C |
Per-nest matrices:
| Quantity | Formula | Blocks that use it |
|---|---|---|
| beta-beta Term B | ||
| beta-beta Term C (chosen nest only) |
Global per-individual: (beta-beta Term A).
OpenMP structure. The outer loop over individuals is
parallelized with dynamic scheduling. Each thread maintains a
thread-local
accumulator local_H, merged into global_H via
#pragma omp critical after the individual loop. The
nest-to-theta-index map is copied thread-privately to avoid false
sharing.
Symmetrization and sanitization. After the parallel loop: enforces exact symmetry; any remaining non-finite entries are zeroed.
Singleton-nest handling. Singleton nests (, theta index ) contribute nothing to the lambda-lambda, lambda-beta, or lambda-delta blocks. Their beta-beta contribution via Term B simplifies to (since ).
Per-individual weights. Every contribution is multiplied by (WESML weight; equals 1 for unweighted data).
Code reference: src/nestlogit.cpp
5. Implementation Details
5.1 Parameter Vector Structure
The full parameter vector is organized as:
| Block | Indices | Length | Description |
|---|---|---|---|
| Coefficients for design matrix | |||
| Non-singleton nest dissimilarity parameters | |||
| , , or | Free alternative-specific constants |
where
is the number of non-singleton nests and
when use_asc = FALSE,
without an outside option, or
with an outside option.
Code reference: src/nestlogit.cpp
5.2 Singleton Nest Handling
At startup, the implementation identifies which nests are singletons
(contain exactly one alternative). These nests: - Have their
fixed to 1 (no contribution to the upper-level logit denominator beyond
their single utility term). - Are excluded from the estimated parameter
vector. - Are tracked via nest_k_to_theta_idx, an integer
vector of length
where entry
holds the corresponding index in
for non-singleton nests and
for singletons.
This ensures that the NL model degenerates gracefully to MNL on a per-nest basis when nests are singletons.
Code reference: src/nestlogit.cpp
5.3 Data Organization
- Design matrix : Stacked matrix of dimension , where is the number of inside alternatives for individual .
-
alt_idx: 1-based indices mapping rows of to global alternative IDs. -
nest_idx: 1-based nest assignment of length (number of unique inside alternatives), not length . Accessed vianest_idx.elem(alt_idx0_i)to handle varying choice sets. -
choice_idx: 1-based local row position of the chosen inside alternative within each situation’s block; 0 for the outside option. - Prefix sums : Used for efficient slicing into the stacked data: .
Code reference: src/nestlogit.cpp
5.4 Base Utility Pre-computation
Prior to the parallel loop, all systematic utilities are computed in a single pass:
base_util = X * beta // single BLAS dgemm
if use_asc: base_util += delta[alt_idx0]
This avoids redundant matrix-vector products inside the per-individual loop.
Code reference: src/nestlogit.cpp
5.5 OpenMP Parallelization
The implementation parallelizes over individuals using OpenMP: - Each
thread maintains local accumulators for log-likelihood and gradient. -
nest_k_to_theta_idx is copied thread-privately to avoid
false sharing. - Thread results are combined using
#pragma omp critical sections. - Dynamic scheduling
balances load across individuals with varying choice set sizes.
Code reference: src/nestlogit.cpp
5.6 Negated Objectives
The likelihood/gradient kernel returns: - (negated log-likelihood) - (negated gradient)
for compatibility with minimization routines (e.g.,
nloptr) that minimize a loss function rather than maximize
a likelihood. The analytical and numeric Hessian kernels return
;
the BHHH kernel instead returns the positive-semidefinite OPG
information approximation
.
5.7 Finite-Value Guards
The likelihood kernel replaces a non-finite chosen log probability by . If the final negated objective is non-finite it returns and a zero gradient; isolated non-finite gradient entries are zeroed. The analytical Hessian skips a situation whose chosen log probability is non-finite, symmetrizes the aggregate, and replaces any remaining non-finite entries by zero. These rules are optimizer failure guards, not part of the regular finite-parameter nested-logit criterion; encountering them calls for rescaling or revising the specification.
Code reference: src/nestlogit.cpp
6. Post-Estimation Quantities
6.1 Choice Probabilities (predict)
The joint probability is the decomposition from §2.1:
with
and
given in §§2.3–2.4. nl_predict returns individual-level
probabilities
and systematic utilities
for every observation row. nl_predict_shares aggregates
over individuals to obtain weighted market shares:
Code reference: src/nestlogit.cpp
6.2 Elasticities
6.2.1 Semi-elasticity with respect to utility
Let be the nest of the responding alternative and be the nest of the perturbed alternative . From §3.1, the derivative of with respect to the systematic utility of any alternative is:
This is the general expression; the gradient formula in §3.1 applies it only to the chosen alternative, whereas here we evaluate it for all pairs to construct the full elasticity matrix.
6.2.2 Elasticity of with respect to covariate of alternative
Since :
Substituting the three cases:
| Case | Condition | Semi-elasticity |
|---|---|---|
| Own | ||
| Cross, same nest | ||
| Cross, different nest |
Reduction to MNL. When for all nests the within-nest term vanishes and the conditional probability drops out, giving , which is exactly the MNL semi-elasticity (§3.1 of the MNL document).
Outside option. When an outside option is present it occupies its own singleton nest with and . Its row (responding = outside option) has semi-elasticity for every inside alternative (different nest, §3.1); its column (perturbed = outside option) is identically zero because .
The implementation accumulates across individuals and divides by to produce a weighted average of individual probability elasticities. This is not generally the elasticity of an aggregate share under a common market-level perturbation when attributes vary across situations. Rows index responding alternatives and columns perturbed alternatives.
Code reference: src/nestlogit.cpp
6.3 Diversion Ratios
6.3.1 Definition
The utility-based diversion ratio from losing alternative to receiving alternative is:
where is aggregate demand and the perturbation is through the systematic utility of the losing alternative .
6.3.2 Partial derivatives of demand
Using and the semi-elasticity from §6.2.1, the three cases with :
6.3.3 Utility Perturbation and Covariate Interpretation
The implemented matrix is defined with respect to a common additive perturbation of . If a fixed-coefficient attribute of alternative receives the same additive change in every situation, , so the common scalar cancels:
It is in this additive-shift sense that NL diversion is independent of the chosen fixed covariate. For a proportional perturbation , the values remain inside both population sums and generally do not cancel. The kernel does not compute that attribute-specific proportional diversion. In MXL even a common additive perturbation of a random-coefficient attribute carries draw-specific , so the coefficient cannot be factored out.
6.3.4 Population aggregation and column-sum property
Define:
so that for .
Columns sum to 1. The fundamental identity (probabilities sum to 1 for every individual and every perturbation direction, including the outside option when present) gives:
When an outside option is present it acts as both a source (it can lose demand) and a destination (it can receive diverted demand), so it appears in both the row index and the column index of the diversion matrix, and the column sums still equal 1 over all alternatives including the outside option. Because its systematic utility is fixed at zero in estimation, the outside-as-source column is a derivative with respect to a hypothetical perturbation of that normalized utility, not an available outside-option covariate.
6.3.5 Reduction to MNL at
When all the cross-same-nest case collapses to the cross-different-nest case ( for ) and the own case gives . Substituting:
which is the MNL diversion ratio (§6.3 of the MNL document).
Code reference: src/nestlogit.cpp
6.4 BLP Share Inversion
6.4.1 Problem statement
Given observed market shares , find the ASC vector such that the NL model reproduces those shares:
6.4.2 Damped contraction mapping
Under the usual feasibility, connected-substitutes, and normalization conditions, the BLP fixed-point iteration is
with giving the undamped update. Existence, uniqueness, and global convergence are properties of the share mapping and target—not an unconditional guarantee for every numerical input. Predicted shares are computed via the NL formula:
where is evaluated at the current with and held fixed.
6.4.3 Damping for nested models
For strongly nested data (small ) the plain update can overshoot numerically. Choosing may stabilize iteration. A possible empirical starting heuristic is
but this is not a theorem or an automatic rule in the package. The
kernel accepts the numeric damping value as supplied and
does not constrain it to
;
the analyst must inspect convergence and resulting share residuals.
6.4.4 Baseline re-normalization
Without an outside option, delta is a full
length-
vector and is centered initially and on return by subtracting its first
inside entry, so the returned baseline is zero. With an outside option,
supplied and returned delta contain the
inside ASCs only. The kernel works internally with a prepended outside
entry, pins that entry at zero after each update, and returns the inside
subvector without subtracting the first inside ASC.
All target shares must be strictly positive and have length
(no outside) or
(outside first). The kernel does not check that they sum to one.
Convergence uses the largest absolute change in the full working vector;
reaching max_iter prints a warning and returns the last
iterate without a separate convergence flag.
Note on the lambda argument.
nl_blp_contraction expects a full
length-
vector where singleton nests have their entry set to 1. This differs
from the estimated parameter block
in
,
which contains only non-singleton entries. The caller is responsible for
expanding the estimated lambdas into the full vector before invoking the
contraction.
Code reference: src/nestlogit.cpp
6.5 Willingness to Pay
Utility is linear in covariates, so willingness to pay is the same marginal rate of substitution as in the MNL model: for attribute and price coefficient ,
with the block of the coefficient covariance. The nest parameters rescale within-nest substitution but do not enter the ratio of marginal utilities, so they affect WTP only through the estimated covariance of . ASCs may also be used as the numerator (). See §8 of the MNL document for the full derivation and caveats.
Code reference: R/wtp.R
6.6 Consumer Surplus and the Nested Logsum
For the nested logit, expected maximum utility is the two-level
logsum below plus the scenario-invariant extreme-value location constant
(omitted by logsum(), as in MNL):
where the term appears when an outside option is present and singleton nests have (§5.2). Both levels are computed with the max-subtraction trick (§2.7).
Two useful identities:
- Reduction to MNL. With all , and the nested logsum collapses to the MNL logsum .
- Outside-option link. Since (§2.5), the logsum equals — a direct consistency check against the probability kernel.
Expected consumer surplus follows Train (2009, Ch. 3) exactly as in the MNL case:
with the same caveats: no income effects, and CS levels inherit the
ASC normalization, so only differences across scenarios (counterfactual
newdata vs. baseline) are meaningful. The implementation
reports point estimates for NL (the delta-method SE of the mean CS is
currently provided for MNL only; Krinsky–Robb resampling of the
coefficients is the practical interval method here). The routine does
not enforce
;
interpreting
as positive marginal utility of income requires the analyst to verify
the estimated sign.
Code reference: R/surplus.R
6.7 Goodness of Fit
The measures are model-agnostic and identical to §10 of the MNL document, computed from the NL log-likelihood and predicted probabilities:
- McFadden pseudo R²: and , with counting all estimated parameters including the block.
- Equal-shares null (default, exact for unbalanced sets and weights): .
- Market-shares null (constants-only closed form): , where is the common weight; requires identical choice-set composition across individuals and uniform weights. The constants-only model is itself an MNL—at and free ASCs the nest structure is not identified from constant shares—so the same closed form applies.
- Hit rate: weighted share of choice situations whose observed choice has the highest predicted NL probability; with an outside option the outside good competes with .
Code reference: R/gof.R
7. Choice-Based Sampling and WESML Weighting
7.1 Endogenous Stratified (Choice-Based) Sampling
Under random (exogenous) sampling each choice situation is drawn independently of its outcome. Under choice-based (endogenous stratified) sampling the strata are defined by the chosen alternative and situations are drawn with stratum-specific frequencies — for example, deliberately oversampling individuals who chose a rare alternative. Let be the population share of alternative and the sample share of choosers of .
Unlike the MNL special case (a full set of ASCs leaves the slopes consistent), the nested logit has no such free pass: the dissimilarity parameters enter the within- and between-nest probabilities nonlinearly, so choice-based sampling generally biases the slopes , the constants , and the block. Weighting is therefore required for consistent estimation of the population parameters.
7.2 The WESML Weighted Log-Likelihood
Manski and Lerman (1977) restore consistency by weighting each situation’s contribution by the ratio of population to sample share of its chosen alternative,
The maximizer is invariant to multiplying every by a common positive constant, so the weights may be normalized to mean 1 without changing the estimates.
7.3 Robust (Sandwich) Variance: the Meat
WESML is a weighted M-estimator solving , where is the full per-situation score over the , and blocks ($$3) and its Hessian ($$4). Its robust (Huber–White) asymptotic variance is the sandwich
The weight enters the bread
linearly, but the meat
carries the weight squared: the contribution of
situation
to the estimating equation is
,
so its variance involves
.
The score
is assembled exactly as in the gradient kernel ($$3.3–3.4): the
and
blocks from grad_vec, and the
blocks from the per-nest expression
, with singleton nests
()
contributing no score.
As in the MNL/MXL cases, both naive variances are wrong under weighting: the inverse-Hessian assumes the information-matrix equality (which fails once the are non-degenerate), and ordinary BHHH/OPG uses the weight to the first power, not the second. The sandwich is invariant to the weight scale: , , hence .
7.4 Scope: Robust vs. Design-Based Variance
The estimator implemented here is the robust weighted-M-estimator (Huber–White) variance, with uncentered meat — the asymptotic variance under variable-probability sampling. The smaller stratum-centered (design-based) variance for a fixed-quota design is out of scope; see Manski & McFadden (1981) and Cosslett (1981).
7.5 Implementation and Cluster-Robust Extension
The common post-estimation path obtains the
matrix
of weight-free scores from nl_scores_parallel (singleton
lambda rows are absent because those parameters are not in
),
then forms
For a fit whose selected method is the numeric NL Hessian, the
post-hoc bread uses the numeric oracle instead. The eager fit-time
robust path is algebraically identical and may obtain
by calling the BHHH accumulator with weights = w^2. For
cluster labels
,
se_method = "cluster" uses
with no finite-cluster correction. These matrices are combined as
.
User-facing entry points: wesml_weights() computes the
Manski–Lerman weights from the population shares
,
while sample_by_choice() draws a choice-based sample and
attaches those weights;
run_nestlogit(..., se_method = "sandwich") estimates with
the robust variance; wesml_vcov() returns it post hoc.
Passing run_nestlogit(..., weights_col = ) collapses a
row-level weight column to one weight per choice situation (validated
constant within id), and a provenance guard prevents a
WESML-labeled sample from being silently fit unweighted.
Code reference: nl_scores_parallel() /
nl_bhhh_parallel() in src/nestlogit.cpp;
compute_sandwich_vcov(), .score_meat(), and
.assemble_score_vcov() in R/classes.R;
wesml_weights() / sample_by_choice() in R/sampling.R.
References
- McFadden, D. (1978). Modelling the choice of residential location. In A. Karlqvist et al. (Eds.), Spatial Interaction Theory and Planning Models (pp. 75-96). North-Holland.
- Ben-Akiva, M., & Lerman, S. R. (1985). Discrete Choice Analysis: Theory and Application to Travel Demand. MIT Press.
- Koppelman, F. S., & Wen, C.-H. (1998). Alternative nested logit models: structure, properties and estimation. Transportation Research Part B, 32(5), 289-298.
- Hensher, D. A., & Greene, W. H. (2002). Specification and estimation of the nested logit model: alternative normalisations. Transportation Research Part B, 36(1), 1-17.
- Heiss, F. (2002). Structural choice analysis with nested logit models. The Stata Journal, 2(3), 227-252.
- Berry, S., Levinsohn, J., & Pakes, A. (1995). Automobile prices in market equilibrium. Econometrica, 63(4), 841–890.
- Train, K. E. (2009). Discrete Choice Methods with Simulation (2nd ed.). Cambridge University Press. Chapter 4.
- Manski, C. F., & Lerman, S. R. (1977). The estimation of choice probabilities from choice based samples. Econometrica, 45(8), 1977–1988.
- Manski, C. F., & McFadden, D. (1981). Alternative estimators and sample designs for discrete choice analysis. In C. F. Manski & D. McFadden (Eds.), Structural Analysis of Discrete Data with Econometric Applications (pp. 2–50). MIT Press.
- Cosslett, S. R. (1981). Maximum likelihood estimator for choice-based samples. Econometrica, 49(5), 1289–1316.