easystats/parameters

Support `nestedLogit`

vincentarelbundock opened this issue · 3 comments

Would it be possible to support nestedLogit models in parameters?

Fit model:

library(nestedLogit)
data(Womenlf, package = "carData")

comparisons <- logits(
    work = dichotomy("not.work", working = c("parttime", "fulltime")),
    full = dichotomy("parttime", "fulltime"))

m <- nestedLogit(
    partic ~ hincome + children,
    dichotomies = comparisons,
    data = Womenlf)

The m object includes a list of glm objects stored in m$models. When we call summary(m), the nestedLogit package returns the summary of each glm object one after the other. This is equivalent to calling:

lapply(m$models, parameters::parameters)
# $work
# Parameter          | Log-Odds |   SE |         95% CI |     z |      p
# ----------------------------------------------------------------------
# (Intercept)        |     1.34 | 0.38 | [ 0.61,  2.12] |  3.48 | < .001
# hincome            |    -0.04 | 0.02 | [-0.08,  0.00] | -2.14 | 0.032 
# children [present] |    -1.58 | 0.29 | [-2.16, -1.01] | -5.39 | < .001
# 
# Uncertainty intervals (profile-likelihood) and p-values (two-tailed)
#   computed using a Wald z-distribution approximation.
# 
# The model has a log- or logit-link. Consider using `exponentiate =
#   TRUE` to interpret coefficients as ratios.
# 
# $full
# Parameter          | Log-Odds |   SE |         95% CI |     z |      p
# ----------------------------------------------------------------------
# (Intercept)        |     3.48 | 0.77 | [ 2.11,  5.14] |  4.53 | < .001
# hincome            |    -0.11 | 0.04 | [-0.19, -0.04] | -2.74 | 0.006 
# children [present] |    -2.65 | 0.54 | [-3.80, -1.66] | -4.90 | < .001
# 
# Uncertainty intervals (profile-likelihood) and p-values (two-tailed)
#   computed using a Wald z-distribution approximation.

Note that the m$models list of models has informative names:

names(m$models)
# [1] "work" "full"

How are these types of models handled in parameters normally? Ideally, I think we would bind each parameters data frame into a single one, with a new column to identify the model names.

Is there an existing example of this approach somewhere?

I'm not sure, we have methods for lm(cbind(), ...) or crch:
https://github.com/easystats/parameters/blob/3bc6d1bd1a7d4109cbb067bedf82fa4fd224f653/R/methods_crch.R

Maybe in that direction?

library(nestedLogit)
library(parameters)

data(Womenlf, package = "carData")

comparisons <- logits(
  work = dichotomy("not.work", working = c("parttime", "fulltime")),
  full = dichotomy("parttime", "fulltime")
)

m <- nestedLogit(
  partic ~ hincome + children,
  dichotomies = comparisons,
  data = Womenlf
)

model_parameters(m)
#> # {not.work} vs. {parttime, fulltime} response
#> 
#> Parameter          | Log-Odds |   SE |         95% CI |     z |      p
#> ----------------------------------------------------------------------
#> (Intercept)        |     1.34 | 0.38 | [ 0.61,  2.12] |  3.48 | < .001
#> hincome            |    -0.04 | 0.02 | [-0.08,  0.00] | -2.14 | 0.032 
#> children [present] |    -1.58 | 0.29 | [-2.16, -1.01] | -5.39 | < .001
#> 
#> # {parttime} vs. {fulltime} response
#> 
#> Parameter          | Log-Odds |   SE |         95% CI |     z |      p
#> ----------------------------------------------------------------------
#> (Intercept)        |     3.48 | 0.77 | [ 2.11,  5.14] |  4.53 | < .001
#> hincome            |    -0.11 | 0.04 | [-0.19, -0.04] | -2.74 | 0.006 
#> children [present] |    -2.65 | 0.54 | [-3.80, -1.66] | -4.90 | < .001
#> 
#> Uncertainty intervals (profile-likelihood) and p-values (two-tailed)
#>   computed using a Wald z-distribution approximation.
#> 
#> The model has a log- or logit-link. Consider using `exponentiate =
#>   TRUE` to interpret coefficients as ratios.

model_parameters(m, ci_method = "wald")
#> # {not.work} vs. {parttime, fulltime} response
#> 
#> Parameter          | Log-Odds |   SE |         95% CI |     z |      p
#> ----------------------------------------------------------------------
#> (Intercept)        |     1.34 | 0.38 | [ 0.58,  2.09] |  3.48 | < .001
#> hincome            |    -0.04 | 0.02 | [-0.08,  0.00] | -2.14 | 0.032 
#> children [present] |    -1.58 | 0.29 | [-2.15, -1.00] | -5.39 | < .001
#> 
#> # {parttime} vs. {fulltime} response
#> 
#> Parameter          | Log-Odds |   SE |         95% CI |     z |      p
#> ----------------------------------------------------------------------
#> (Intercept)        |     3.48 | 0.77 | [ 1.97,  4.98] |  4.53 | < .001
#> hincome            |    -0.11 | 0.04 | [-0.18, -0.03] | -2.74 | 0.006 
#> children [present] |    -2.65 | 0.54 | [-3.71, -1.59] | -4.90 | < .001
#> 
#> Uncertainty intervals (equal-tailed) and p-values (two-tailed) computed
#>   using a Wald z-distribution approximation.

model_parameters(m, vcov = "HC3")
#> # {not.work} vs. {parttime, fulltime} response
#> 
#> Parameter          | Log-Odds |   SE |         95% CI |     z |      p
#> ----------------------------------------------------------------------
#> (Intercept)        |     1.34 | 0.42 | [ 0.52,  2.15] |  3.20 | 0.001 
#> hincome            |    -0.04 | 0.02 | [-0.09,  0.00] | -1.88 | 0.061 
#> children [present] |    -1.58 | 0.30 | [-2.16, -1.00] | -5.33 | < .001
#> 
#> # {parttime} vs. {fulltime} response
#> 
#> Parameter          | Log-Odds |   SE |         95% CI |     z |      p
#> ----------------------------------------------------------------------
#> (Intercept)        |     3.48 | 0.76 | [ 1.98,  4.98] |  4.55 | < .001
#> hincome            |    -0.11 | 0.04 | [-0.18, -0.03] | -2.88 | 0.004 
#> children [present] |    -2.65 | 0.56 | [-3.75, -1.55] | -4.72 | < .001
#> 
#> Uncertainty intervals (equal-tailed) and p-values (two-tailed) computed
#>   using a Wald z-distribution approximation.

model_parameters(m, exponentiate = TRUE)
#> # {not.work} vs. {parttime, fulltime} response
#> 
#> Parameter          | Odds Ratio |   SE |       95% CI |     z |      p
#> ----------------------------------------------------------------------
#> (Intercept)        |       3.80 | 1.46 | [1.83, 8.29] |  3.48 | < .001
#> hincome            |       0.96 | 0.02 | [0.92, 1.00] | -2.14 | 0.032 
#> children [present] |       0.21 | 0.06 | [0.12, 0.36] | -5.39 | < .001
#> 
#> # {parttime} vs. {fulltime} response
#> 
#> Parameter          | Odds Ratio |    SE |         95% CI |     z |      p
#> -------------------------------------------------------------------------
#> (Intercept)        |      32.39 | 24.84 | [8.26, 171.34] |  4.53 | < .001
#> hincome            |       0.90 |  0.04 | [0.83,   0.97] | -2.74 | 0.006 
#> children [present] |       0.07 |  0.04 | [0.02,   0.19] | -4.90 | < .001
#> 
#> Uncertainty intervals (profile-likelihood) and p-values (two-tailed)
#>   computed using a Wald z-distribution approximation.

model_parameters(m) |> as.data.frame()
#>         Parameter Coefficient         SE   CI      CI_low      CI_high
#> 1     (Intercept)  1.33582979 0.38376323 0.95  0.60590835  2.115336975
#> 2         hincome -0.04230843 0.01978012 0.95 -0.08225743 -0.004471769
#> 3 childrenpresent -1.57564843 0.29226284 0.95 -2.16143847 -1.012720928
#> 4     (Intercept)  3.47777346 0.76710910 0.95  2.11086529  5.143653414
#> 5         hincome -0.10726786 0.03915231 0.95 -0.18920584 -0.035088050
#> 6 childrenpresent -2.65145569 0.54107504 0.95 -3.80274064 -1.657253408
#>           z df_error            p Component                            Response
#> 1  3.480870      Inf 4.997885e-04      work {not.work} vs. {parttime, fulltime}
#> 2 -2.138937      Inf 3.244074e-02      work {not.work} vs. {parttime, fulltime}
#> 3 -5.391204      Inf 6.998736e-08      work {not.work} vs. {parttime, fulltime}
#> 4  4.533610      Inf 5.798406e-06      full           {parttime} vs. {fulltime}
#> 5 -2.739758      Inf 6.148445e-03      full           {parttime} vs. {fulltime}
#> 6 -4.900347      Inf 9.566732e-07      full           {parttime} vs. {fulltime}




model_parameters(m, component = "work")
#> # Fixed Effects
#> 
#> Parameter          | Log-Odds |   SE |         95% CI |     z |      p
#> ----------------------------------------------------------------------
#> (Intercept)        |     1.34 | 0.38 | [ 0.61,  2.12] |  3.48 | < .001
#> hincome            |    -0.04 | 0.02 | [-0.08,  0.00] | -2.14 | 0.032 
#> children [present] |    -1.58 | 0.29 | [-2.16, -1.01] | -5.39 | < .001
#> 
#> Uncertainty intervals (profile-likelihood) and p-values (two-tailed)
#>   computed using a Wald z-distribution approximation.

model_parameters(m, ci_method = "wald", component = "work")
#> # Fixed Effects
#> 
#> Parameter          | Log-Odds |   SE |         95% CI |     z |      p
#> ----------------------------------------------------------------------
#> (Intercept)        |     1.34 | 0.38 | [ 0.58,  2.09] |  3.48 | < .001
#> hincome            |    -0.04 | 0.02 | [-0.08,  0.00] | -2.14 | 0.032 
#> children [present] |    -1.58 | 0.29 | [-2.15, -1.00] | -5.39 | < .001
#> 
#> Uncertainty intervals (equal-tailed) and p-values (two-tailed) computed
#>   using a Wald z-distribution approximation.

model_parameters(m, vcov = "HC3", component = "work")
#> # Fixed Effects
#> 
#> Parameter          | Log-Odds |   SE |         95% CI |     z |      p
#> ----------------------------------------------------------------------
#> (Intercept)        |     1.34 | 0.42 | [ 0.52,  2.15] |  3.20 | 0.001 
#> hincome            |    -0.04 | 0.02 | [-0.09,  0.00] | -1.88 | 0.061 
#> children [present] |    -1.58 | 0.30 | [-2.16, -1.00] | -5.33 | < .001
#> 
#> Uncertainty intervals (equal-tailed) and p-values (two-tailed) computed
#>   using a Wald z-distribution approximation.

model_parameters(m, exponentiate = TRUE, component = "work")
#> # Fixed Effects
#> 
#> Parameter          | Odds Ratio |   SE |       95% CI |     z |      p
#> ----------------------------------------------------------------------
#> (Intercept)        |       3.80 | 1.46 | [1.83, 8.29] |  3.48 | < .001
#> hincome            |       0.96 | 0.02 | [0.92, 1.00] | -2.14 | 0.032 
#> children [present] |       0.21 | 0.06 | [0.12, 0.36] | -5.39 | < .001
#> 
#> Uncertainty intervals (profile-likelihood) and p-values (two-tailed)
#>   computed using a Wald z-distribution approximation.

model_parameters(m, component = "work") |> as.data.frame()
#>         Parameter Coefficient         SE   CI      CI_low      CI_high
#> 1     (Intercept)  1.33582979 0.38376323 0.95  0.60590835  2.115336975
#> 2         hincome -0.04230843 0.01978012 0.95 -0.08225743 -0.004471769
#> 3 childrenpresent -1.57564843 0.29226284 0.95 -2.16143847 -1.012720928
#>           z df_error            p                            Response
#> 1  3.480870      Inf 4.997885e-04 {not.work} vs. {parttime, fulltime}
#> 2 -2.138937      Inf 3.244074e-02 {not.work} vs. {parttime, fulltime}
#> 3 -5.391204      Inf 6.998736e-08 {not.work} vs. {parttime, fulltime}

Created on 2023-05-22 with reprex v2.0.2

This is awesome! Thanks so much @strengejacke