Smoke job repo: grouped tabular dataset + config
400 rows / 200 patients, two samples each, so grouped splitting is actually exercised. Signal is modest and noisy on purpose — a separable toy would score 1.0 with a broken model and prove nothing.
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
"""Generate the smoke dataset. Deterministic — rerunning reproduces the file byte
|
||||
for byte, so the committed CSV can always be regenerated and diffed.
|
||||
|
||||
Signal is real but modest: the label depends on age/iop/cdr with noise, so a
|
||||
working pipeline lands around 0.85-0.95 AUC and a broken one sits near 0.5. A
|
||||
perfectly separable toy would hide bugs by scoring 1.0 no matter what.
|
||||
"""
|
||||
import csv, math, random
|
||||
from pathlib import Path
|
||||
|
||||
rng = random.Random(20260813)
|
||||
N_PATIENTS, EYES = 200, 2
|
||||
SITES = ["skovde", "gothenburg", "linkoping"]
|
||||
out = Path(__file__).resolve().parents[1] / "data" / "smoke" / "labels.csv"
|
||||
|
||||
rows = []
|
||||
for p in range(N_PATIENTS):
|
||||
# Patient-level traits: both samples from one patient share them, which is
|
||||
# what makes grouped splitting matter — a per-row split would leak.
|
||||
base_age = rng.gauss(62, 11)
|
||||
site = rng.choice(SITES)
|
||||
frailty = rng.gauss(0, 1)
|
||||
for e in range(EYES):
|
||||
age = base_age + rng.gauss(0, 1.5)
|
||||
iop = rng.gauss(16 + 2.2 * frailty, 2.8) # intraocular pressure
|
||||
cdr = min(0.95, max(0.05, rng.gauss(0.45 + 0.09 * frailty, 0.11))) # cup/disc
|
||||
rnfl = rng.gauss(95 - 7 * frailty, 9) # retinal nerve fibre layer
|
||||
noise = rng.gauss(0, 1)
|
||||
logit = -6.0 + 0.045 * age + 0.20 * iop + 4.2 * cdr - 0.035 * rnfl + 0.5 * noise
|
||||
pos = rng.random() < 1 / (1 + math.exp(-logit))
|
||||
rows.append({
|
||||
"sample_id": f"S{p:03d}_{e}",
|
||||
"patient_id": f"P{p:03d}",
|
||||
"age": round(age, 1),
|
||||
"iop": round(iop, 1),
|
||||
"cdr": round(cdr, 3),
|
||||
"rnfl": round(rnfl, 1),
|
||||
"noise_feat": round(noise, 3),
|
||||
"site": site,
|
||||
"notes": "routine screening" if not pos else "referred",
|
||||
"diagnosis": "glaucoma" if pos else "healthy",
|
||||
})
|
||||
|
||||
out.parent.mkdir(parents=True, exist_ok=True)
|
||||
with out.open("w", newline="") as fh:
|
||||
w = csv.DictWriter(fh, fieldnames=list(rows[0]))
|
||||
w.writeheader()
|
||||
w.writerows(rows)
|
||||
|
||||
pos = sum(r["diagnosis"] == "glaucoma" for r in rows)
|
||||
print(f"wrote {out} rows={len(rows)} patients={N_PATIENTS} positives={pos} ({pos/len(rows):.0%})")
|
||||
Reference in New Issue
Block a user