Add scripts for patient classification and visualization

- Created `classification.py` for comparing image-level and patient-level classification results using various CNN models.
- Implemented `create_patient_groups.py` to extract features, generate PCA/t-SNE plots, and identify patient groups via K-means clustering.
- Added `figure6.py` to generate boxplots for test accuracy across multiple seeds.
- Developed `simple_patient_tsne.py` to perform t-SNE visualization of patient groups and save results in a manifest file.
- Introduced `simple_patient_manifest.csv` to store patient IDs, classes, image counts, and associated images.
This commit is contained in:
rpotter6298
2026-06-29 14:30:16 +02:00
commit 8a136c71fe
15 changed files with 4273 additions and 0 deletions
+97
View File
@@ -0,0 +1,97 @@
#!/usr/bin/env python3
"""
figure6.py — test accuracy boxplots across 20 seeds (Figure 6).
Usage:
conda activate fundus_imaging
python scripts/figure6.py
"""
import os, sys, json
import numpy as np
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.patches import Patch
from tqdm import tqdm
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from classes import PatientLeakageClassifier
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
MODELS = ["VGG16", "DenseNet121", "EfficientNetB1", "MobileNetV2", "ResNet50"]
SEEDS = list(range(1, 21))
clf = PatientLeakageClassifier(
os.path.join(ROOT, "results", "simple_patient_manifest.csv"),
os.path.join(ROOT, "features"),
n_jobs=8)
# ---------------------------------------------------------------------------
# Run all seeds
# ---------------------------------------------------------------------------
all_data = [] # flat list of per-run dicts for raw data file
for name in tqdm(MODELS, desc="Models"):
for seed in tqdm(SEEDS, desc=f" {name} seeds", leave=False):
for stype in ["image", "patient"]:
r = clf.run(name, seed, stype)
all_data.append(r)
# Save raw data
with open(os.path.join(ROOT, "results", "figure6_data.json"), "w") as f:
json.dump(all_data, f, indent=2)
# ---------------------------------------------------------------------------
# Build per-model accuracy lists
# ---------------------------------------------------------------------------
accs = {} # model -> {image: [accs], patient: [accs]}
for name in MODELS:
accs[name] = {"image": [], "patient": []}
for r in all_data:
accs[r["model"]][r["split_type"]].append(r["test"])
# ---------------------------------------------------------------------------
# Plot
# ---------------------------------------------------------------------------
fig, ax = plt.subplots(1, 1, figsize=(10, 6))
for i, name in enumerate(MODELS):
pos_img = i * 2 + 0.7
pos_pat = i * 2 + 1.3
for pos, stype, color in [(pos_img, "image", '#4C9BD4'),
(pos_pat, "patient", '#6DBF6D')]:
data = accs[name][stype]
bp = ax.boxplot(data, positions=[pos], widths=0.5,
patch_artist=True, showfliers=True,
flierprops=dict(marker='o', markersize=3))
bp['boxes'][0].set_facecolor(color)
med = np.median(data)
ax.annotate(f"{med:.3f}", (pos, med), fontsize=6,
ha='center', va='bottom')
ax.legend(handles=[
Patch(facecolor='#4C9BD4', label='Image-level split'),
Patch(facecolor='#6DBF6D', label='Patient-level split'),
], loc='lower right')
ax.set_xticks([p + 1 for p in range(0, len(MODELS) * 2, 2)])
ax.set_xticklabels(MODELS)
ax.set_ylabel("Test accuracy")
ax.set_title("Figure 6 — Image-level vs Patient-level test accuracy (20 seeds)")
ax.set_ylim(0.7, 1.02)
ax.grid(axis='y', alpha=0.3)
plt.tight_layout()
out = os.path.join(ROOT, "plots", "figure6.png")
plt.savefig(out, dpi=150)
plt.close()
print(f"\nSaved → {out}")
print(f"Saved → {ROOT}/results/figure6_data.json")
print("DONE")