Last active
April 14, 2020 13:12
-
-
Save svmiller/cb8dc541f82b64621cf20340c911f7c6 to your computer and use it in GitHub Desktop.
Simulate Ordinal Mixed Model Coefficients and Make Posterior Predictions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Let's load the packages and the data. ----- | |
# See this instead: http://svmiller.com/blog/2020/04/summarizing-ordinal-models-with-simulation-multivariate-normal/ | |
library(stevemisc) | |
library(post8000r) | |
library(tidyverse) | |
TV16 %>% | |
filter(racef == "White") %>% | |
filter(state %in% c("Indiana","Ohio","Pennsylvania","Wisconsin","Michigan")) %>% | |
mutate(whiteadvf = ordered(whiteadv)) -> Data | |
Data %>% | |
mutate_at(vars("age", "famincr","pid7na","ideo","lcograc","lemprac"), | |
list(z = ~r2sd(.))) %>% | |
rename_at(vars(contains("_z")), | |
~paste("z", gsub("_z", "", .), sep = "_") ) -> Data | |
# Simple ordinal model with state random effects. ---- | |
require(ordinal) | |
Ord1 <- clmm(whiteadvf ~ z_age + z_famincr + z_pid7na + female + collegeed + z_ideo + (1 | state), | |
data=Data) | |
# Extract some model parameters and make sims ---- | |
coefOrd1 <- coef(Ord1) | |
vcovOrd1 <- vcov(Ord1) # vcov without state random effect | |
vcovOrd1 <- vcovOrd1[-nrow(vcovOrd1), -ncol(vcovOrd1)] | |
set.seed(8675309) | |
simOrd1 <- MASS::mvrnorm(1000, coefOrd1, vcovOrd1) %>% tbl_df() %>% | |
mutate(sim = seq(1:1000)) %>% select(sim, everything()) | |
# Get hypothetical data. | |
require(modelr) | |
Data %>% | |
# Let's keep it simple and obvious. The min of z_ideo is "very liberal." | |
# The max of z_ideo is "very conservative." | |
# We should expect to see magnitude differences. | |
data_grid(.model = Ord1, z_ideo = c(min(z_ideo, na.rm=T), max(z_ideo, na.rm=T))) %>% | |
# because we got 1000 sims, we need to repeat this 1000 times | |
dplyr::slice(rep(row_number(), 1000)) -> newdatOrd1 | |
simOrd1 %>% | |
# repeat it twice because we have two values of z_ideo | |
dplyr::slice(rep(row_number(), 2)) %>% | |
# arrange by simulation number after we repeated the data twice | |
arrange(sim) %>% | |
# rename these to be clear they're simulated coefficients | |
rename_at(vars("z_age", "z_famincr", "z_pid7na", "female", "collegeed", "z_ideo"), | |
~paste0("coef", .)) %>% | |
bind_cols(., newdatOrd1) %>% | |
# Manually calculate the logits | |
mutate(logit1 = `1|2` - ((z_age*coefz_age) + (z_famincr*coefz_famincr) + (z_pid7na*coefz_pid7na) + | |
(female*coeffemale) + (collegeed*coefcollegeed) + (z_ideo*coefz_ideo)), | |
logit2 = `2|3` - ((z_age*coefz_age) + (z_famincr*coefz_famincr) + (z_pid7na*coefz_pid7na) + | |
(female*coeffemale) + (collegeed*coefcollegeed) + (z_ideo*coefz_ideo)), | |
logit3 = `3|4` - ((z_age*coefz_age) + (z_famincr*coefz_famincr) + (z_pid7na*coefz_pid7na) + | |
(female*coeffemale) + (collegeed*coefcollegeed) + (z_ideo*coefz_ideo)), | |
logit4 = `4|5` - ((z_age*coefz_age) + (z_famincr*coefz_famincr) + (z_pid7na*coefz_pid7na) + | |
(female*coeffemale) + (collegeed*coefcollegeed) + (z_ideo*coefz_ideo))) %>% | |
mutate_at(vars(contains("logit")), list(p = ~plogis(.))) %>% | |
mutate(p1 = logit1_p, | |
p2 = logit2_p - logit1_p, | |
p3 = logit3_p - logit2_p, | |
p4 = logit4_p - logit3_p, | |
p5 = 1 - logit4_p, | |
sump = p1 + p2 + p3 + p4 + p5) -> simOrd1 | |
simOrd1 %>% | |
group_by(z_ideo) %>% | |
summarize_at(vars("p1","p2","p3","p4","p5"), | |
list(mean = ~mean(.), | |
lwr = ~quantile(., .025), | |
upr = ~quantile(., .975))) %>% | |
select(z_ideo, p5_mean, p5_lwr, p5_upr) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment