format_deviation_table <- function(deviations_df) {
deviations_df |>
mutate(
Metric_Short = case_when(
grepl("Bias", Metric) ~ "Bias",
grepl("Sensitivity", Metric) ~ "Sens",
grepl("Precision", Metric) ~ "Prec",
TRUE ~ "Other"
),
CI_Label = sprintf("[%.2f, %.2f]", CI_Low, CI_High)
) |>
select(contrast, Metric_Short, Deviation, p_val, CI_Label) |>
pivot_wider(
names_from = Metric_Short,
values_from = c(Deviation, p_val, CI_Label),
names_glue = "{Metric_Short}_{.value}"
) |>
select(
contrast,
starts_with("Bias"),
starts_with("Sens"),
starts_with("Prec")
) |>
gt() |>
tab_spanner(label = "Bias (Intercept)", columns = starts_with("Bias")) |>
tab_spanner(label = "Sensitivity (Slope)", columns = starts_with("Sens")) |>
tab_spanner(label = "Precision (Noise)", columns = starts_with("Prec")) |>
fmt_number(columns = ends_with("Deviation"), decimals = 2) |>
fmt_number(columns = ends_with("p_val"), decimals = 3) |>
text_transform(
locations = cells_body(columns = ends_with("p_val")),
fn = function(x) {
vals <- suppressWarnings(as.numeric(x))
ifelse(is.na(vals), x,
ifelse(vals < 0.001, "< .001", sprintf("%.3f", vals))
)
}
) |>
cols_label(
contrast = "Group",
Bias_Deviation = "Dev.", Bias_p_val = "p-val", Bias_CI_Label = "95% CI",
Sens_Deviation = "Dev.", Sens_p_val = "p-val", Sens_CI_Label = "95% CI",
Prec_Deviation = "Dev.", Prec_p_val = "p-val", Prec_CI_Label = "95% CI"
) |>
cols_align(align = "left", columns = contrast) |>
tab_header(
title = "Fairness Audit Results",
subtitle = "Systematic Deviations by Metric"
) |>
tab_style(
style = cell_text(weight = "bold"),
locations = list(
cells_body(columns = "Bias_p_val", rows = Bias_p_val < 0.05),
cells_body(columns = "Sens_p_val", rows = Sens_p_val < 0.05),
cells_body(columns = "Prec_p_val", rows = Prec_p_val < 0.05)
)
) |>
tab_options(table.font.size = 14)
}
# Helper: format an Est + 95% CI summary as a gt table
gt_est_table <- function(df, group_col, group_label, est_label, title, subtitle = NULL) {
df |>
mutate(CI_Label = sprintf("[%.2f, %.2f]", CI_Low, CI_High)) |>
select(all_of(group_col), Est, CI_Label, any_of("p_val")) |>
gt() |>
fmt_number(columns = Est, decimals = 2) |>
cols_label(.list = setNames(list(group_label, est_label, "95% CI"),
c(group_col, "Est", "CI_Label"))) |>
cols_align(align = "left", columns = all_of(group_col)) |>
tab_header(title = title, subtitle = subtitle) |>
tab_options(table.font.size = 14)
}