vincentarelbundock / marginaleffects

R package to compute and plot predictions, slopes, marginal means, and comparisons (contrasts, risk ratios, odds, etc.) for over 100 classes of statistical and ML models. Conduct linear and non-linear hypothesis tests, or equivalence tests. Calculate uncertainty estimates using the delta method, bootstrapping, or simulation-based inference
https://marginaleffects.com
Other
459 stars 47 forks source link

obtaining odds ratios for multinomial models #1254

Closed abduazizR closed 2 hours ago

abduazizR commented 2 hours ago

Hi

I am trying to use marginaleffects to get odds ratios and confidence intervals for mutlinomial logistic model created by nnet::multinom. I have 4 categories for the outcome variable, and three categories for the predictor. I am expecting the output to show ORs across the three levels of the predictor comparing each category of the outcome variable with the base level. However, marginal effects produce ORs for the 4 categories, which seems strange to me.

Below is an example

library(marginaleffects)
library(nnet)
library(tidyverse)

mtcars2 <- 
  mtcars |> 
  mutate(
    across(c(cyl, carb), as_factor)
  )

multinom(cyl ~ carb, data = mtcars2) |> 
  avg_comparisons(comparison = "lnor")
#> # weights:  21 (12 variable)
#> initial  value 35.155593 
#> iter  10 value 17.851169
#> iter  20 value 17.648332
#> final  value 17.648124 
#> converged
#> 
#>  Group              Contrast Estimate Std. Error         z Pr(>|z|)     S
#>      4 ln(odds(2) / odds(1))   -0.511   1.06e+00 -4.83e-01    0.629   0.7
#>      4 ln(odds(3) / odds(1))  -16.221   1.21e+03 -1.34e-02    0.989   0.0
#>      4 ln(odds(4) / odds(1))  -18.548   5.04e+02 -3.68e-02    0.971   0.0
#>      4 ln(odds(6) / odds(1))  -19.351   6.64e-04 -2.91e+04   <0.001   Inf
#>      4 ln(odds(8) / odds(1))  -15.408   1.40e+03 -1.10e-02    0.991   0.0
#>      6 ln(odds(2) / odds(1))  -18.302   2.58e-01 -7.09e+01   <0.001   Inf
#>      6 ln(odds(3) / odds(1))  -21.767   1.22e+03 -1.79e-02    0.986   0.0
#>      6 ln(odds(4) / odds(1))    0.511   1.06e+00  4.83e-01    0.629   0.7
#>      6 ln(odds(6) / odds(1))   19.351   8.37e-01  2.31e+01   <0.001 390.7
#>      6 ln(odds(8) / odds(1))  -22.143   1.40e+03 -1.58e-02    0.987   0.0
#>      8 ln(odds(2) / odds(1))   14.738   7.14e+02  2.06e-02    0.984   0.0
#>      8 ln(odds(3) / odds(1))   30.447   1.41e+03  2.17e-02    0.983   0.0
#>      8 ln(odds(4) / odds(1))   15.549   7.14e+02  2.18e-02    0.983   0.0
#>      8 ln(odds(6) / odds(1))  -24.402   5.98e-01 -4.08e+01   <0.001   Inf
#>      8 ln(odds(8) / odds(1))   29.635   1.57e+03  1.89e-02    0.985   0.0
#>     2.5 %  97.5 %
#>     -2.58    1.56
#>  -2396.94 2364.50
#>  -1007.10  970.00
#>    -19.35  -19.35
#>  -2762.56 2731.74
#>    -18.81  -17.80
#>  -2403.97 2360.43
#>     -1.56    2.58
#>     17.71   20.99
#>  -2769.81 2725.53
#>  -1384.78 1414.25
#>  -2723.36 2784.26
#>  -1383.96 1415.06
#>    -25.57  -23.23
#>  -3044.80 3104.07
#> 
#> Term: carb
#> Type:  probs 
#> Columns: term, group, contrast, estimate, std.error, statistic, p.value, s.value, conf.low, conf.high

Created on 2024-10-27 with reprex v2.1.1

I was expecting to see something like the following

library(marginaleffects)
library(nnet)
library(tidyverse)
library(broom)

mtcars2 <- 
  mtcars |> 
  mutate(
    across(c(cyl, carb), as_factor)
  )

multinom(cyl ~ carb, data = mtcars2) |> 
  tidy(exp = T, conf.int = T)
#> # weights:  21 (12 variable)
#> initial  value 35.155593 
#> iter  10 value 17.851169
#> iter  20 value 17.648332
#> final  value 17.648124 
#> converged
#> # A tibble: 12 × 8
#>    y.level term     estimate std.error statistic   p.value  conf.low   conf.high
#>    <chr>   <chr>       <dbl>     <dbl>     <dbl>     <dbl>     <dbl>       <dbl>
#>  1 6       (Interc… 4.00e- 1   8.37e-1  -1.10e+0 2.73e-  1 7.76e-  2   2.06e+  0
#>  2 6       carb2    1.88e- 8   2.50e-5  -7.11e+5 0         1.88e-  8   1.88e-  8
#>  3 6       carb3    1.56e- 3   8.78e-1  -7.36e+0 1.82e- 13 2.79e-  4   8.72e-  3
#>  4 6       carb4    4.54e+ 7   5.04e+2   3.50e-2 9.72e-  1 0         Inf        
#>  5 6       carb6    2.54e+ 8   3.97e-6   4.87e+6 0         2.54e+  8   2.54e+  8
#>  6 6       carb8    4.76e- 4   2.98e-1  -2.56e+1 5.28e-145 2.65e-  4   8.54e-  4
#>  7 8       (Interc… 3.71e- 7   7.14e+2  -2.07e-2 9.83e-  1 0         Inf        
#>  8 8       carb2    1.80e+ 6   7.14e+2   2.02e-2 9.84e-  1 0         Inf        
#>  9 8       carb3    1.19e+13   1.41e+3   2.14e-2 9.83e-  1 0         Inf        
#> 10 8       carb4    7.35e+13   2.36e+2   1.35e-1 8.92e-  1 1.28e-187   4.23e+214
#> 11 8       carb6    1.83e- 3   1.27e-8  -4.95e+8 0         1.83e-  3   1.83e-  3
#> 12 8       carb8    5.30e+12   1.57e+3   1.87e-2 9.85e-  1 0         Inf

Created on 2024-10-27 with reprex v2.1.1

Is there something I am missing here?

Thanks

vincentarelbundock commented 2 hours ago

Some of the estimates are just -1 another estimate. You can just ignore those.

Closing because this is not a bug report of feature request.