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:
@@ -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")
|
||||
Reference in New Issue
Block a user