---
title: "Case Study: Breast Cancer Diagnosis"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Case Study: Breast Cancer Diagnosis}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.width = 6,
  fig.height = 4
)
```

```{r setup}
library(triageR)
library(mlbench)
```

## Overview

This vignette applies triageR to the **Wisconsin Breast Cancer** dataset,
a real-world dataset of tumor characteristics used to predict whether a
biopsy is benign or malignant. It complements the introductory vignette
by demonstrating a three-engine comparison, and by illustrating an
important nuance in automated pipeline review: the difference between
genuine biological signal and true data leakage.

## 1. Load and prepare data

The dataset stores its predictors as factors representing ordinal scores
(1-10). We convert these to numeric, and note that patient IDs contain
duplicates (repeat biopsies), both are realistic data quality issues
that `triageR` is designed to surface rather than hide.

```{r}
data(BreastCancer)
bc <- BreastCancer

score_cols <- c("Cl.thickness", "Cell.size", "Cell.shape", "Marg.adhesion",
                 "Epith.c.size", "Bare.nuclei", "Bl.cromatin",
                 "Normal.nucleoli", "Mitoses")
bc[score_cols] <- lapply(bc[score_cols], function(x) as.numeric(as.character(x)))

bc_loaded <- tr_load_clinical(bc, id_col = "Id")
```

```{r}
tr_check_missing(bc_loaded)
```

## 2. Impute missing data

```{r, message = FALSE, results = "hide"}
bc_for_impute <- bc_loaded[, setdiff(names(bc_loaded), "Id")]
bc_imputed <- tr_impute(bc_for_impute, method = "mice", m = 5)
```

## 3. Fit and compare three engines

```{r}
set.seed(7)
n <- nrow(bc_imputed)
train_idx <- sample(seq_len(n), size = floor(0.7 * n))

bc_train <- bc_imputed[train_idx, ]
bc_test  <- bc_imputed[-train_idx, ]

bc_model_glm <- tr_fit(bc_train, outcome = "Class", engine = "logistic_reg")
bc_model_rf  <- tr_fit(bc_train, outcome = "Class", engine = "random_forest")
bc_model_xgb <- tr_fit(bc_train, outcome = "Class", engine = "boost_tree")
```

```{r}
bc_val_glm <- tr_validate(bc_model_glm, newdata = bc_test)
bc_val_rf  <- tr_validate(bc_model_rf, newdata = bc_test)
bc_val_xgb <- tr_validate(bc_model_xgb, newdata = bc_test)
```

```{r}
bc_comparison <- dplyr::bind_rows(
  dplyr::mutate(bc_val_glm$metrics, engine = "logistic_reg"),
  dplyr::mutate(bc_val_rf$metrics, engine = "random_forest"),
  dplyr::mutate(bc_val_xgb$metrics, engine = "boost_tree")
)

tidyr::pivot_wider(bc_comparison, names_from = .metric, values_from = .estimate)
```

All three engines perform very well on this dataset (AUC > 0.98),
reflecting the fact that tumor morphology is highly predictive of
malignancy. Notably, logistic regression performs competitively with
the more flexible tree-based methods, a reminder that added model
complexity does not always yield better clinical performance.

```{r}
bc_val_glm$roc_plot
```

## 4. Explainability

```{r}
tr_explain(bc_model_glm, method = "permutation")
```

Cell thickness, bare nuclei, and bland chromatin emerge as the strongest
predictors which is consistent with established cytological indicators of
malignancy.

## 5. Automated pipeline review: interpreting the leakage flag

```{r}
bc_review <- tr_agent_review(bc_train, bc_model_glm, use_agent = FALSE)
```

`tr_agent_review()` flags `Cell.shape` as a possible leakage concern,
since it alone achieves a high AUC predicting malignancy. **This is an
important nuance to understand**: the check cannot distinguish between
genuine, strong biological signal and true data leakage (e.g. a variable
derived from the outcome itself). In this case, cell shape is a
well-established cytological indicator of malignancy, not a leakage
artifact.

This illustrates the intended role of `tr_agent_review()`: it flags
statistically unusual patterns for **human review**, not automatic
disqualification. A researcher with domain knowledge can correctly
interpret this flag as expected biological signal rather than an error.

## 6. Sensitivity analysis

```{r}
bc_sensitivity <- tr_sensitivity(bc_train, bc_model_glm)
```

Performance remains stable across the complete-case and outlier-exclusion
scenarios, indicating the model is not overly sensitive to a small number
of extreme values or missing-data handling.

## Summary

This case study demonstrated triageR's three-engine comparison workflow
on a second real-world clinical dataset, and highlighted an important
interpretive nuance in automated pipeline review: statistical flags
require clinical context to interpret correctly. triageR is designed to
surface these patterns for expert review, not to make final judgments
autonomously.
