| """Produce comprehensive statistics on the current healthy-brain corpus.""" |
| import pandas as pd |
| from pathlib import Path |
| import textwrap |
|
|
| ROOT = Path("/home/MRI-DataSet") |
| df = pd.read_csv(ROOT / "manifest.csv") |
|
|
| out = [] |
| out.append("=" * 72) |
| out.append("HEALTHY-BRAIN TRAINING CORPUS — FINAL SNAPSHOT") |
| out.append("=" * 72) |
| out.append(f"Manifest: {ROOT/'manifest.csv'}") |
| out.append(f"Golden-0-to-25 (primary): {ROOT/'Golden-0-to-25'}/") |
| out.append(f"Golden-25plus (fine-tune): {ROOT/'Golden-25plus'}/") |
| out.append("") |
|
|
| |
| total = len(df) |
| healthy = (df["healthy"] == True).sum() |
| with_age = df["age_years"].notna().sum() |
| age025 = ((df["age_years"].notna()) & (df["age_years"] < 25)).sum() |
| age25p = ((df["age_years"].notna()) & (df["age_years"] >= 25)).sum() |
| no_age = df["age_years"].isna().sum() |
|
|
| out.append(f"Total scans: {total}") |
| out.append(f"Labelled healthy: {healthy} ({100*healthy/total:.1f}%)") |
| out.append(f"With known age: {with_age} ({100*with_age/total:.1f}%)") |
| out.append(f" age < 25 (primary): {age025}") |
| out.append(f" age >= 25 (pretrain): {age25p}") |
| out.append(f"Unknown age (to impute): {no_age}") |
| out.append("") |
|
|
| |
| if with_age: |
| ages = df["age_years"].dropna() |
| out.append("Age distribution (years) over dated scans:") |
| out.append(f" min={ages.min():.1f} median={ages.median():.1f} max={ages.max():.1f}") |
| out.append(f" mean={ages.mean():.1f} ± {ages.std():.1f}") |
| out.append("") |
|
|
| |
| if "split" in df.columns: |
| out.append("-" * 72) |
| out.append("SPLIT BREAKDOWN") |
| out.append("-" * 72) |
| for split, grp in df.groupby("split"): |
| n = len(grp) |
| h = (grp["healthy"] == True).sum() |
| ages = grp["age_years"].dropna() |
| rng = f"{ages.min():.1f}-{ages.max():.1f}" if len(ages) else "n/a" |
| out.append(f" {split:<28} {n:>5} scans (healthy={h}) range={rng}") |
| out.append("") |
|
|
| |
| out.append("-" * 72) |
| out.append("PER-DATASET BREAKDOWN") |
| out.append("-" * 72) |
| out.append(f"{'dataset':<28}{'scans':>7}{'healthy':>9}{'age<25':>8}{'age>=25':>9}" |
| f"{'age range':>18}") |
| out.append("-" * 72) |
| for ds, grp in df.groupby("dataset"): |
| n = len(grp) |
| h = (grp["healthy"] == True).sum() |
| a = ((grp["age_years"].notna()) & (grp["age_years"] < 25)).sum() |
| b = ((grp["age_years"].notna()) & (grp["age_years"] >= 25)).sum() |
| ages = grp["age_years"].dropna() |
| if len(ages): |
| rng = f"{ages.min():.1f}-{ages.max():.1f}" |
| else: |
| rng = "n/a" |
| out.append(f"{ds:<28}{n:>7}{h:>9}{a:>8}{b:>9}{rng:>18}") |
| out.append("-" * 72) |
| out.append("") |
|
|
| |
| out.append("AGE HISTOGRAM (5-year bins, across all dated scans)") |
| ages = df["age_years"].dropna() |
| if len(ages): |
| max_age = int(ages.max()) + 5 |
| edges = list(range(0, max_age + 1, 5)) |
| counts, _ = pd.cut(ages, bins=edges, right=False, include_lowest=True).value_counts(sort=False), None |
| for interval, n in counts.items(): |
| bar = "#" * int(40 * n / counts.max()) |
| out.append(f" [{interval.left:>3}, {interval.right:>3}) {n:>5} {bar}") |
| out.append("") |
|
|
| |
| out.append("=" * 72) |
| out.append("TARGET SPLITS FOR TRAINING") |
| out.append("=" * 72) |
| out.append("") |
| out.append(textwrap.dedent(f"""\ |
| Primary training (0-25 years) : {age025:>5} scans |
| Pretraining pool (25+ years) : {age25p:>5} scans |
| Grand total labelled : {age025+age25p:>5} scans |
| |
| Strategy (per user): |
| 1. Train EfficientNet-B3 multi-view on Training_0to25/ (pediatric + young adult) |
| 2. Ablation: pretrain on Training_0to25 + Pretrain_25plus |
| (full lifespan), then fine-tune on 0-25 |
| 3. Compare pediatric MAE between the two strategies in thesis |
| """)) |
|
|
| text = "\n".join(out) |
| print(text) |
| (ROOT / "STATISTICS.md").write_text(text) |
| (ROOT / "STATISTICS.txt").write_text(text) |
| print(f"\n-> wrote {ROOT/'STATISTICS.md'} and {ROOT/'STATISTICS.txt'}") |
|
|