Skip to contents

Estimates a nested logit model via maximum likelihood.

Usage

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")
)

Arguments

data

Data frame containing choice data (convenience workflow). Mutually exclusive with input_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/0).

covariate_cols

Vector of column names for covariates. None may be named like a generated parameter: Lambda_<k>, or ASC_<label> with use_asc = TRUE.

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 data.

use_asc

Logical indicating whether to include alternative specific constants (ASCs).

theta_init

Optional initial parameter vector in natural units, ordered as the coefficients, the nest parameters (Lambda_<k>, one per nest of two or more alternatives) and the constants. If NULL: 0 for the coefficients and constants, 0.5 for each nest parameter.

param_names

Optional vector of parameter names, which must be unique. If NULL, default names are generated.

optimizer

Optimizer to use: "nloptr" (default), "optim", or a custom function. See run_mnlogit for details.

control

List of optimizer-specific control parameters. With scale_vars other than "none", settings in parameter units apply to the scaled coordinates.

weights

Optional weight vector (convenience workflow). If NULL, equal weights are used. All weights must be finite and strictly positive.

weights_col

Optional name of a column in data holding per-row weights (convenience workflow only). The column must be constant within each id_col (one weight per choice situation) and is collapsed accordingly. Mutually exclusive with weights. All weights must be finite and strictly positive. Used for choice-based / WESML weighting; pair with se_method = "sandwich" for valid inference.

outside_opt_label

Label for the outside option (convenience workflow).

include_outside_option

Logical whether to include an outside option (convenience workflow).

keep_data

Logical. If TRUE (default), stores prepared data in the returned object for post-estimation functions.

se_method

Method for computing standard errors: "hessian" (default, analytical Hessian via nl_loglik_hessian_parallel), "numeric" (finite-difference oracle via nl_loglik_numeric_hessian), "bhhh" (outer product of gradients via nl_bhhh_parallel), "sandwich" (robust Huber–White / WESML variance \(A^{-1} B A^{-1}\)), or "cluster" (cluster-robust sandwich; requires cluster_col or a prepared input_data with a cluster field). Use "sandwich" under choice-based / WESML weighting. Any of these can also be recomputed post hoc via vcov(fit, type = ).

cluster_col

Optional name of a column in data holding cluster labels for cluster-robust standard errors (e.g. a person id when the same decision maker contributes several choice situations). Must be constant within each id_col. Supplying cluster_col without an explicit se_method selects se_method = "cluster".

nloptr_opts

Deprecated. Use optimizer and control instead.

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 "none" (default), "sd" (sample standard deviation), "mad" (stats::mad), "iqr" (stats::IQR(x) / 1.349), or "bhhh". With "sd", "mad" or "iqr", the optimizer works on the coefficients X would have with every column divided by the chosen scale (each coefficient times its column's scale), to improve the conditioning of its problem; the nest parameters and constants keep their scale, and the data are not divided. "bhhh" scales every parameter, nest parameters included, by the inverse square root of the diagonal of the BHHH (outer product of gradients) matrix at the start values, rounded to a power of two, from one extra gradient pass. Its scales are fixed at the start values, so when the nest parameters end far from their start (0.5) they can mislead the optimizer, which then converges more slowly than without them; hence "none" is the default here. Where the diagonal is unusable (no finite, positive entry), the parameters are left unscaled, with a message. With any choice but "none", the optimizer, a custom one included, works in the scaled coordinates (theta_init, in natural units, and the nest parameters' lower bound of 1e-16 are mapped), so settings in parameter units in control (nloptr's xtol_abs; optim's parscale, and pgtol, which then applies to the scaled gradient) apply to the scaled coordinates; "none" keeps the parameters' units. Coefficients are reported in natural units and the standard errors computed in them (for any choice but "none", with the information matrix equilibrated before it is inverted), so, where the likelihood is well identified and every choice reaches its maximum, reported quantities do not depend on this choice beyond the optimizer's tolerance.

Value

A choicer_nl object (inherits from choicer_fit). Standard S3 methods available: summary(), coef(), vcov(), logLik(), AIC(), BIC(), nobs().

Details

Two workflows are supported:

Convenience

Supply data and column names (including nest_col). Data preparation (prepare_nl_data) is handled automatically.

Advanced

Call prepare_nl_data (or build the input list manually) and pass it via input_data.

Column names

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.

Examples

# \donttest{
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))]
#>         id   alt         x1          x2
#>      <int> <int>      <num>       <num>
#>   1:     1     1  1.3709584  1.33491259
#>   2:     1     2 -0.5646982 -0.86927176
#>   3:     1     3  0.3631284  0.05548695
#>   4:     1     4  0.6328626  0.04906691
#>   5:     2     1  0.4042683 -0.57835573
#>  ---                                   
#> 396:    99     4  1.0965134 -1.07287540
#> 397:   100     1  0.4420131 -2.29297143
#> 398:   100     2  0.2410163 -1.20720685
#> 399:   100     3 -0.2556077  0.11410943
#> 400:   100     4  0.9310329 -1.03329708
dt[, nest := ifelse(alt <= 2, "A", "B")]
#>         id   alt         x1          x2   nest
#>      <int> <int>      <num>       <num> <char>
#>   1:     1     1  1.3709584  1.33491259      A
#>   2:     1     2 -0.5646982 -0.86927176      A
#>   3:     1     3  0.3631284  0.05548695      B
#>   4:     1     4  0.6328626  0.04906691      B
#>   5:     2     1  0.4042683 -0.57835573      A
#>  ---                                          
#> 396:    99     4  1.0965134 -1.07287540      B
#> 397:   100     1  0.4420131 -2.29297143      A
#> 398:   100     2  0.2410163 -1.20720685      A
#> 399:   100     3 -0.2556077  0.11410943      B
#> 400:   100     4  0.9310329 -1.03329708      B
dt[, choice := 0L]
#>         id   alt         x1          x2   nest choice
#>      <int> <int>      <num>       <num> <char>  <int>
#>   1:     1     1  1.3709584  1.33491259      A      0
#>   2:     1     2 -0.5646982 -0.86927176      A      0
#>   3:     1     3  0.3631284  0.05548695      B      0
#>   4:     1     4  0.6328626  0.04906691      B      0
#>   5:     2     1  0.4042683 -0.57835573      A      0
#>  ---                                                 
#> 396:    99     4  1.0965134 -1.07287540      B      0
#> 397:   100     1  0.4420131 -2.29297143      A      0
#> 398:   100     2  0.2410163 -1.20720685      A      0
#> 399:   100     3 -0.2556077  0.11410943      B      0
#> 400:   100     4  0.9310329 -1.03329708      B      0
dt[, choice := sample(c(1L, rep(0L, J - 1))), by = id]
#>         id   alt         x1          x2   nest choice
#>      <int> <int>      <num>       <num> <char>  <int>
#>   1:     1     1  1.3709584  1.33491259      A      1
#>   2:     1     2 -0.5646982 -0.86927176      A      0
#>   3:     1     3  0.3631284  0.05548695      B      0
#>   4:     1     4  0.6328626  0.04906691      B      0
#>   5:     2     1  0.4042683 -0.57835573      A      0
#>  ---                                                 
#> 396:    99     4  1.0965134 -1.07287540      B      0
#> 397:   100     1  0.4420131 -2.29297143      A      0
#> 398:   100     2  0.2410163 -1.20720685      A      0
#> 399:   100     3 -0.2556077  0.11410943      B      1
#> 400:   100     4  0.9310329 -1.03329708      B      0

fit <- run_nestlogit(
  data = dt, id_col = "id", alt_col = "alt", choice_col = "choice",
  covariate_cols = c("x1", "x2"), nest_col = "nest"
)
#> Optimization run time 0h:0m:0s
summary(fit)
#> Nested Logit (NL) model
#> 
#> Parameter    Estimate  Std.Error  z-value  Pr(>|z|)  
#> x1          -0.135699   0.188113  -0.7214  4.71e-01  
#> x2           0.295655   0.222668   1.3278  1.84e-01  
#> Lambda_1     6.296863  23.550214   0.2674  7.89e-01  
#> Lambda_2     1.640148   1.813470   0.9044  3.66e-01  
#> ASC_2       -2.778324  10.488956  -0.2649  7.91e-01  
#> ASC_3        2.033850  11.737696   0.1733  8.62e-01  
#> ASC_4        1.520384  11.782281   0.1290  8.97e-01  
#> ---
#> Signif. codes:  '***' 0.001 '**' 0.01 '*' 0.05
#> 
#> Std. Errors: Analytical Hessian 
#> Log-likelihood: -134.492 
#> AIC: 282.983  | BIC: 301.219 
#> McFadden R2: 0.030 (adj: -0.021) | Hit rate: 0.380 
#> N: 100  | Parameters: 7 
#> Optimization time: 0 s
#> Convergence: 1 ( NLOPT_SUCCESS: Generic success return value. )
# }