1 1) Import & clean

# Location & filename stem (extension auto-detected)
data_dir  <- "C:/Users/Artur/OneDrive - Florida State University/FIRST/Papers/Covid-Corbinian/Data"
file_stem <- "Covid_Yout_Data-3"

# Find a file with this stem (xlsx/xls/csv)
hits <- list.files(path = data_dir,
                   pattern = paste0("^", file_stem, "\\.(xlsx|xls|csv)$"),
                   full.names = TRUE, ignore.case = TRUE)
if (!length(hits)) {
  cat("No file with stem:", file_stem, "in:\n", data_dir, "\nFiles here:\n")
  print(list.files(data_dir, full.names = TRUE))
  stop("Confirm the exact filename (including extension).")
}
data_path <- hits[1]
cat("Reading:", data_path, "\n")
## Reading: C:/Users/Artur/OneDrive - Florida State University/FIRST/Papers/Covid-Corbinian/Data/Covid_Yout_Data-3.xlsx
# Read Excel or CSV
df_raw <- if (grepl("\\.xlsx?$", data_path, ignore.case = TRUE)) {
  readxl::read_excel(data_path)
} else {
  readr::read_csv(data_path, show_col_types = FALSE)
}

# The Excel had trailing spaces in some headers (symptoms); trim, then clean
names(df_raw) <- trimws(names(df_raw))
df <- df_raw %>% janitor::clean_names()

cat("Rows:", nrow(df), " | Cols:", ncol(df), "\n")
## Rows: 1725  | Cols: 66

2 2) Missing values → NA (numeric codes)

# Dataset uses explicit missing codes (e.g., 999; sometimes 990/9999)
special_missing <- c(990, 999, 9999)
df <- df %>% mutate(across(where(is.numeric), ~ ifelse(. %in% special_missing, NA_real_, .)))

3 3) Symptoms: detect, enforce {0,1}, and index

# Robust detection after clean_names() to catch variants
symptom_patterns <- c(
  "^s_?headache$", "^s_?fever$", "^s_?cough$",
  "^s_?sore[_]?thro$", "^s_?shor[_]?bre$", "^s_?weak$", "^s_?cold$"
)

cand <- names(df)
symptom_cols <- unique(unlist(lapply(symptom_patterns, function(pat) {
  cand[stringr::str_detect(cand, stringr::regex(pat, ignore_case = TRUE))]
})))
symptom_cols <- union(symptom_cols, intersect(
  names(df), c("sheadache","s_fever","s_cough","s_sore_thro","s_shor_bre","s_weak","s_cold")
))
symptom_cols <- unique(symptom_cols)

cat("Detected symptom columns:\n"); print(symptom_cols)
## Detected symptom columns:
## [1] "sheadache"   "s_fever"     "s_cough"     "s_sore_thro" "s_shor_bre" 
## [6] "s_weak"      "s_cold"
# Enforce domain {0,1}; anything else -> NA (e.g., 2, 990, 999, 9990, 9999)
if (length(symptom_cols)) {
  df <- df %>%
    mutate(across(all_of(symptom_cols), ~ {
      x <- suppressWarnings(as.numeric(.))
      ifelse(x %in% c(0,1), x, NA_real_)
    }))
}

# Build index: sum of 7 binary symptoms (range 0..7)
df <- df %>% mutate(symptom_index = if (length(symptom_cols)) rowSums(across(all_of(symptom_cols)), na.rm = TRUE) else NA_real_)
summary(df$symptom_index)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   0.000   0.000   3.000   2.892   5.000   7.000

4 4) Codebook labels (safe; out-of-range → NA)

recode_factor_safe <- function(x, levels, labels, varname = "") {
  x_num <- suppressWarnings(as.numeric(x))
  bad <- !is.na(x_num) & !(x_num %in% levels)
  if (any(bad, na.rm = TRUE)) message(sprintf("Note: %s had %d out-of-codebook value(s) -> NA.", varname, sum(bad, na.rm = TRUE)))
  x_num[bad] <- NA_real_
  factor(x_num, levels = levels, labels = labels)
}

if ("sex" %in% names(df))        df <- df %>% mutate(sex = recode_factor_safe(sex, c(0,1,2), c("Male","Female","Diverse"), "sex"))
if ("country" %in% names(df))    df <- df %>% mutate(country = recode_factor_safe(country, c(1,2,3), c("Germany","China","Ukraine"), "country"))
if ("native" %in% names(df))     df <- df %>% mutate(native = recode_factor_safe(native, c(1,2,3,4), c("German","Polish","Ukrainian","Spanish"), "native"))
if ("religion" %in% names(df))   df <- df %>% mutate(religion = recode_factor_safe(religion, c(1,2,3,4,5,6),
                                         c("Protestant","Muslim","Other","Catholic","Jewish","No religion"), "religion"))
if ("religiousness" %in% names(df)) df <- df %>% mutate(religiousness = recode_factor_safe(religiousness, c(0,1),
                                         c("Not religious","Religious"), "religiousness"))
if ("occupation" %in% names(df)) df <- df %>% mutate(occupation = recode_factor_safe(occupation, c(1,2,3,4),
                                         c("Gymnasium","Realschule","Middle school","FOS/BOS"), "occupation"))
if ("sexual_o" %in% names(df))   df <- df %>% mutate(sexual_o = recode_factor_safe(sexual_o, c(1,2,3,4,5,6),
                                         c("Heterosexual","Gay","Bisexual","Uncertain","Other","Prefer not to answer"), "sexual_o"))
if ("infection" %in% names(df))  df <- df %>% mutate(infection   = recode_factor_safe(infection,   c(0,1), c("No","Yes"), "infection"))
if ("vaccination" %in% names(df))df <- df %>% mutate(vaccination = recode_factor_safe(vaccination, c(0,1), c("No","Yes"), "vaccination"))
if ("mental" %in% names(df))     df <- df %>% mutate(mental      = recode_factor_safe(mental,      c(0,1), c("No","Yes"), "mental"))

5 5) Descriptives & Table 1

df %>% select(any_of(c("infection","vaccination","mental","symptom_index"))) %>% summary()
##  infection   vaccination  mental     symptom_index  
##  No  : 418   No  : 254   No  :1157   Min.   :0.000  
##  Yes :1302   Yes :1445   Yes : 491   1st Qu.:0.000  
##  NA's:   5   NA's:  26   NA's:  77   Median :3.000  
##                                      Mean   :2.892  
##                                      3rd Qu.:5.000  
##                                      Max.   :7.000
if (have_gtsummary) {
  library(gtsummary)
  df %>%
    select(mental, infection, vaccination, age, sex, sexual_o, symptom_index) %>%
    tbl_summary(by = mental, missing_text = "(missing)") %>%
    add_p() %>%
    modify_caption("**Table 1. Sample characteristics by mental health status**")
}
Table 1. Sample characteristics by mental health status
Characteristic No
N = 1,157
1
Yes
N = 491
1
p-value2
infection 925 (80%) 370 (76%) 0.038
    (missing) 2 1
vaccination 964 (84%) 411 (85%) 0.8
    (missing) 16 7
age

0.6
    13 1 (<0.1%) 1 (0.2%)
    14 6 (0.5%) 1 (0.2%)
    15 434 (38%) 191 (39%)
    16 592 (51%) 257 (52%)
    17 104 (9.0%) 33 (6.7%)
    18 20 (1.7%) 7 (1.4%)
    (missing) 0 1
sex

<0.001
    Male 615 (53%) 126 (26%)
    Female 526 (45%) 347 (71%)
    Diverse 16 (1.4%) 16 (3.3%)
    (missing) 0 2
sexual_o

<0.001
    Heterosexual 948 (83%) 303 (63%)
    Gay 7 (0.6%) 15 (3.1%)
    Bisexual 52 (4.6%) 60 (13%)
    Uncertain 67 (5.9%) 64 (13%)
    Other 11 (1.0%) 17 (3.5%)
    Prefer not to answer 54 (4.7%) 20 (4.2%)
    (missing) 18 12
symptom_index

<0.001
    0 255 (22%) 128 (26%)
    1 96 (8.3%) 25 (5.1%)
    2 129 (11%) 33 (6.7%)
    3 190 (16%) 45 (9.2%)
    4 167 (14%) 75 (15%)
    5 164 (14%) 80 (16%)
    6 129 (11%) 73 (15%)
    7 27 (2.3%) 32 (6.5%)
1 n (%)
2 Pearson’s Chi-squared test; Fisher’s exact test

6 6) Crosstabs (chi-square + Cramér’s V)

do_chisq <- function(a, b) {
  tb <- table(a, b, useNA = "no")
  print(tb)
  chi <- suppressWarnings(chisq.test(tb))
  print(chi)
  if (have_vcd) {
    vcd::assocstats(tb)   # includes Cramér's V
  } else {
    n <- sum(tb); phi2 <- as.numeric(chi$statistic) / n; k <- min(nrow(tb), ncol(tb))
    cramer_v <- sqrt(phi2 / (k - 1))
    cat("Cramer's V (manual):", round(cramer_v, 3), "\n")
  }
}

if (all(c("infection","mental") %in% names(df))) {
  cat("\n### Infection × Mental\n"); do_chisq(df$infection, df$mental)
}
## 
## ### Infection × Mental
##      b
## a      No Yes
##   No  230 120
##   Yes 925 370
## 
##  Pearson's Chi-squared test with Yates' continuity correction
## 
## data:  tb
## X-squared = 4.0329, df = 1, p-value = 0.04462
##                     X^2 df P(> X^2)
## Likelihood Ratio 4.2200  1 0.039950
## Pearson          4.3018  1 0.038072
## 
## Phi-Coefficient   : 0.051 
## Contingency Coeff.: 0.051 
## Cramer's V        : 0.051
if (all(c("vaccination","mental") %in% names(df))) {
  cat("\n### Vaccination × Mental\n"); do_chisq(df$vaccination, df$mental)
}
## 
## ### Vaccination × Mental
##      b
## a      No Yes
##   No  177  73
##   Yes 964 411
## 
##  Pearson's Chi-squared test with Yates' continuity correction
## 
## data:  tb
## X-squared = 0.020899, df = 1, p-value = 0.8851
##                       X^2 df P(> X^2)
## Likelihood Ratio 0.048435  1  0.82581
## Pearson          0.048284  1  0.82608
## 
## Phi-Coefficient   : 0.005 
## Contingency Coeff.: 0.005 
## Cramer's V        : 0.005

7 7) Logistic regression (moderation; centered covariates)

# Center continuous covariates
df <- df %>% mutate(
  age_c = age - mean(age, na.rm = TRUE),
  symptom_index_c = symptom_index - mean(symptom_index, na.rm = TRUE)
)

# Build complete-case modeling frame
model_vars <- c("mental","infection","vaccination","age_c","sex","sexual_o","symptom_index_c")
df_model <- df %>%
  select(all_of(model_vars)) %>%
  drop_na() %>%
  mutate(across(where(is.factor), fct_drop))

# Defensive: keep interaction only if both predictors have ≥2 levels
need_2_levels <- function(x) !is.factor(x) || nlevels(x) >= 2
has_infection_ok   <- "infection"   %in% names(df_model) && need_2_levels(df_model$infection)
has_vaccination_ok <- "vaccination" %in% names(df_model) && need_2_levels(df_model$vaccination)

covars <- c("age_c","sex","sexual_o","symptom_index_c")
keep_covars <- covars[covars %in% names(df_model)]
keep_covars <- keep_covars[sapply(df_model[keep_covars], need_2_levels)]

rhs <- if (has_infection_ok && has_vaccination_ok) {
  c("infection * vaccination", keep_covars)
} else if (has_vaccination_ok) {
  message("NOTE: 'infection' has < 2 levels after filtering; modeling without it.")
  c("vaccination", keep_covars)
} else if (has_infection_ok) {
  message("NOTE: 'vaccination' has < 2 levels after filtering; modeling without it.")
  c("infection", keep_covars)
} else stop("Neither infection nor vaccination retained ≥ 2 levels after filtering.")

form <- as.formula(paste("mental ~", paste(rhs, collapse = " + ")))
form
## mental ~ infection * vaccination + age_c + sex + sexual_o + symptom_index_c
fit <- glm(form, data = df_model, family = binomial, na.action = na.exclude)
summary(fit)
## 
## Call:
## glm(formula = form, family = binomial, data = df_model, na.action = na.exclude)
## 
## Coefficients:
##                              Estimate Std. Error z value Pr(>|z|)    
## (Intercept)                  -1.06734    0.37792  -2.824 0.004739 ** 
## infectionYes                 -0.81105    0.41411  -1.959 0.050166 .  
## vaccinationYes                0.11521    0.37355   0.308 0.757770    
## age_c                         0.07005    0.08594   0.815 0.415015    
## sexFemale                     1.04671    0.13200   7.930 2.20e-15 ***
## sexDiverse                    0.78815    0.45037   1.750 0.080113 .  
## sexual_oGay                   1.98622    0.51042   3.891 9.97e-05 ***
## sexual_oBisexual              0.91553    0.21051   4.349 1.37e-05 ***
## sexual_oUncertain             0.83067    0.19746   4.207 2.59e-05 ***
## sexual_oOther                 1.58975    0.45049   3.529 0.000417 ***
## sexual_oPrefer not to answer -0.23598    0.29464  -0.801 0.423187    
## symptom_index_c               0.18314    0.03925   4.666 3.07e-06 ***
## infectionYes:vaccinationYes  -0.23903    0.41418  -0.577 0.563856    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 1926.4  on 1588  degrees of freedom
## Residual deviance: 1728.5  on 1576  degrees of freedom
## AIC: 1754.5
## 
## Number of Fisher Scoring iterations: 4
broom::tidy(fit, conf.int = TRUE, exponentiate = TRUE) %>% arrange(p.value)
## # A tibble: 13 × 7
##    term                 estimate std.error statistic  p.value conf.low conf.high
##    <chr>                   <dbl>     <dbl>     <dbl>    <dbl>    <dbl>     <dbl>
##  1 sexFemale               2.85     0.132      7.93  2.20e-15    2.20      3.70 
##  2 symptom_index_c         1.20     0.0392     4.67  3.07e- 6    1.11      1.30 
##  3 sexual_oBisexual        2.50     0.211      4.35  1.37e- 5    1.65      3.78 
##  4 sexual_oUncertain       2.29     0.197      4.21  2.59e- 5    1.56      3.38 
##  5 sexual_oGay             7.29     0.510      3.89  9.97e- 5    2.80     21.4  
##  6 sexual_oOther           4.90     0.450      3.53  4.17e- 4    2.05     12.2  
##  7 (Intercept)             0.344    0.378     -2.82  4.74e- 3    0.159     0.707
##  8 infectionYes            0.444    0.414     -1.96  5.02e- 2    0.200     1.02 
##  9 sexDiverse              2.20     0.450      1.75  8.01e- 2    0.895     5.30 
## 10 age_c                   1.07     0.0859     0.815 4.15e- 1    0.906     1.27 
## 11 sexual_oPrefer not …    0.790    0.295     -0.801 4.23e- 1    0.432     1.38 
## 12 infectionYes:vaccin…    0.787    0.414     -0.577 5.64e- 1    0.342     1.75 
## 13 vaccinationYes          1.12     0.374      0.308 7.58e- 1    0.549     2.40

8 8) Collinearity & performance

# Term-level VIFs (use GVIF^(1/(2*Df)) for factors/interactions)
vif_tbl <- tryCatch({
  v <- car::vif(fit)
  if (is.vector(v)) {
    tibble(term = names(v), df = 1L, index = as.numeric(v), type = "VIF")
  } else {
    tibble(term = rownames(v),
           df   = if ("Df" %in% colnames(v)) v[, "Df"] else 1L,
           gvif = if ("GVIF" %in% colnames(v)) v[, "GVIF"] else as.numeric(v)) |>
      mutate(index = if_else(df > 1, gvif^(1/(2*df)), gvif),
             type  = if_else(df > 1, "GVIF^(1/(2*Df))", "VIF")) |>
      select(term, df, type, index) |>
      arrange(desc(index))
  }
}, error = function(e) NULL)

if (!is.null(vif_tbl)) {
  cat("\n### Collinearity indices (term-level)\n"); print(vif_tbl, n = nrow(vif_tbl))
}
## 
## ### Collinearity indices (term-level)
## # A tibble: 7 × 4
##   term                     df type            index
##   <chr>                 <dbl> <chr>           <dbl>
## 1 infection:vaccination     1 VIF             11.4 
## 2 infection                 1 VIF              8.68
## 3 vaccination               1 VIF              5.34
## 4 symptom_index_c           1 VIF              2.33
## 5 sex                       2 GVIF^(1/(2*Df))  1.08
## 6 age_c                     1 VIF              1.03
## 7 sexual_o                  5 GVIF^(1/(2*Df))  1.03
# GLM-friendly collinearity summary
if (have_perf) {
  library(performance)
  cat("\n### performance::check_collinearity\n")
  print(performance::check_collinearity(fit))
}
## 
## ### performance::check_collinearity
## # Check for Multicollinearity
## 
## Low Correlation
## 
##             Term  VIF     VIF 95% CI adj. VIF Tolerance Tolerance 95% CI
##            age_c 1.03 [ 1.01,  1.16]     1.02      0.97     [0.86, 0.99]
##              sex 1.35 [ 1.28,  1.45]     1.16      0.74     [0.69, 0.78]
##         sexual_o 1.33 [ 1.26,  1.42]     1.15      0.75     [0.70, 0.79]
##  symptom_index_c 2.33 [ 2.16,  2.52]     1.52      0.43     [0.40, 0.46]
## 
## Moderate Correlation
## 
##         Term  VIF     VIF 95% CI adj. VIF Tolerance Tolerance 95% CI
##    infection 8.68 [ 7.92,  9.52]     2.95      0.12     [0.11, 0.13]
##  vaccination 5.34 [ 4.90,  5.84]     2.31      0.19     [0.17, 0.20]
## 
## High Correlation
## 
##                   Term   VIF     VIF 95% CI adj. VIF Tolerance Tolerance 95% CI
##  infection:vaccination 11.36 [10.35, 12.47]     3.37      0.09     [0.08, 0.10]
# Pseudo-R2
if (have_pscl) {
  library(pscl)
  cat("\n### Pseudo-R2 (pscl::pR2)\n")
  print(pscl::pR2(fit))
}
## 
## ### Pseudo-R2 (pscl::pR2)
## fitting null model for pseudo-r2
##          llh      llhNull           G2     McFadden         r2ML         r2CU 
## -864.2389989 -963.1780719  197.8781459    0.1027215    0.1170882    0.1666760
# ROC / AUC
if (have_pROC) {
  library(pROC)
  roc_obj <- roc(df_model$mental, fitted(fit))
  cat("\n### ROC AUC:\n"); print(auc(roc_obj))
  plot(roc_obj, col = "#2C7BB6", lwd = 2, main = "ROC curve (logit model)")
}
## 
## ### ROC AUC:
## Area under the curve: 0.7147

# Hosmer–Lemeshow
if (have_RS) {
  library(ResourceSelection)
  cat("\n### Hosmer–Lemeshow test (g=10)\n")
  print(hoslem.test(as.integer(df_model$mental) - 1, fitted(fit), g = 10))
}
## 
## ### Hosmer–Lemeshow test (g=10)
## 
##  Hosmer and Lemeshow goodness of fit (GOF) test
## 
## data:  as.integer(df_model$mental) - 1, fitted(fit)
## X-squared = 2.7318, df = 8, p-value = 0.95

9 9) Marginal effects & interaction plot

# Average marginal effects for infection & vaccination
if (have_margins) {
  library(margins)
  cat("\n### Average marginal effects (infection, vaccination)\n")
  print(summary(margins(fit, variables = c("infection","vaccination"))))
}
## 
## ### Average marginal effects (infection, vaccination)
##          factor     AME     SE       z      p   lower   upper
##    infectionYes -0.1963 0.0414 -4.7401 0.0000 -0.2775 -0.1152
##  vaccinationYes -0.0130 0.0302 -0.4311 0.6664 -0.0721  0.0461
# Predicted probabilities by Infection × Vaccination (if interaction present)
if (have_ggeffects) {
  library(ggeffects); library(ggplot2)
  if (all(c("infection","vaccination") %in% all.vars(form))) {
    eff <- ggpredict(fit, terms = c("infection","vaccination"))
    ggplot(eff, aes(x = x, y = predicted, colour = group)) +
      geom_line(linewidth = 1.2) + geom_point(size = 2) +
      labs(x = "Infection", y = "Pr(Mental = Yes)", colour = "Vaccination",
           title = "Predicted probability by Infection × Vaccination") +
      theme_minimal(base_size = 12)
  } else {
    message("Interaction not in the model — plot skipped.")
  }
}

10 10) Publication-ready model table (optional)

if (have_modelsum) {
  library(modelsummary)
  modelsummary(list("Mental health (logit)" = fit),
               exponentiate = TRUE,
               estimate = "{estimate} ({conf.low}, {conf.high})",
               gof_omit = "AIC|BIC|Log.Lik|Deviance",
               output = "markdown")
}
Mental health (logit)
(Intercept) 0.344 (0.159, 0.707)
(0.130)
infectionYes 0.444 (0.200, 1.021)
(0.184)
vaccinationYes 1.122 (0.549, 2.397)
(0.419)
age_c 1.073 (0.906, 1.269)
(0.092)
sexFemale 2.848 (2.204, 3.699)
(0.376)
sexDiverse 2.199 (0.895, 5.297)
(0.991)
sexual_oGay 7.288 (2.800, 21.409)
(3.720)
sexual_oBisexual 2.498 (1.654, 3.782)
(0.526)
sexual_oUncertain 2.295 (1.557, 3.380)
(0.453)
sexual_oOther 4.903 (2.047, 12.159)
(2.209)
sexual_oPrefer not to answer 0.790 (0.432, 1.380)
(0.233)
symptom_index_c 1.201 (1.113, 1.298)
(0.047)
infectionYes × vaccinationYes 0.787 (0.342, 1.750)
(0.326)
Num.Obs. 1589
F 14.027
RMSE 0.43

11 11) Bias-reduced alternatives (use if separation warnings appear)

if (have_logistf) {
  library(logistf)
  fit_firth <- logistf(form, data = df_model)
  summary(fit_firth)
  exp(cbind(OR = coef(fit_firth), confint(fit_firth)))
}
if (have_brglm2) {
  library(brglm2)
  fit_br <- glm(form, data = df_model, family = binomial, method = brglmFit, type = "AS_median")
  summary(fit_br)
  broom::tidy(fit_br, conf.int = TRUE, exponentiate = TRUE)
}

12 12) Export cleaned data

clean_path <- file.path(dirname(data_path), "Covid_Youth_Data_cleaned.csv")
readr::write_csv(df, clean_path)
cat("Saved cleaned data to:\n", clean_path, "\n")
## Saved cleaned data to:
##  C:/Users/Artur/OneDrive - Florida State University/FIRST/Papers/Covid-Corbinian/Data/Covid_Youth_Data_cleaned.csv

13 Appendix: Session info

sessionInfo()
## R version 4.4.1 (2024-06-14 ucrt)
## Platform: x86_64-w64-mingw32/x64
## Running under: Windows 11 x64 (build 26200)
## 
## Matrix products: default
## 
## 
## locale:
## [1] LC_COLLATE=English_United States.utf8 
## [2] LC_CTYPE=English_United States.utf8   
## [3] LC_MONETARY=English_United States.utf8
## [4] LC_NUMERIC=C                          
## [5] LC_TIME=English_United States.utf8    
## 
## time zone: America/New_York
## tzcode source: internal
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] modelsummary_2.5.0      ggeffects_2.3.2         margins_0.3.28         
##  [4] ResourceSelection_0.3-6 pROC_1.19.0.1           pscl_1.5.9             
##  [7] performance_0.16.0      gtsummary_2.5.0         car_3.1-5              
## [10] carData_3.0-6           broom_1.0.12            janitor_2.2.1          
## [13] readxl_1.4.5            lubridate_1.9.5         forcats_1.0.1          
## [16] stringr_1.6.0           dplyr_1.2.0             purrr_1.2.1            
## [19] readr_2.1.6             tidyr_1.3.2             tibble_3.3.1           
## [22] ggplot2_4.0.2           tidyverse_2.0.0        
## 
## loaded via a namespace (and not attached):
##   [1] Rdpack_2.6.6           rlang_1.1.7            magrittr_2.0.4        
##   [4] snakecase_0.11.1       prediction_0.3.18      compiler_4.4.1        
##   [7] mgcv_1.9-4             brglm2_1.0.1           vctrs_0.7.1           
##  [10] crayon_1.5.3           pkgconfig_2.0.3        shape_1.4.6.1         
##  [13] fastmap_1.2.0          backports_1.5.0        labeling_0.4.3        
##  [16] effectsize_1.0.1       utf8_1.2.6             rmarkdown_2.30        
##  [19] markdown_2.0           tzdb_0.5.0             haven_2.5.5           
##  [22] nloptr_2.2.1           bit_4.6.0              xfun_0.56             
##  [25] glmnet_4.1-10          jomo_2.7-6             logistf_1.26.1        
##  [28] cachem_1.1.0           litedown_0.9           jsonlite_2.0.0        
##  [31] tinytable_0.16.0       pan_1.9                parallel_4.4.1        
##  [34] R6_2.6.1               bslib_0.10.0           tables_0.9.33         
##  [37] stringi_1.8.7          vcd_1.4-13             RColorBrewer_1.1-3    
##  [40] rpart_4.1.24           boot_1.3-32            lmtest_0.9-40         
##  [43] jquerylib_0.1.4        cellranger_1.1.0       numDeriv_2016.8-1.1   
##  [46] Rcpp_1.1.1             iterators_1.0.14       knitr_1.51            
##  [49] zoo_1.8-15             parameters_0.28.3      Matrix_1.7-4          
##  [52] splines_4.4.1          nnet_7.3-20            timechange_0.4.0      
##  [55] tidyselect_1.2.1       rstudioapi_0.18.0      abind_1.4-8           
##  [58] yaml_2.3.12            codetools_0.2-20       lattice_0.22-7        
##  [61] enrichwith_0.4.0       bayestestR_0.17.0      withr_3.0.2           
##  [64] S7_0.2.1               evaluate_1.0.5         survival_3.8-6        
##  [67] xml2_1.5.2             pillar_1.11.1          mice_3.19.0           
##  [70] checkmate_2.3.4        foreach_1.5.2          reformulas_0.4.4      
##  [73] insight_1.4.6          generics_0.1.4         vroom_1.7.0           
##  [76] nleqslv_3.3.5          hms_1.1.4              commonmark_2.0.0      
##  [79] scales_1.4.0           minqa_1.2.8            glue_1.8.0            
##  [82] tools_4.4.1            data.table_1.18.2.1    lme4_1.1-38           
##  [85] fs_1.6.6               grid_4.4.1             rbibutils_2.4.1       
##  [88] datawizard_1.3.0       cards_0.7.1            colorspace_2.1-2      
##  [91] nlme_3.1-168           formula.tools_1.7.1    cardx_0.3.2           
##  [94] Formula_1.2-5          cli_3.6.5              gt_1.3.0              
##  [97] gtable_0.3.6           sass_0.4.10            digest_0.6.39         
## [100] operator.tools_1.6.3.1 farver_2.1.2           htmltools_0.5.9       
## [103] lifecycle_1.0.5        mitml_0.4-5            statmod_1.5.1         
## [106] bit64_4.6.0-1          MASS_7.3-65