web stats
Making tables for multinomial models with {modelsummary} and {brms} | Michael E Flynn - Political Science

Making tables for multinomial models with {modelsummary} and {brms}

tl;dr: Learn how to make some cool and customizable tables for multinomial logit models using {brms} and {modelsummary}.

UPDATE: Vincent informed me that the most recent version of {modelsummary} relies entirely on the {parameters} package. Apparently the {broom} package will no longer be actively developing. Keep this in mind if you’re trying this approach and get stuck.

Background

I’m coming off a couple of long projects where we were using a lot of multinomial logit models, and making publication quality tables was a major challenge. Actually, started using {brms} several years ago partly because I had data where we had 1) lots of individuals making choices, 2) those individuals were all grouped in some pretty clear ways, and 3) we were also interested in modeling group-level characteristics that might relate to individuals' choices. This more or less marked my full transition from Stata to R and from frequentist stats to Bayesian stats.

Early on the biggest problem I ran into was finding a way to generate tables for multinomial models run using {brms}. Initially most packages didn’t support {brms} and/or developing tables for multilevel/hierarchical models required a lot of extra legwork. Building tables to accommodate choice models was another issue. Taken together, these problems meant that I had to write a lot of extensive code by hand to generate clean Latex tables for the models I was using. The process has, thankfully, become much simpler over the last couple of years.

First, for those who aren’t familiar {brms} is an amazing package created by Paul Bürkner. It stands for Bayesian Regression Modeling using Stan, and, as the name suggests, provides users with a convenient front-end for building regression models using Stan as a back end. This is particularly useful for building multilevel models, but also lots of other stuff.

Second, {modelsummary} is another amazing and ever-expanding package created by Vincent Arel-Bundock. This packages does a few different things, but most importantly and prominently it helps users to create excellent tables for summarizing data and building tables for regression output. The package is incredibly flexible, supports dozens of different model types, and Vincent is constantly adding new features.

Both packages are fantastic. If you’re interested in Bayesian modeling, or just looking for a new and easy way to build tables for whatever modeling package you already use, you should check out one or both of these packages.

Multilevel Multinomial Logit Models

Lots of regression models are going to be fairly simple to present in a table format, and there are some fairly easy ways to go about generating those tables. Typically you’ll have a single column per model, and each row of your table will be for a single variable. You might also have some summary statistics for the model at the bottom (think $ N $, $ R^2 $, etc.).

Multinomial models get a little more complicated because you’ll typically have multiple outcomes. Specifically, you’ll have $k-1 $ columns to present in the table, where $k $ is the number of choices respondents have. In our case we had lots of models where survey respondents offered their assessments of various actors and we condensed those assessments down into four general categories: Positive, Neutral, Negative, and Don’t Know. This means we ultimately ended up with three columns per model, with the “Neutral” response serving as the baseline category against which the others were compared.

Multilevel models complicate things slightly because you may also have summary statistics for the groups in your data in addition to the general summary statistics for the model.

Last, Bayesian models and {brms} specifically provide users with a ton of additional information they might want to present beyond the traditional stuff you’d find in frequentist models. Some of this information can take a long time to compile. There’s often going to be an efficiency and transparency tradeoff here, and so you may want to customize what you present in your table. Even if you end up presenting lots of information in the end, having the ability to control what’s in your table at the outset can be really useful as you run the code to make sure the basic output looks right.

Anyway, the goal here is rather niche, but it’s to talk through the process of building nice and readable tables when we’re using these models and have lots of information to present. {modelsummary} lets us do this, but also requires a bit of additional effort to fully customize our output.

Getting Started

OK, first we’re going to load our libraries. The relevance of some of these is immediately obvious given what I’ve already said, but I’ll talk more about some of the additional packages we need below.

# Load libraries
library(tidyverse)
library(here)
library(modelsummary)
library(brms)
library(parameters)
library(kableExtra)
library(broom)
library(broom.mixed)

In addition to loading the libraries we want to load our model objects. In this case I have three models, each with three outcome categories. Each of these ends with a “p1” or a “t1” to denote the reference group for the model’s outcome variable (e.g. if the outcome variable is asking about troops, people, or government).

Then I’m creating a list object to store the three model objects. Note here that I’m leaving the label for the individual models blank by including the empty quotation marks in the list function. Depending on your situation you can go ahead and name these if you want. In my case it makes more sense to keep them empty because I plan to add a grouping header/title later in the final table and based on how {modelsummary} works including the titles here would create some redundancies in the final output and take up extra horizontal space. If you’re working with HTML output and you have scrollable tables maybe this doesn’t matter, but it can matter a lot for print versions..

# Load brms model objects
m.c.t1 <- readRDS(here::here("static/files/data-files/m.c.t1.rds"))
m.c.p1 <- readRDS(here::here("static/files/data-files/m.c.p1.rds"))
m.c.g1 <- readRDS(here::here("static/files/data-files/m.c.g1.rds"))


# Create a list object to store the three separate model objects.
mod.list <- list(" " = m.c.t1,
                 " " = m.c.p1,
                 " " = m.c.g1)

Before we move on, let’s take a quick look at the models and what they look like.

summary(mod.list[[1]])
##  Family: categorical 
##   Links: mudk = logit; muneg = logit; mupos = logit 
## Formula: troops_1_cat ~ contact_pers + contact_nonpers + benefit_pers + benefit_nonpers + age + ed_z + ideology_z + income.5.cat + gender + minority + relig + troops_crime_pers + american_inf_1 + american_inf_2 + basecount_z + gdp_z + pop_z + troops_z + (1 | r | country) 
##    Data: o.data (Number of observations: 38626) 
##   Draws: 4 chains, each with iter = 8000; warmup = 4000; thin = 1;
##          total post-warmup draws = 16000
## 
## Group-Level Effects: 
## ~country (Number of levels: 14) 
##                                      Estimate Est.Error l-95% CI u-95% CI Rhat
## sd(mudk_Intercept)                       0.51      0.14     0.30     0.83 1.00
## sd(muneg_Intercept)                      0.83      0.20     0.53     1.31 1.00
## sd(mupos_Intercept)                      0.57      0.15     0.35     0.94 1.00
## cor(mudk_Intercept,muneg_Intercept)      0.57      0.22     0.05     0.88 1.00
## cor(mudk_Intercept,mupos_Intercept)     -0.48      0.24    -0.84     0.08 1.00
## cor(muneg_Intercept,mupos_Intercept)    -0.15      0.27    -0.63     0.40 1.00
##                                      Bulk_ESS Tail_ESS
## sd(mudk_Intercept)                       8625    10276
## sd(muneg_Intercept)                      8585    10729
## sd(mupos_Intercept)                      7977     9513
## cor(mudk_Intercept,muneg_Intercept)      8920    10405
## cor(mudk_Intercept,mupos_Intercept)      8157    11321
## cor(muneg_Intercept,mupos_Intercept)    10970    11879
## 
## Population-Level Effects: 
##                                                 Estimate Est.Error l-95% CI
## mudk_Intercept                                     -2.21      0.20    -2.62
## muneg_Intercept                                    -0.46      0.24    -0.94
## mupos_Intercept                                    -0.24      0.18    -0.58
## mudk_contact_persDontknowDdeclinetoanswer           0.50      0.13     0.23
## mudk_contact_persYes                               -0.61      0.17    -0.94
## mudk_contact_nonpersDontknowDdeclinetoanswer       -0.39      0.12    -0.64
## mudk_contact_nonpersYes                            -0.72      0.15    -1.02
## mudk_benefit_persDontknowDdeclinetoanswer           0.48      0.11     0.26
## mudk_benefit_persYes                               -0.59      0.22    -1.05
## mudk_benefit_nonpersDontknowDdeclinetoanswer        0.25      0.11     0.03
## mudk_benefit_nonpersYes                            -0.55      0.22    -1.00
## mudk_age25to34years                                -0.12      0.07    -0.26
## mudk_age35to44years                                -0.26      0.08    -0.41
## mudk_age45to54years                                -0.31      0.08    -0.46
## mudk_age55to64years                                -0.59      0.09    -0.76
## mudk_ageAge65orolder                               -0.78      0.10    -0.98
## mudk_ed_z                                          -0.04      0.06    -0.16
## mudk_ideology_z                                    -0.21      0.07    -0.34
## mudk_income.5.cat21M40%                            -0.18      0.08    -0.34
## mudk_income.5.cat41M60%                            -0.07      0.08    -0.23
## mudk_income.5.cat61M80%                            -0.33      0.10    -0.52
## mudk_income.5.cat81M100%                           -0.42      0.11    -0.63
## mudk_genderFemale                                   0.38      0.05     0.28
## mudk_genderNonMbinary                              -1.52      1.36    -4.92
## mudk_genderNoneoftheabove                           0.19      0.56    -0.95
## mudk_minorityYes                                   -0.12      0.09    -0.30
## mudk_minorityDeclinetoanswer                        0.53      0.11     0.31
## mudk_religBuddhism                                  0.09      0.18    -0.27
## mudk_religCatholicism                               0.06      0.08    -0.10
## mudk_religChristianityprotestant                    0.09      0.11    -0.14
## mudk_religDeclinetoanswer                           0.24      0.09     0.06
## mudk_religHinduism                                  0.01      0.35    -0.72
## mudk_religIslam                                     0.04      0.14    -0.25
## mudk_religJudaism                                   0.75      0.37     0.01
## mudk_religLocal                                    -0.68      0.46    -1.63
## mudk_religLocalreligion                            -0.17      0.35    -0.88
## mudk_religMormonism                               -91.22     51.29  -202.31
## mudk_religOther                                     0.17      0.09    -0.01
## mudk_religProtestant                                0.04      0.12    -0.20
## mudk_religShinto                                  -88.49     50.35  -196.62
## mudk_troops_crime_persYes                          -0.22      0.32    -0.89
## mudk_troops_crime_persDontknowDdeclinetoanswer      0.24      0.14    -0.03
## mudk_american_inf_1DontknowDdeclinetoanswer         0.44      0.13     0.20
## mudk_american_inf_1Alittle                         -0.33      0.12    -0.56
## mudk_american_inf_1Some                            -0.21      0.11    -0.42
## mudk_american_inf_1Alot                            -0.29      0.12    -0.52
## mudk_american_inf_2DontknowDdeclinetoanswer         1.90      0.08     1.74
## mudk_american_inf_2Verynegative                     0.62      0.14     0.35
## mudk_american_inf_2Negative                         0.28      0.07     0.14
## mudk_american_inf_2Positive                         0.00      0.09    -0.16
## mudk_american_inf_2Verypositive                     0.62      0.20     0.22
## mudk_basecount_z                                    0.09      0.07    -0.05
## mudk_gdp_z                                          0.82      0.49    -0.18
## mudk_pop_z                                         -0.20      0.37    -0.91
## mudk_troops_z                                      -0.66      0.50    -1.60
## muneg_contact_persDontknowDdeclinetoanswer          0.04      0.11    -0.17
## muneg_contact_persYes                               0.16      0.06     0.05
## muneg_contact_nonpersDontknowDdeclinetoanswer       0.01      0.08    -0.13
## muneg_contact_nonpersYes                            0.09      0.05    -0.01
## muneg_benefit_persDontknowDdeclinetoanswer         -0.44      0.10    -0.62
## muneg_benefit_persYes                              -0.50      0.09    -0.68
## muneg_benefit_nonpersDontknowDdeclinetoanswer      -0.38      0.08    -0.54
## muneg_benefit_nonpersYes                           -0.26      0.08    -0.41
## muneg_age25to34years                                0.09      0.04     0.01
## muneg_age35to44years                               -0.01      0.04    -0.09
## muneg_age45to54years                               -0.11      0.04    -0.20
## muneg_age55to64years                               -0.19      0.05    -0.28
## muneg_ageAge65orolder                              -0.07      0.05    -0.17
## muneg_ed_z                                          0.16      0.03     0.09
## muneg_ideology_z                                   -0.24      0.03    -0.31
## muneg_income.5.cat21M40%                           -0.06      0.05    -0.15
## muneg_income.5.cat41M60%                            0.00      0.05    -0.09
## muneg_income.5.cat61M80%                           -0.03      0.05    -0.13
## muneg_income.5.cat81M100%                           0.04      0.05    -0.07
## muneg_genderFemale                                 -0.03      0.03    -0.08
## muneg_genderNonMbinary                              0.41      0.30    -0.18
## muneg_genderNoneoftheabove                         -0.48      0.47    -1.42
## muneg_minorityYes                                   0.04      0.05    -0.04
## muneg_minorityDeclinetoanswer                      -0.10      0.09    -0.28
## muneg_religBuddhism                                -0.22      0.08    -0.37
## muneg_religCatholicism                             -0.42      0.04    -0.51
## muneg_religChristianityprotestant                  -0.46      0.06    -0.58
## muneg_religDeclinetoanswer                         -0.25      0.06    -0.36
## muneg_religHinduism                                -0.21      0.22    -0.65
## muneg_religIslam                                    0.29      0.08     0.13
## muneg_religJudaism                                 -0.05      0.28    -0.62
## muneg_religLocal                                   -0.37      0.20    -0.76
## muneg_religLocalreligion                           -0.34      0.20    -0.74
## muneg_religMormonism                               -0.21      0.41    -1.03
## muneg_religOther                                   -0.16      0.05    -0.25
## muneg_religProtestant                              -0.39      0.06    -0.52
## muneg_religShinto                                  -0.28      0.23    -0.74
## muneg_troops_crime_persYes                         -0.13      0.13    -0.40
## muneg_troops_crime_persDontknowDdeclinetoanswer    -0.34      0.13    -0.60
## muneg_american_inf_1DontknowDdeclinetoanswer       -0.82      0.10    -1.02
## muneg_american_inf_1Alittle                        -0.30      0.07    -0.44
## muneg_american_inf_1Some                           -0.17      0.07    -0.30
## muneg_american_inf_1Alot                            0.13      0.07    -0.01
## muneg_american_inf_2DontknowDdeclinetoanswer        0.38      0.08     0.22
## muneg_american_inf_2Verynegative                    1.97      0.06     1.85
## muneg_american_inf_2Negative                        1.14      0.03     1.07
## muneg_american_inf_2Positive                       -0.28      0.05    -0.37
## muneg_american_inf_2Verypositive                   -0.21      0.12    -0.44
## muneg_basecount_z                                   0.07      0.04     0.00
## muneg_gdp_z                                        -0.80      0.55    -1.90
## muneg_pop_z                                         0.63      0.53    -0.47
## muneg_troops_z                                      0.60      0.67    -0.66
## mupos_contact_persDontknowDdeclinetoanswer         -0.31      0.09    -0.50
## mupos_contact_persYes                               0.48      0.05     0.39
## mupos_contact_nonpersDontknowDdeclinetoanswer       0.08      0.06    -0.04
## mupos_contact_nonpersYes                            0.27      0.04     0.18
## mupos_benefit_persDontknowDdeclinetoanswer         -0.17      0.08    -0.32
## mupos_benefit_persYes                               0.05      0.06    -0.07
## mupos_benefit_nonpersDontknowDdeclinetoanswer      -0.09      0.07    -0.22
## mupos_benefit_nonpersYes                            0.38      0.06     0.27
## mupos_age25to34years                               -0.11      0.04    -0.19
## mupos_age35to44years                               -0.08      0.04    -0.16
## mupos_age45to54years                               -0.05      0.04    -0.13
## mupos_age55to64years                                0.11      0.04     0.03
## mupos_ageAge65orolder                               0.19      0.04     0.11
## mupos_ed_z                                          0.03      0.03    -0.02
## mupos_ideology_z                                    0.38      0.03     0.32
## mupos_income.5.cat21M40%                           -0.03      0.04    -0.12
## mupos_income.5.cat41M60%                            0.01      0.04    -0.07
## mupos_income.5.cat61M80%                           -0.01      0.04    -0.10
## mupos_income.5.cat81M100%                           0.06      0.05    -0.03
## mupos_genderFemale                                 -0.22      0.02    -0.27
## mupos_genderNonMbinary                             -0.18      0.23    -0.63
## mupos_genderNoneoftheabove                         -0.68      0.39    -1.46
## mupos_minorityYes                                  -0.05      0.04    -0.13
## mupos_minorityDeclinetoanswer                      -0.06      0.08    -0.22
## mupos_religBuddhism                                 0.06      0.07    -0.07
## mupos_religCatholicism                              0.15      0.04     0.07
## mupos_religChristianityprotestant                   0.13      0.05     0.03
## mupos_religDeclinetoanswer                         -0.15      0.05    -0.26
## mupos_religHinduism                                -0.23      0.14    -0.51
## mupos_religIslam                                   -0.17      0.07    -0.31
## mupos_religJudaism                                  0.18      0.15    -0.11
## mupos_religLocal                                   -0.18      0.17    -0.52
## mupos_religLocalreligion                           -0.21      0.16    -0.51
## mupos_religMormonism                                0.47      0.33    -0.17
## mupos_religOther                                   -0.12      0.05    -0.21
## mupos_religProtestant                               0.25      0.05     0.15
## mupos_religShinto                                  -0.03      0.20    -0.41
## mupos_troops_crime_persYes                         -0.11      0.09    -0.28
## mupos_troops_crime_persDontknowDdeclinetoanswer    -0.55      0.11    -0.77
## mupos_american_inf_1DontknowDdeclinetoanswer       -0.35      0.10    -0.54
## mupos_american_inf_1Alittle                         0.04      0.07    -0.09
## mupos_american_inf_1Some                            0.19      0.06     0.06
## mupos_american_inf_1Alot                            0.53      0.07     0.40
## mupos_american_inf_2DontknowDdeclinetoanswer       -0.27      0.08    -0.42
## mupos_american_inf_2Verynegative                   -0.57      0.08    -0.73
## mupos_american_inf_2Negative                       -0.33      0.03    -0.40
## mupos_american_inf_2Positive                        1.24      0.03     1.18
## mupos_american_inf_2Verypositive                    1.94      0.07     1.81
## mupos_basecount_z                                   0.02      0.03    -0.04
## mupos_gdp_z                                         0.41      0.47    -0.46
## mupos_pop_z                                        -0.20      0.39    -1.04
## mupos_troops_z                                     -0.76      0.51    -1.80
##                                                 u-95% CI Rhat Bulk_ESS Tail_ESS
## mudk_Intercept                                     -1.82 1.00     9965    11260
## muneg_Intercept                                     0.02 1.00     7614     9735
## mupos_Intercept                                     0.12 1.00     9111    10223
## mudk_contact_persDontknowDdeclinetoanswer           0.76 1.00    28898    12459
## mudk_contact_persYes                               -0.28 1.00    35071    12285
## mudk_contact_nonpersDontknowDdeclinetoanswer       -0.15 1.00    31078    12476
## mudk_contact_nonpersYes                            -0.43 1.00    36906    12402
## mudk_benefit_persDontknowDdeclinetoanswer           0.69 1.00    32950    12049
## mudk_benefit_persYes                               -0.17 1.00    35339    12214
## mudk_benefit_nonpersDontknowDdeclinetoanswer        0.47 1.00    32827    12413
## mudk_benefit_nonpersYes                            -0.13 1.00    31219    12371
## mudk_age25to34years                                 0.03 1.00    24495    13948
## mudk_age35to44years                                -0.11 1.00    25225    13106
## mudk_age45to54years                                -0.15 1.00    24303    13303
## mudk_age55to64years                                -0.42 1.00    24857    12792
## mudk_ageAge65orolder                               -0.58 1.00    28255    13715
## mudk_ed_z                                           0.08 1.00    33506    12754
## mudk_ideology_z                                    -0.08 1.00    33194    12144
## mudk_income.5.cat21M40%                            -0.01 1.00    22824    13682
## mudk_income.5.cat41M60%                             0.09 1.00    19412    14131
## mudk_income.5.cat61M80%                            -0.14 1.00    20502    12789
## mudk_income.5.cat81M100%                           -0.21 1.00    22830    13131
## mudk_genderFemale                                   0.49 1.00    33841    10953
## mudk_genderNonMbinary                               0.49 1.00    20464     8210
## mudk_genderNoneoftheabove                           1.24 1.00    33952    11270
## mudk_minorityYes                                    0.05 1.00    32060    12384
## mudk_minorityDeclinetoanswer                        0.74 1.00    28095    13069
## mudk_religBuddhism                                  0.43 1.00    26888    11973
## mudk_religCatholicism                               0.23 1.00    18539    13734
## mudk_religChristianityprotestant                    0.31 1.00    18774    13720
## mudk_religDeclinetoanswer                           0.42 1.00    18677    13477
## mudk_religHinduism                                  0.67 1.00    34397    11772
## mudk_religIslam                                     0.32 1.00    18499    12850
## mudk_religJudaism                                   1.45 1.00    32645    11069
## mudk_religLocal                                     0.16 1.00    32044    11584
## mudk_religLocalreligion                             0.47 1.00    34222    12600
## mudk_religMormonism                                -9.58 1.00    24158    13289
## mudk_religOther                                     0.36 1.00    19821    12970
## mudk_religProtestant                                0.28 1.00    27632    11675
## mudk_religShinto                                   -7.75 1.00    19564    11761
## mudk_troops_crime_persYes                           0.38 1.00    32686    12782
## mudk_troops_crime_persDontknowDdeclinetoanswer      0.51 1.00    31428    12367
## mudk_american_inf_1DontknowDdeclinetoanswer         0.69 1.00    15559    13814
## mudk_american_inf_1Alittle                         -0.09 1.00    13818    13275
## mudk_american_inf_1Some                             0.01 1.00    12912    12654
## mudk_american_inf_1Alot                            -0.05 1.00    13781    12670
## mudk_american_inf_2DontknowDdeclinetoanswer         2.06 1.00    28532    13094
## mudk_american_inf_2Verynegative                     0.89 1.00    31676    12350
## mudk_american_inf_2Negative                         0.41 1.00    30795    12359
## mudk_american_inf_2Positive                         0.17 1.00    32015    11768
## mudk_american_inf_2Verypositive                     1.00 1.00    34404    12569
## mudk_basecount_z                                    0.23 1.00    31930    11766
## mudk_gdp_z                                          1.75 1.00     7257    10182
## mudk_pop_z                                          0.55 1.00     8368     9894
## mudk_troops_z                                       0.38 1.00     7180     9511
## muneg_contact_persDontknowDdeclinetoanswer          0.24 1.00    31677    13165
## muneg_contact_persYes                               0.27 1.00    29413    13303
## muneg_contact_nonpersDontknowDdeclinetoanswer       0.16 1.00    30181    12663
## muneg_contact_nonpersYes                            0.20 1.00    29722    12561
## muneg_benefit_persDontknowDdeclinetoanswer         -0.25 1.00    31796    12788
## muneg_benefit_persYes                              -0.31 1.00    29760    12683
## muneg_benefit_nonpersDontknowDdeclinetoanswer      -0.22 1.00    28191    12601
## muneg_benefit_nonpersYes                           -0.10 1.00    30794    13592
## muneg_age25to34years                                0.18 1.00    19021    14170
## muneg_age35to44years                                0.08 1.00    17918    13604
## muneg_age45to54years                               -0.02 1.00    17885    13006
## muneg_age55to64years                               -0.10 1.00    19718    13630
## muneg_ageAge65orolder                               0.03 1.00    19181    13486
## muneg_ed_z                                          0.22 1.00    29969    12788
## muneg_ideology_z                                   -0.18 1.00    29967    13882
## muneg_income.5.cat21M40%                            0.04 1.00    16734    12707
## muneg_income.5.cat41M60%                            0.10 1.00    16085    13400
## muneg_income.5.cat61M80%                            0.07 1.00    15790    13382
## muneg_income.5.cat81M100%                           0.14 1.00    15876    13469
## muneg_genderFemale                                  0.03 1.00    33812    12500
## muneg_genderNonMbinary                              0.99 1.00    32807    12179
## muneg_genderNoneoftheabove                          0.42 1.00    35351    11331
## muneg_minorityYes                                   0.13 1.00    28631    13853
## muneg_minorityDeclinetoanswer                       0.08 1.00    28560    13121
## muneg_religBuddhism                                -0.08 1.00    28084    12375
## muneg_religCatholicism                             -0.34 1.00    21767    13047
## muneg_religChristianityprotestant                  -0.33 1.00    22392    14003
## muneg_religDeclinetoanswer                         -0.14 1.00    24872    13345
## muneg_religHinduism                                 0.22 1.00    33576    12434
## muneg_religIslam                                    0.45 1.00    29433    13237
## muneg_religJudaism                                  0.49 1.00    34033    11571
## muneg_religLocal                                    0.02 1.00    36353    12593
## muneg_religLocalreligion                            0.05 1.00    29412    11751
## muneg_religMormonism                                0.58 1.00    31354    12582
## muneg_religOther                                   -0.07 1.00    21870    13789
## muneg_religProtestant                              -0.27 1.00    27692    12782
## muneg_religShinto                                   0.17 1.00    29869    12719
## muneg_troops_crime_persYes                          0.13 1.00    26836    12721
## muneg_troops_crime_persDontknowDdeclinetoanswer    -0.08 1.00    31219    13322
## muneg_american_inf_1DontknowDdeclinetoanswer       -0.62 1.00    17595    13033
## muneg_american_inf_1Alittle                        -0.17 1.00    12365    12392
## muneg_american_inf_1Some                           -0.05 1.00    12309    11739
## muneg_american_inf_1Alot                            0.26 1.00    13038    12974
## muneg_american_inf_2DontknowDdeclinetoanswer        0.53 1.00    27150    12704
## muneg_american_inf_2Verynegative                    2.09 1.00    26109    12100
## muneg_american_inf_2Negative                        1.20 1.00    28932    12972
## muneg_american_inf_2Positive                       -0.20 1.00    29590    12833
## muneg_american_inf_2Verypositive                    0.01 1.00    29668    11649
## muneg_basecount_z                                   0.14 1.00    28661    12810
## muneg_gdp_z                                         0.25 1.00    13085    11450
## muneg_pop_z                                         1.64 1.00    10633    10608
## muneg_troops_z                                      2.00 1.00    10630    11094
## mupos_contact_persDontknowDdeclinetoanswer         -0.13 1.00    29408    12810
## mupos_contact_persYes                               0.57 1.00    28351    11980
## mupos_contact_nonpersDontknowDdeclinetoanswer       0.20 1.00    28651    12566
## mupos_contact_nonpersYes                            0.35 1.00    29172    13128
## mupos_benefit_persDontknowDdeclinetoanswer         -0.02 1.00    31679    12489
## mupos_benefit_persYes                               0.17 1.00    28144    11998
## mupos_benefit_nonpersDontknowDdeclinetoanswer       0.04 1.00    28630    13105
## mupos_benefit_nonpersYes                            0.48 1.00    27498    12797
## mupos_age25to34years                               -0.04 1.00    20577    14146
## mupos_age35to44years                               -0.01 1.00    19447    13819
## mupos_age45to54years                                0.03 1.00    18261    13498
## mupos_age55to64years                                0.18 1.00    19104    14277
## mupos_ageAge65orolder                               0.27 1.00    20552    13091
## mupos_ed_z                                          0.09 1.00    29661    13353
## mupos_ideology_z                                    0.44 1.00    29576    13265
## mupos_income.5.cat21M40%                            0.05 1.00    17020    13662
## mupos_income.5.cat41M60%                            0.09 1.00    16045    13836
## mupos_income.5.cat61M80%                            0.07 1.00    16733    12897
## mupos_income.5.cat81M100%                           0.15 1.00    16900    13783
## mupos_genderFemale                                 -0.17 1.00    32595    12972
## mupos_genderNonMbinary                              0.27 1.00    36395    12502
## mupos_genderNoneoftheabove                          0.08 1.00    35631    12341
## mupos_minorityYes                                   0.02 1.00    29799    12901
## mupos_minorityDeclinetoanswer                       0.09 1.00    27930    13383
## mupos_religBuddhism                                 0.19 1.00    26507    12840
## mupos_religCatholicism                              0.22 1.00    19101    14110
## mupos_religChristianityprotestant                   0.23 1.00    19766    13453
## mupos_religDeclinetoanswer                         -0.05 1.00    22491    12723
## mupos_religHinduism                                 0.04 1.00    31120    11441
## mupos_religIslam                                   -0.02 1.00    25817    14288
## mupos_religJudaism                                  0.48 1.00    31904    12952
## mupos_religLocal                                    0.15 1.00    38026    11372
## mupos_religLocalreligion                            0.10 1.00    29335    12494
## mupos_religMormonism                                1.12 1.00    30673    12942
## mupos_religOther                                   -0.03 1.00    20788    13895
## mupos_religProtestant                               0.35 1.00    25563    12706
## mupos_religShinto                                   0.36 1.00    31985    12756
## mupos_troops_crime_persYes                          0.07 1.00    28799    13442
## mupos_troops_crime_persDontknowDdeclinetoanswer    -0.33 1.00    30133    13226
## mupos_american_inf_1DontknowDdeclinetoanswer       -0.16 1.00    17919    14365
## mupos_american_inf_1Alittle                         0.17 1.00    13119    12543
## mupos_american_inf_1Some                            0.32 1.00    12624    12508
## mupos_american_inf_1Alot                            0.66 1.00    13174    12358
## mupos_american_inf_2DontknowDdeclinetoanswer       -0.12 1.00    29210    13052
## mupos_american_inf_2Verynegative                   -0.40 1.00    31274    13396
## mupos_american_inf_2Negative                       -0.26 1.00    32656    13653
## mupos_american_inf_2Positive                        1.29 1.00    29010    13253
## mupos_american_inf_2Verypositive                    2.08 1.00    29050    12641
## mupos_basecount_z                                   0.09 1.00    31330    12676
## mupos_gdp_z                                         1.37 1.00    10986    11660
## mupos_pop_z                                         0.53 1.00    10387     9799
## mupos_troops_z                                      0.21 1.00    10625    10867
## 
## Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).

There’s a lot going on here, but you can see from the summary output that organizing this could be a bit of a bear. We have three outcome categories, lots of categorical variables (some conceptually related), model summary statistics, etc.

Customization

The first two chunks are pretty boiler plate, and for lots of types of models you can probably just go on to use {modelsummary} directly and get some nice tables. But this section is going to dive into some of the extra steps required to make the tables look nice and clean, but also to save us a ton of time.

The big issue that we have to address is that {modelsummary} is going to automatically try to generate lots of different types of goodness-of-fit or model summary statistics for the models you’re including. If this were OLS it would be super quick. But since we’re using {brms} models the defaults can run for a very long time and, depending on your workflow needs, cause some major slowdowns.

{modelsummary} is using the packages like {tidy}, {parameters}, and {broom} to extract information from the models in your list and to generate a basic data frame with that output that serves as the basis for the final table. Things like WAIC and LOOIC can take a long time to calculate, and depending on your needs you might not want them right way.

Beyond that, you might just want to customize how the footer of your table looks, what information is included in which places, etc. This is a good way to do that, but it takes a little extra work.

First, we need to assign a “custom” class to each of the three model objects stored in the mod.list object. Assigning the custom class is going allow us to write some custom {tidy} and {glance} functions that will let us select the specific summary stats and other model info that we want to include.

for (i in seq_along(mod.list)){
  class(mod.list[[i]]) <- c("custom", class(mod.list[[i]]))
}

Next we can write out custom tidy function, appropriately labeled here tidy.custom. Actually, I think you have to name it this so {modelsummary} recognizes that you want to use a custom function.

There’s a lot going on here, and some of it is going to be specific to the models I’m using as an example.

First, you create the function, where x is the object placeholder, and conf.level=.95 is specifying the default confidence/credible interval threshold. The ... just leaves it open for other arguments.

Next we create an object named out using the {parameters} package. First we start off creating a data frame using this function, then we standardize all of the variable/column names (i.e. make them lower case). So far pretty standard.

The mutate chunk is where things get more complicated, and where you’ll need to substitute your own model-specific factors. {modelsummary} also has a formula-based argument for helping you to arrange your models in the resulting table, but we need to do a little extra work here to properly identify the outcome variable levels. This is partly a function of the fact that {brms} does some weird things like attaching outcome choices (i.e. the binary outcome variable for the individual equations) as prefixes to each variable name, meaning there are no outcome levels for {parameters} to automatically detect. So we need to create them.

All I’m going here is using case_when(...) to identify the outcome variable levels/choices and creating a categorical y.level variable containing the full name for each of the choices for the outcome variable. As I mentioned above, those are “Don’t know”, “Negative”, and “Positive” (with “Neutral” as the omitted reference category).

Next, I take the term column that {parameters} generates, which contains all of the predictor variables, and I remove the outcome level prefixes that {brms} attaches. This way I have two columns with variable names (term) and the outcome variable choice/model equation (i.e. y.level).

# tidy method extracts level names into new column
tidy.custom <- function(x, conf.level=.95, ...) {                                   # Create function
  out = parameters::parameters(x, ci=conf.level, verbose=FALSE) |>                 # Call {parameters} to pull model parameter info with specified credible interval
        parameters::standardize_names(style="broom") |>                            # make names lower case
        mutate(y.level = case_when(grepl("mudk", term) ~ "Don't Know",              # Change outcome level values to plain meaning for output table
                                 grepl("muneg", term) ~ "Negative",
                                 grepl("mupos", term) ~ "Positive"),
               term = gsub("dk|neg|pos", "", term))                                 # remove outcome prefix {brms} attaches to variable names
  return(out)
}

Next we can move on to writing a custom function to pull the relevant model and summary statistic information. First, we need to tell glance() to quiet down since it’s going to do lots of stuff we don’t necessarily want it to do right now. I can’t remember if the gof.check lines are necessary at this point (I seem to recall it had no effect one way or the other when I was initially working on this), but I’ll turn those off just to be safe, too.

# Write custom glance function to extract summary information.
glance.custom <- function(x, ...) {
  ret <- tibble::tibble(N = summary(x)$nobs)
  ret
}

# Turn off GOF stuff
gof.check <- modelsummary::gof_map
gof.check$omit <- TRUE

Next we can move on to using the {parameters} package to full information on the “random” part of our varying intercepts model. We’ll also use this step to include some basic summary information on the models as mentioned above.

Ultimately the goal here is to generate a clean data frame containing summary information that we want. I’ve included more specific comments in the code chunk below for readers who want to scrutinize each step, but much of this mirrors what we just did with the tidy.custom() function above, it’s just doing it to the “random” or “varying” part of the model rather than the population-level coefficients.

# Write function to loop over list of models
rows <- lapply(mod.list, function(x){

  temp.sd <- parameters::parameters(x, effect = "random")  |>                   # start with parameters and pull "random" component of model
    filter(grepl(".*sd.*", Parameter)) |>                                       # filter out parameters containing standard deviation info
    filter(grepl(".*persYes.*|.*nonpersYes.*|.*Intercept.*", Parameter)) |>     # further filter parameters containing SD info for relevant variables
    dplyr::select(Parameter, Median) |>                                         # Keep only the Parameter (name) column and the Median column
    dplyr::mutate(Median = as.character(round(Median, 2)),
      y.level = case_when(                                                       # Like before, create a y.level column for outcome variable level/equation
      grepl(".*mudk.*", Parameter) ~ "dk",
      grepl(".*mupos.*", Parameter) ~ "pos",
      grepl(".*muneg.*", Parameter) ~ "neg",
    ),
    Parameter = gsub("_mudk_|_mupos_|_muneg_", "_", Parameter)) |>              # Remove the {brms} prefix from the Parameter column
    pivot_wider(id_cols = Parameter,                                             # Rearrange  columns from long to wide
                values_from = Median,
                names_from = y.level) |> 
    mutate(Parameter = case_when(                                                # Rename relevant parameters to appear how you want in text
      grepl(".*Intercept.*", Parameter) ~ "sd(Intercept)"
    ))
  
  temp.obs <- tibble::tribble(~Parameter, ~dk, ~neg, ~pos,                       # Create another data frame containing observation count and grouping info
                              "N", as.character(nobs(x)), "", "",
                              "Group", "Country", "", "",
                              "\\# Groups", as.character(length(unique(x$data$country))), "", "")
  

  temp.com <- bind_rows(temp.obs, temp.sd)                                       # Bind two data frames together for consolidated footer data frame

  return(temp.com)
  
  }
)

# Group everything from the three models together
# Also select relevant columns containing information
rows.com <- bind_cols(rows[[1]], rows[[2]], rows[[3]]) |> 
  dplyr::select(1, 2, 3, 4, 6, 7, 8, 10, 11, 12) 

# Rename those columns so they'll match eventual output data frame names
names(rows.com) <- c("term", "col1", "col2", "col3", "col4", "col5", "col6", "col7", "col8", "col9")

Great! Next we can start cleaning up the variable names for presenting them in the table, and we can even go a step further to add grouping labels to help readers move between broad categories of predictor variables (e.g. income, age, etc.).

Here’s we’re going to generate a tribble with the “raw” variable names and the “clean” label for presentation. Note that we have to arrange them in the order in which we want them to appear.

coef.list <- tibble::tribble(~raw, ~clean,
                            "b_mu_contact_persYes", "Personal Contact: Yes",
                            "b_mu_contact_persDontknowDdeclinetoanswer", "Personal Contact: DK/Decline",
                            "b_mu_contact_nonpersYes", "Network Contact: Yes",
                            "b_mu_contact_nonpersDontknowDdeclinetoanswer", "Network Contact: DK/Decline",
                            "b_mu_benefit_persYes", "Personal Benefit: Yes",
                            "b_mu_benefit_persDontknowDdeclinetoanswer", "Personal Benefit: DK/Decline",
                            "b_mu_benefit_nonpersYes", "Network Benefit: Yes",
                            "b_mu_benefit_nonpersDontknowDdeclinetoanswer", "Network Benefit: DK/Decline",
                            "b_mu_age25to34years", "25-34",
                            "b_mu_age35to44years", "35-44",
                            "b_mu_age45to54years", "45-54",
                            "b_mu_age55to64years", "55-65",
                            "b_mu_ageAge65orolder", ">65",
                            "b_mu_income.5.cat21M40%", "21-40",
                            "b_mu_income.5.cat41M60%", "41-60",
                            "b_mu_income.5.cat61M80%", "61-80",
                            "b_mu_income.5.cat81M100%", "81-100",
                            "b_mu_genderFemale", "Female",
                            "b_mu_genderNonMbinary", "Non-binary",
                            "b_mu_genderNoneoftheabove", "None of the above",
                            "b_mu_minorityYes", "Minority: Yes",
                            "b_mu_minorityDeclinetoanswer", "Minoriy: Decline to answer",
                            "b_mu_religCatholicism", "Catholic",
                            "b_mu_religChristianityprotestant", "Protestant",
                            "b_mu_religBuddhism", "Buddhism",
                            "b_mu_religHinduism", "Hindu",
                            "b_mu_religIslam", "Islam",
                            "b_mu_religJudaism", "Judaism",
                            "b_mu_religShinto", "Shinto",
                            "b_mu_religMormonism", "Mormonism",
                            "b_mu_religLocal", "Local Religion",
                            "b_mu_religOther", "Other",
                            "b_mu_religDeclinetoanswer", "Religion: Decline to answer",
                            "b_mu_ed_z", "Education",
                            "b_mu_ideology_z", "Ideology",
                            "b_mu_troops_crime_persYes", "Personal Crime Experience: Yes",
                            "b_mu_american_inf_1DontknowDdeclinetoanswer", "Influence 1: DK/Decline",
                            "b_mu_american_inf_1Alittle", "Influence 1: A little",
                            "b_mu_american_inf_1Some", "Influence 1: Some",
                            "b_mu_american_inf_1Alot", "Influence 1: A lot",
                            "b_mu_american_inf_2DontknowDdeclinetoanswer", "Influence 2: DK/Decline",
                            "b_mu_american_inf_2Veryative", "Influence 2: Very negative",
                            "b_mu_american_inf_2Negative", "Influence 2: Negative",
                            "b_mu_american_inf_2Positive", "Influence 2: Positive",
                            "b_mu_american_inf_2Veryitive", "Influence 2: Very positive",
                            "b_mu_basecount_z", "Base count",
                            "b_mu_gdp_z", "GDP",
                            "b_mu_pop_z", "Population",
                            "b_mu_troops_z", "Troop deployment size",
                            "b_mu_Intercept", "Intercept")

Next we’re going to add a new column that contains the grouping list. Since we’re using lots of categorical predictor variables we want to make sure they’re grouped in a sensible way.

coef.list <- coef.list |> 
  mutate(group = case_when(
           grepl(".*ontact.*", raw) ~ "Contact Status",
           grepl(".*enefit.*", raw) ~ "Economic Benefits",
           grepl(".*age.*", raw) ~ "Age",
           grepl(".*ncome.*", raw) ~ "Income Quintile",
           grepl(".*gender.*", raw) ~ "Gender Identification",
           grepl(".*minority.*", raw) ~ "Minority Self-Identification",
           grepl(".*relig.*", raw) ~ "Religious Identification",
           grepl(".*ed_z.*", raw) ~ "Education",
           grepl(".*ideology_z.*", raw) ~ "Ideology",
           grepl(".*crime.*", raw) ~ "Crime Experience",
           grepl(".*inf_1.*", raw) ~ "American Influence (Amount)",
           grepl(".*inf_2.*", raw) ~ "American Influence (Quality)",
           TRUE ~ "Group-Level Variables"
         )) 

Next, because we’re dealing with a really wide table we’ll have coefficients with standard errors underneath. This means that each variable name is actually going to take up two lines. So we need to do a little extra here to properly format this bit. I have to admit I think Vincent actually came up with this particular solution as I was puttering with it for a while. So more props to him!

# Find how long the coefficient list is for the final table hline
last.line <- length(coef.list[[1]]) * 2

coef_map <- setNames(coef.list$clean, coef.list$raw)
idx <- rle(coef.list$group)
idx <- setNames(idx$lengths  * 2, idx$values)

Putting it all together

Finally, we’ve done all of the prep work. Now we can generate the actual table itself! I’m going to change just a couple of things here. Since the output is going to appear on a webpage, I’ll change the “output” argument to HTML. I’ll also delete the save_kable() bit that tells it to save to a latex file, but you can add that in at the end if you want \latex output.

You can see that we use the last.line values from the previous chunk in that last row_spec() line to tell it where to put an horizontal line.

modelsummary::modelsummary(mod.list,
                  estimate = "{estimate}",
                  statistic = "conf.int",
                  fmt = 2,
                  group = term ~ model + y.level,
                  gof_map = gof.check,
                  coef_map = coef_map,
                  add_rows = rows.com,
                  stars = FALSE,
                  output = "kableExtra",
                  caption = "Bayesian multilevel multinomial logistic regressions. Population level effects. \\label{tab:contactfull}") |> 
  kable_styling(bootstrap_options = c("striped"), font_size = 10, position = "center", full_width = FALSE) |>
  add_header_above(c(" ", "US Presence" = 3, "US People" = 3, "US Government" = 3)) |> 
  group_rows(index = idx, bold = TRUE, background = "gray", color = "white", hline_after = TRUE)  |>  
  row_spec(last.line, hline_after = TRUE) |> 
  column_spec(1, width = "5cm") |>
  column_spec(2:10, width = "3cm") |> 
  kableExtra::scroll_box(width = "100%", height = "600px") 
(\#tab:table output)Bayesian multilevel multinomial logistic regressions. Population level effects. \label{tab:contactfull}
US Presence
US People
US Government
/ Don't Know/ Negative/ Positive/ Don't Know/ Negative/ Positive/ Don't Know/ Negative/ Positive
Contact Status
Personal Contact: Yes−0.610.160.48−0.090.050.26−0.230.150.21
[−0.94, −0.28][0.05, 0.27][0.39, 0.57][−0.49, 0.29][−0.06, 0.17][0.17, 0.34][−0.61, 0.13][0.04, 0.25][0.11, 0.30]
Personal Contact: DK/Decline0.500.04−0.310.41−0.19−0.410.08−0.49−0.40
[0.23, 0.76][−0.17, 0.24][−0.50, −0.13][0.08, 0.75][−0.41, 0.03][−0.59, −0.24][−0.26, 0.41][−0.68, −0.29][−0.59, −0.20]
Network Contact: Yes−0.720.090.27−0.190.170.20−0.170.260.20
[−1.02, −0.43][−0.01, 0.20][0.18, 0.35][−0.57, 0.18][0.06, 0.28][0.12, 0.28][−0.53, 0.17][0.16, 0.36][0.11, 0.29]
Network Contact: DK/Decline−0.390.010.080.390.020.040.29−0.050.16
[−0.64, −0.15][−0.13, 0.16][−0.04, 0.20][0.09, 0.69][−0.14, 0.17][−0.07, 0.16][−0.01, 0.58][−0.19, 0.09][0.03, 0.30]
Economic Benefits
Personal Benefit: Yes−0.59−0.500.050.370.000.15−0.02−0.150.20
[−1.05, −0.17][−0.68, −0.31][−0.07, 0.17][−0.06, 0.79][−0.17, 0.18][0.04, 0.27][−0.46, 0.39][−0.30, 0.00][0.08, 0.32]
Personal Benefit: DK/Decline0.48−0.44−0.170.32−0.32−0.100.23−0.42−0.02
[0.26, 0.69][−0.62, −0.25][−0.32, −0.02][0.02, 0.63][−0.52, −0.11][−0.25, 0.04][−0.05, 0.51][−0.59, −0.26][−0.18, 0.14]
Network Benefit: Yes−0.55−0.260.38−0.230.100.11−0.39−0.220.09
[−1.00, −0.13][−0.41, −0.10][0.27, 0.48][−0.73, 0.24][−0.05, 0.25][0.01, 0.22][−0.86, 0.06][−0.35, −0.08][−0.02, 0.21]
Network Benefit: DK/Decline0.25−0.38−0.090.180.080.050.04−0.060.01
[0.03, 0.47][−0.54, −0.22][−0.22, 0.04][−0.11, 0.47][−0.09, 0.25][−0.07, 0.18][−0.24, 0.31][−0.20, 0.08][−0.13, 0.16]
Age
25-34−0.120.09−0.110.15−0.170.06−0.15−0.160.05
[−0.26, 0.03][0.01, 0.18][−0.19, −0.04][−0.08, 0.37][−0.26, −0.08][−0.01, 0.13][−0.36, 0.06][−0.24, −0.08][−0.03, 0.14]
35-44−0.26−0.01−0.08−0.02−0.410.07−0.18−0.220.04
[−0.41, −0.11][−0.09, 0.08][−0.16, −0.01][−0.26, 0.23][−0.50, −0.31][0.00, 0.14][−0.41, 0.03][−0.31, −0.14][−0.04, 0.12]
45-54−0.31−0.11−0.05−0.03−0.370.19−0.25−0.100.04
[−0.46, −0.15][−0.20, −0.02][−0.13, 0.03][−0.28, 0.23][−0.46, −0.28][0.12, 0.26][−0.49, −0.03][−0.18, −0.02][−0.04, 0.13]
55-65−0.59−0.190.11−0.02−0.550.31−0.180.040.12
[−0.76, −0.42][−0.28, −0.10][0.03, 0.18][−0.30, 0.25][−0.65, −0.45][0.24, 0.38][−0.43, 0.06][−0.04, 0.13][0.03, 0.21]
>65−0.78−0.070.190.24−0.380.41−0.140.170.18
[−0.98, −0.58][−0.17, 0.03][0.11, 0.27][−0.07, 0.53][−0.49, −0.27][0.33, 0.49][−0.44, 0.14][0.08, 0.26][0.08, 0.27]
Income Quintile
21-40−0.18−0.06−0.03−0.16−0.010.01−0.250.050.03
[−0.34, −0.01][−0.15, 0.04][−0.12, 0.05][−0.40, 0.08][−0.12, 0.09][−0.07, 0.09][−0.48, −0.03][−0.05, 0.14][−0.07, 0.12]
41-60−0.070.000.01−0.210.110.12−0.250.12−0.01
[−0.23, 0.09][−0.09, 0.10][−0.07, 0.09][−0.45, 0.03][0.00, 0.21][0.04, 0.19][−0.47, −0.03][0.03, 0.21][−0.10, 0.08]
61-80−0.33−0.03−0.01−0.530.120.14−0.620.160.01
[−0.52, −0.14][−0.13, 0.07][−0.10, 0.07][−0.85, −0.24][0.01, 0.23][0.05, 0.21][−0.91, −0.33][0.07, 0.26][−0.08, 0.11]
81-100−0.420.040.06−0.740.090.15−0.750.270.11
[−0.63, −0.21][−0.07, 0.14][−0.03, 0.15][−1.12, −0.39][−0.03, 0.21][0.07, 0.23][−1.10, −0.41][0.17, 0.37][0.00, 0.21]
Gender Identification
Female0.38−0.03−0.220.09−0.05−0.060.210.06−0.10
[0.28, 0.49][−0.08, 0.03][−0.27, −0.17][−0.07, 0.24][−0.11, 0.01][−0.10, −0.02][0.07, 0.36][0.02, 0.11][−0.15, −0.05]
Non-binary−1.300.41−0.18−0.69−0.21−0.301.420.48−0.18
[−4.92, 0.49][−0.18, 0.99][−0.63, 0.27][−4.07, 1.04][−0.86, 0.38][−0.71, 0.12][0.40, 2.29][−0.07, 1.04][−0.68, 0.33]
None of the above0.20−0.47−0.681.240.521.37−1.50−0.21−0.66
[−0.95, 1.24][−1.42, 0.42][−1.46, 0.08][−0.42, 2.75][−0.94, 1.82][0.51, 2.30][−4.99, 0.55][−0.97, 0.53][−1.47, 0.16]
Minority Self-Identification
Minority: Yes−0.120.04−0.05−0.040.04−0.08−0.05−0.14−0.07
[−0.30, 0.05][−0.04, 0.13][−0.13, 0.02][−0.29, 0.21][−0.06, 0.14][−0.15, −0.01][−0.28, 0.17][−0.22, −0.06][−0.15, 0.01]
Minoriy: Decline to answer0.53−0.10−0.060.780.00−0.150.46−0.11−0.17
[0.31, 0.74][−0.28, 0.08][−0.22, 0.09][0.51, 1.05][−0.19, 0.18][−0.29, −0.01][0.19, 0.71][−0.27, 0.04][−0.34, −0.01]
Religious Identification
Catholic0.06−0.420.15−0.06−0.280.090.27−0.39−0.03
[−0.10, 0.23][−0.51, −0.34][0.07, 0.22][−0.33, 0.21][−0.37, −0.19][0.02, 0.16][0.00, 0.54][−0.48, −0.31][−0.12, 0.06]
Protestant0.09−0.460.130.16−0.270.030.41−0.410.05
[−0.14, 0.31][−0.58, −0.33][0.03, 0.23][−0.23, 0.53][−0.40, −0.14][−0.06, 0.12][0.05, 0.75][−0.52, −0.29][−0.07, 0.16]
Buddhism0.09−0.220.060.03−0.200.140.05−0.390.04
[−0.27, 0.43][−0.37, −0.08][−0.07, 0.19][−0.47, 0.50][−0.40, 0.00][0.02, 0.26][−0.47, 0.54][−0.53, −0.24][−0.09, 0.18]
Hindu0.02−0.20−0.230.02−0.37−0.070.44−0.40−0.16
[−0.72, 0.67][−0.65, 0.22][−0.51, 0.04][−1.17, 0.99][−0.87, 0.09][−0.33, 0.19][−0.50, 1.28][−0.77, −0.04][−0.44, 0.13]
Islam0.040.29−0.170.230.05−0.130.410.04−0.29
[−0.25, 0.32][0.13, 0.45][−0.31, −0.02][−0.16, 0.62][−0.11, 0.21][−0.25, 0.00][0.05, 0.78][−0.12, 0.20][−0.44, −0.14]
Judaism0.76−0.050.18−0.80−1.670.091.68−0.560.29
[0.01, 1.45][−0.62, 0.49][−0.11, 0.48][−2.80, 0.72][−2.81, −0.74][−0.18, 0.36][0.88, 2.42][−1.07, −0.07][−0.03, 0.60]
Shinto−83.92−0.28−0.03−82.55−0.140.111.15−0.710.31
[−196.62, −7.75][−0.74, 0.17][−0.41, 0.36][−194.75, −7.27][−0.83, 0.49][−0.26, 0.49][0.05, 2.10][−1.28, −0.17][−0.08, 0.70]
Mormonism−86.86−0.200.46−83.83−0.800.290.27−0.070.47
[−202.31, −9.58][−1.03, 0.58][−0.17, 1.12][−197.04, −7.49][−1.78, 0.09][−0.29, 0.89][−3.24, 2.35][−0.91, 0.77][−0.28, 1.27]
Local Religion−0.66−0.37−0.190.95−0.49−0.111.20−1.16−0.06
[−1.63, 0.16][−0.76, 0.02][−0.52, 0.15][0.11, 1.72][−0.94, −0.07][−0.44, 0.21][0.43, 1.90][−1.55, −0.77][−0.42, 0.30]
Other0.17−0.16−0.120.05−0.160.050.47−0.23−0.06
[−0.01, 0.36][−0.25, −0.07][−0.21, −0.03][−0.27, 0.36][−0.26, −0.06][−0.03, 0.13][0.16, 0.77][−0.33, −0.13][−0.17, 0.05]
Religion: Decline to answer0.24−0.25−0.150.53−0.31−0.210.84−0.50−0.24
[0.06, 0.42][−0.36, −0.14][−0.26, −0.05][0.26, 0.79][−0.43, −0.19][−0.30, −0.11][0.57, 1.11][−0.61, −0.40][−0.37, −0.12]
Education
Education−0.040.160.03−0.010.050.17−0.080.170.12
[−0.16, 0.08][0.09, 0.22][−0.02, 0.09][−0.18, 0.17][−0.02, 0.12][0.11, 0.22][−0.25, 0.09][0.10, 0.23][0.05, 0.18]
Ideology
Ideology−0.21−0.250.38−0.15−0.010.11−0.22−0.580.46
[−0.34, −0.08][−0.31, −0.18][0.32, 0.44][−0.35, 0.04][−0.08, 0.07][0.06, 0.17][−0.41, −0.05][−0.64, −0.51][0.40, 0.53]
Crime Experience
Personal Crime Experience: Yes−0.21−0.13−0.110.550.12−0.280.15−0.47−0.18
[−0.89, 0.38][−0.40, 0.13][−0.28, 0.07][−0.05, 1.11][−0.11, 0.35][−0.44, −0.12][−0.50, 0.73][−0.69, −0.25][−0.35, 0.00]
American Influence (Amount)
Influence 1: DK/Decline0.44−0.82−0.350.41−0.75−0.440.24−0.61−0.54
[0.20, 0.69][−1.02, −0.62][−0.54, −0.16][0.07, 0.75][−0.97, −0.54][−0.61, −0.28][−0.07, 0.55][−0.79, −0.43][−0.77, −0.30]
Influence 1: A little−0.33−0.300.04−0.77−0.34−0.10−1.08−0.030.22
[−0.56, −0.09][−0.44, −0.17][−0.09, 0.17][−1.12, −0.42][−0.47, −0.20][−0.22, 0.02][−1.42, −0.74][−0.16, 0.10][0.07, 0.38]
Influence 1: Some−0.21−0.170.19−0.75−0.510.13−0.670.010.28
[−0.42, 0.01][−0.30, −0.05][0.06, 0.32][−1.07, −0.42][−0.64, −0.38][0.01, 0.24][−0.96, −0.38][−0.12, 0.13][0.13, 0.43]
Influence 1: A lot−0.290.130.53−0.63−0.330.55−0.780.130.61
[−0.52, −0.05][−0.01, 0.26][0.40, 0.66][−0.98, −0.28][−0.46, −0.19][0.43, 0.67][−1.11, −0.47][0.00, 0.26][0.46, 0.77]
American Influence (Quality)
Influence 2: DK/Decline1.900.38−0.271.69−0.01−0.281.980.22−0.17
[1.74, 2.06][0.22, 0.53][−0.42, −0.12][1.45, 1.92][−0.19, 0.16][−0.40, −0.16][1.76, 2.20][0.09, 0.35][−0.35, 0.01]
Influence 2: Very negative0.631.97−0.570.561.88−0.881.272.83−0.01
[0.35, 0.89][1.85, 2.09][−0.73, −0.40][0.15, 0.94][1.77, 1.99][−1.00, −0.76][0.77, 1.74][2.64, 3.01][−0.27, 0.24]
Influence 2: Negative0.281.14−0.33−0.151.13−0.550.541.61−0.17
[0.14, 0.41][1.07, 1.20][−0.40, −0.26][−0.42, 0.12][1.06, 1.20][−0.61, −0.49][0.27, 0.80][1.54, 1.68][−0.27, −0.07]
Influence 2: Positive0.00−0.281.240.27−0.161.31−0.02−0.411.35
[−0.16, 0.17][−0.37, −0.20][1.18, 1.29][−0.01, 0.55][−0.27, −0.05][1.25, 1.36][−0.28, 0.22][−0.48, −0.34][1.29, 1.41]
Influence 2: Very positive0.62−0.211.941.160.272.241.26−0.672.31
[0.22, 1.00][−0.44, 0.01][1.81, 2.08][0.61, 1.67][−0.01, 0.53][2.10, 2.38][0.84, 1.66][−0.88, −0.47][2.18, 2.43]
Group-Level Variables
Base count0.100.070.020.070.02−0.08−0.09−0.02−0.02
[−0.05, 0.23][0.00, 0.14][−0.04, 0.09][−0.15, 0.27][−0.07, 0.11][−0.14, −0.02][−0.30, 0.12][−0.10, 0.05][−0.09, 0.06]
GDP0.83−0.800.40−0.49−0.360.700.600.91−0.15
[−0.18, 1.75][−1.90, 0.25][−0.46, 1.37][−1.59, 0.55][−1.66, 0.68][−0.14, 1.53][−0.20, 1.36][−0.12, 1.91][−0.99, 0.68]
Population−0.210.64−0.18−0.02−0.04−0.13−0.25−0.630.04
[−0.91, 0.55][−0.47, 1.64][−1.04, 0.53][−0.76, 0.77][−0.89, 1.20][−0.95, 0.56][−0.83, 0.29][−1.75, 0.50][−0.66, 0.71]
Troop deployment size−0.680.57−0.740.53−0.22−0.66−0.30−0.11−0.33
[−1.60, 0.38][−0.66, 2.00][−1.80, 0.21][−0.43, 1.55][−1.36, 0.99][−1.53, 0.34][−1.07, 0.58][−1.38, 1.38][−1.30, 0.58]
Intercept−2.21−0.46−0.24−3.24−0.62−0.26−2.730.21−0.74
[−2.62, −1.82][−0.94, 0.02][−0.58, 0.12][−3.74, −2.75][−1.05, −0.20][−0.58, 0.06][−3.17, −2.29][−0.32, 0.74][−1.08, −0.40]
N386263862638626
GroupCountryCountryCountry
\# Groups141414
sd(Intercept)0.490.80.540.440.660.510.350.920.51

What’s left?

There are a few things I’d like to tweak. For example, {modelsummary} adds little slashes before the outcome variable name and inserts the name from the model list before that. I leave the list entries blank to avoid this since horizontal space is a premium.

Blogdown/hugo is also being a bit frustrating with the final table. I’ve tried making the font larger, but for whatever reason the horizontal scrollbar isn’t working with the kableExtra table in this environment. Not great, but it looks ok for now. Sizing and scale were a littl tough to tweak in Tex files, but I got it more or less where it needed to be by the end. I’m sure someone with a little more skill than me can figure out some of the hiccups.

There’s way more you can do to cusomtize the output of these tables, particularly in the footer. You might want to add particular model fit or summary statistics, and the glance.custom() function is a great place to specify what you want. Much is possible, but I’m going to stop here for now since it took me something like a month to get this posted.

Michael E. Flynn
Michael E. Flynn
Associate Professor of Political Science

My research focuses on the political economy of US foreign policy, the influence of domestic politics on foreign policy, and the causes and consequences of US military deployments overseas.

Related