161 lines
5.9 KiB
R
161 lines
5.9 KiB
R
# Compare AUC distributions between models by ICD-10 chapter (1-year and no-gap)
|
|
# Usage:
|
|
# Rscript plot_auc_boxplots_by_chapter.R [one_year_csv] [no_gap_csv] [output_dir]
|
|
# Defaults:
|
|
# one_year_csv = "model_comparison_auc_1year.csv"
|
|
# no_gap_csv = "model_comparison_auc_no_gap.csv"
|
|
# output_dir = current working directory (".")
|
|
|
|
suppressPackageStartupMessages({
|
|
library(ggplot2)
|
|
library(cowplot)
|
|
})
|
|
|
|
args <- commandArgs(trailingOnly = TRUE)
|
|
one_year_csv <- if (length(args) >= 1) args[1] else "model_comparison_auc_1year.csv"
|
|
no_gap_csv <- if (length(args) >= 2) args[2] else "model_comparison_auc_no_gap.csv"
|
|
out_dir <- if (length(args) >= 3) args[3] else "."
|
|
orientation <- if (length(args) >= 4) tolower(args[4]) else "vertical" # "horizontal" (flipped) or "vertical"
|
|
|
|
if (!dir.exists(out_dir)) {
|
|
dir.create(out_dir, recursive = TRUE, showWarnings = FALSE)
|
|
}
|
|
|
|
read_csv_safe <- function(path) {
|
|
tryCatch({
|
|
read.csv(path, check.names = FALSE)
|
|
}, error = function(e) {
|
|
stop(sprintf("Failed to read CSV at '%s': %s", path, e$message))
|
|
})
|
|
}
|
|
|
|
# Determine a chapter column name robustly
|
|
get_chapter_col <- function(df) {
|
|
candidates <- c("ICD-10 Chapter (short)", "ICD-10 Chapter", "ICD10_chapter", "chapter", "ICD_chapter")
|
|
for (c in candidates) {
|
|
if (c %in% names(df)) return(c)
|
|
}
|
|
return(NA_character_)
|
|
}
|
|
|
|
# Compute a deterministic chapter ordering using the ICD-10 chapter numeral prefix
|
|
# e.g., "I. Infectious Diseases", "II. Neoplasms", ..., "XVII. ...", with a fallback for "Death" and unknowns
|
|
compute_chapter_levels <- function(chapters) {
|
|
ch <- as.character(chapters)
|
|
roman_levels <- c(
|
|
"I","II","III","IV","V","VI","VII","VIII","IX","X",
|
|
"XI","XII","XIII","XIV","XV","XVI","XVII","XVIII","XIX","XX"
|
|
)
|
|
roman_map <- setNames(seq_along(roman_levels), roman_levels)
|
|
# Extract leading Roman numeral before a dot, like "XVI." -> "XVI"
|
|
roman <- toupper(gsub("^\\s*([IVXLCDM]+)\\..*$", "\\1", ch))
|
|
idx <- rep(NA_integer_, length(ch))
|
|
hit <- roman %in% names(roman_map)
|
|
idx[hit] <- roman_map[roman[hit]]
|
|
# Special-case Death at the end
|
|
idx[grepl("^\\s*Death\\b", ch, ignore.case = TRUE)] <- 99L
|
|
# Unknowns to the very end
|
|
idx[is.na(idx)] <- 100L
|
|
# Order chapters by idx, stable within same idx by appearance
|
|
o <- order(idx, match(ch, unique(ch)))
|
|
unique(ch[o])
|
|
}
|
|
|
|
# Build long-format data.frame with columns: chapter, model, auc
|
|
# It will include any of the known model columns that exist in the input df
|
|
build_long_df <- function(df) {
|
|
model_cols <- c(
|
|
auc_120 = "auc_120",
|
|
auc_120_l = "auc_120_l",
|
|
auc_256 = "auc_256",
|
|
auc_256_l = "auc_256_l",
|
|
auc_delphi = "auc_delphi"
|
|
)
|
|
pretty_names <- c(
|
|
auc_120 = "GPT-2 120",
|
|
auc_120_l = "GPT-2 120_L",
|
|
auc_256 = "GPT-2 256",
|
|
auc_256_l = "GPT-2 256_L",
|
|
auc_delphi = "Delphi"
|
|
)
|
|
present <- model_cols[names(model_cols) %in% names(df)]
|
|
if (length(present) == 0) stop("No known AUC columns found in input data.")
|
|
chap_col <- get_chapter_col(df)
|
|
if (is.na(chap_col)) {
|
|
warning("No chapter column found; using a single 'All' group.")
|
|
chapters <- rep("All", nrow(df))
|
|
} else {
|
|
chapters <- df[[chap_col]]
|
|
}
|
|
out_list <- list()
|
|
for (key in names(model_cols)) {
|
|
col <- model_cols[[key]]
|
|
if (col %in% names(df)) {
|
|
out_list[[length(out_list) + 1]] <- data.frame(
|
|
chapter = chapters,
|
|
model = pretty_names[[key]],
|
|
auc = as.numeric(df[[col]]),
|
|
stringsAsFactors = FALSE
|
|
)
|
|
}
|
|
}
|
|
long_df <- do.call(rbind, out_list)
|
|
# Filter out-of-range or NA
|
|
long_df <- long_df[is.finite(long_df$auc) & long_df$auc >= 0 & long_df$auc <= 1, ]
|
|
long_df$model <- factor(long_df$model, levels = c("GPT-2 120", "GPT-2 120_L", "GPT-2 256", "GPT-2 256_L", "Delphi"))
|
|
return(long_df)
|
|
}
|
|
|
|
# Make the boxplot grouped by chapter
|
|
make_boxplot <- function(long_df, title_text, flip = TRUE) {
|
|
# Order chapters by their ICD-10 chapter number prefix (Roman numerals)
|
|
chap_levels <- compute_chapter_levels(long_df$chapter)
|
|
long_df$chapter <- factor(long_df$chapter, levels = chap_levels)
|
|
|
|
p <- ggplot(long_df, aes(x = chapter, y = auc, fill = model)) +
|
|
geom_boxplot(outlier.shape = 19, outlier.size = 0.7, width = 0.75, alpha = 0.95) +
|
|
scale_y_continuous(limits = c(0.3, 1.0), breaks = seq(0.3, 1.0, by = 0.1)) +
|
|
labs(title = title_text, x = "ICD-10 Chapter", y = "AUC") +
|
|
theme_minimal(base_size = 11) +
|
|
theme(
|
|
plot.title = element_text(hjust = 0.5),
|
|
panel.grid.minor = element_blank(),
|
|
legend.position = "bottom"
|
|
) +
|
|
guides(fill = guide_legend(nrow = 1))
|
|
if (flip) {
|
|
p <- p + coord_flip()
|
|
} else {
|
|
# For vertical plots, angle x-axis labels for readability
|
|
p <- p + theme(axis.text.x = element_text(angle = 45, hjust = 1))
|
|
}
|
|
p
|
|
}
|
|
|
|
# Build plots for 1-year and no-gap
|
|
one_year_df <- read_csv_safe(one_year_csv)
|
|
no_gap_df <- read_csv_safe(no_gap_csv)
|
|
|
|
one_year_long <- build_long_df(one_year_df)
|
|
no_gap_long <- build_long_df(no_gap_df)
|
|
|
|
flip_flag <- ifelse(orientation %in% c("horizontal", "flip", "flipped"), TRUE, FALSE)
|
|
|
|
p1 <- make_boxplot(one_year_long, "AUC by ICD-10 Chapter (1-year gap)", flip = flip_flag)
|
|
p2 <- make_boxplot(no_gap_long, "AUC by ICD-10 Chapter (no gap)", flip = flip_flag)
|
|
|
|
# Save individual plots
|
|
out_1year <- file.path(out_dir, "auc_boxplot_by_chapter_1year.png")
|
|
ggsave(out_1year, p1, width = 12, height = 10, dpi = 300, bg = "white")
|
|
cat(sprintf("Saved: %s\n", out_1year))
|
|
|
|
out_nogap <- file.path(out_dir, "auc_boxplot_by_chapter_no_gap.png")
|
|
ggsave(out_nogap, p2, width = 12, height = 10, dpi = 300, bg = "white")
|
|
cat(sprintf("Saved: %s\n", out_nogap))
|
|
|
|
# Save a side-by-side grid for quick comparison
|
|
grid <- plot_grid(p1, p2, labels = c("A", "B"), ncol = 2, align = "hv")
|
|
out_grid <- file.path(out_dir, "auc_boxplot_by_chapter_grid.png")
|
|
ggsave(out_grid, grid, width = 18, height = 10, dpi = 250, bg = "white")
|
|
cat(sprintf("Saved grid: %s\n", out_grid))
|