## ----setup, include = FALSE--------------------------------------------------- knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.width = 7, fig.height = 4.5 ) # This is an UNWEIGHTED MAIHDA on the full ~352,714-record complete-case sample. An # lme4 glmer on that many rows (with the 432-group random intercept, two models) # takes minutes -- too slow for a package build -- so it is fitted once by # data-raw/brfss_precompute.R and this article renders from a small cache plus # pre-rendered figures. pc <- readRDS("brfss_precomputed.rds") fmt <- function(x, d = 3) formatC(as.numeric(x), format = "f", digits = d) fmt0 <- function(x, d = 3) ifelse(is.na(x), "", formatC(as.numeric(x), format = "f", digits = d)) pct <- function(x, d = 1) paste0(formatC(100 * as.numeric(x), format = "f", digits = d), "%") big <- function(x) format(as.numeric(x), big.mark = ",", trim = TRUE) ## ----download, eval = FALSE--------------------------------------------------- # library(MAIHDA) # library(dplyr) # # raw_cols <- c( # "_MENT14D", "SEXVAR", "_IMPRACE", "_AGEG5YR", "EDUCA", "_INCOMG1", # "DEAF", "BLIND", "DECIDE", "DIFFWALK", "DIFFDRES", "DIFFALON" # ) # # brfss_raw <- haven::read_xpt(xpt_file, col_select = dplyr::all_of(raw_cols)) # dim(brfss_raw) ## ----recode, eval = FALSE----------------------------------------------------- # disability_vars <- c("DEAF", "BLIND", "DECIDE", "DIFFWALK", "DIFFDRES", "DIFFALON") # disability_items <- brfss_raw[disability_vars] # # any_disability <- rowSums(disability_items == 1, na.rm = TRUE) > 0 # all_answered_no <- rowSums(disability_items == 2, na.rm = TRUE) == length(disability_vars) # # brfss_reduced <- brfss_raw |> # transmute( # frequent_distress = case_when( # .data[["_MENT14D"]] == 3 ~ 1L, # .data[["_MENT14D"]] %in% c(1, 2) ~ 0L, # TRUE ~ NA_integer_ # ), # sex = factor( # case_when(SEXVAR == 1 ~ "Male", SEXVAR == 2 ~ "Female", TRUE ~ NA_character_), # levels = c("Male", "Female") # ), # race_ethnicity = factor( # case_when( # .data[["_IMPRACE"]] == 1 ~ "White, non-Hispanic", # .data[["_IMPRACE"]] == 2 ~ "Black, non-Hispanic", # .data[["_IMPRACE"]] == 5 ~ "Hispanic", # .data[["_IMPRACE"]] %in% c(3, 4, 6) ~ "Other race/ethnicity", # TRUE ~ NA_character_ # ), # levels = c("White, non-Hispanic", "Black, non-Hispanic", # "Hispanic", "Other race/ethnicity") # ), # age_group = factor( # case_when( # .data[["_AGEG5YR"]] %in% 1:3 ~ "18-34", # .data[["_AGEG5YR"]] %in% 4:9 ~ "35-64", # .data[["_AGEG5YR"]] %in% 10:13 ~ "65+", # TRUE ~ NA_character_ # ), # levels = c("18-34", "35-64", "65+") # ), # education = factor( # case_when( # EDUCA %in% 1:4 ~ "HS or less", EDUCA == 5 ~ "Some college", # EDUCA == 6 ~ "College graduate", TRUE ~ NA_character_ # ), # levels = c("HS or less", "Some college", "College graduate") # ), # income = factor( # case_when( # .data[["_INCOMG1"]] %in% 1:2 ~ "<$25k", # .data[["_INCOMG1"]] %in% 3:4 ~ "$25k-<$50k", # .data[["_INCOMG1"]] %in% 5:7 ~ "$50k+", # TRUE ~ NA_character_ # ), # levels = c("<$25k", "$25k-<$50k", "$50k+") # ), # disability = factor( # case_when( # any_disability ~ "Any disability", all_answered_no ~ "No disability", # TRUE ~ NA_character_ # ), # levels = c("No disability", "Any disability") # ) # ) |> # filter( # !is.na(frequent_distress), !is.na(sex), !is.na(race_ethnicity), # !is.na(age_group), !is.na(education), !is.na(income), !is.na(disability) # ) ## ----fit-code, eval = FALSE--------------------------------------------------- # brfss_fit <- maihda( # frequent_distress ~ sex + race_ethnicity + age_group + education + income + disability + # (1 | sex:race_ethnicity:age_group:education:income:disability), # data = brfss_reduced, family = "binomial", interactions = "BH" # ) # # brfss_fit # generics::glance(brfss_fit) ## ----model-table, echo = FALSE------------------------------------------------ mt <- pc$model_table knitr::kable( data.frame( Statistic = mt$statistic, `Null (Model 1)` = fmt0(mt$null), `Adjusted (Model 2)` = fmt0(mt$adjusted), check.names = FALSE ), caption = "Model-results table." ) ## ----ranked-strata-cached, echo = FALSE--------------------------------------- ts <- pc$top_strata disp <- data.frame(Rank = ts$rank, Stratum = ts$label, Predicted = fmt(ts$predicted), check.names = FALSE) if ("observed" %in% names(ts)) disp[["Observed"]] <- fmt(ts$observed) if ("raw_n" %in% names(ts)) disp[["N"]] <- big(ts$raw_n) knitr::kable(disp, caption = "Highest predicted-risk strata.") ## ----interaction-table-cached, echo = FALSE----------------------------------- it <- pc$top_interactions disp <- data.frame(Stratum = it$label, Interaction = fmt(it$interaction), Lower = fmt(it$lower), Upper = fmt(it$upper), check.names = FALSE) if ("direction" %in% names(it)) disp[["Direction"]] <- it$direction if ("decision" %in% names(it)) disp[["ROPE (±0.4)"]] <- it$decision knitr::kable(head(disp, 15), digits = 3, caption = "Strongest interactions by absolute size, with ROPE classification.") ## ----rope-code, eval = FALSE-------------------------------------------------- # maihda_interactions(brfss_fit, rope = 0.4) # ROPE = +/- 0.4 log-odds (OR ~ 1.5) ## ----plot-vpc-cached, echo = FALSE, out.width = "100%", fig.cap = "Variance partition (VPC): share of latent-scale variation between intersectional strata."---- knitr::include_graphics("figures/brfss_vpc.png") ## ----plot-code, eval = FALSE-------------------------------------------------- # plot(brfss_fit, type = "upset", n_strata = 20, select = "deviation", # highlight_interactions = TRUE, highlight_by = "rope", rope = 0.4) # plot(brfss_fit, type = "effect_decomp", # highlight_interactions = TRUE, highlight_by = "rope", rope = 0.4) ## ----plot-upset-cached, echo = FALSE, out.width = "100%", fig.cap = "UpSet-style predicted-risk view: read each stratum's defining category off the matrix instead of a long text label. Columns are the most extreme-risk strata plus the ROPE-relevant ones (±0.4), which are highlighted."---- knitr::include_graphics("figures/brfss_upset.png") ## ----plot-effect-cached, echo = FALSE, out.width = "100%", fig.cap = "Effect decomposition: additive (fixed-effect) vs. residual stratum (interaction) component per stratum; the two ROPE-relevant strata (±0.4) are labelled."---- knitr::include_graphics("figures/brfss_effect_decomp.png")