$npx -y skills add Aperivue/medsci-skills --skill profile-imagingProfile a medical-imaging dataset before any modelling decision is made — the acquisition grid, voxel spacing and orientation spread, the intensity domain, which label values are actually present, how much of the volume the target occupies, and how large the target is in millilit
| 1 | # Profile-Imaging Skill |
| 2 | |
| 3 | ## Purpose |
| 4 | |
| 5 | A dataset decides more of a study than the architecture does, and it decides it **first**. Before |
| 6 | anything is preprocessed, split, or trained, a handful of facts are already true about the data, and |
| 7 | each one closes off or opens up a research plan: |
| 8 | |
| 9 | - If the target occupies 0.4 % of the volume, accuracy is not a metric — predicting background |
| 10 | everywhere scores 99.6 %. |
| 11 | - If through-plane spacing runs 1.5–8 mm inside a single institution, resampling is not a default to |
| 12 | accept quietly; it is the most consequential preprocessing choice in the study, and it is also the |
| 13 | axis along which an external dataset will differ. |
| 14 | - If the directory named `imagesTs` has no labels, it is not a test set, and the held-out set has to |
| 15 | come from somewhere else — better known before training than after. |
| 16 | - If the organ volume spans 56–502 mL when normal is roughly 100–250, the cohort contains disease |
| 17 | that a subgroup analysis should be **pre-specified** for, rather than discovered post hoc. |
| 18 | |
| 19 | None of that requires a model, a GPU, or an engineer. It requires reading every file once and |
| 20 | writing down what is there. This skill does that, and then audits the plan against it. |
| 21 | |
| 22 | It is the **front door** of the model-engineering lane: |
| 23 | `profile-imaging (describe)` → `/design-study` + `/architecture-zoo` (decide) → |
| 24 | `/preprocess-imaging` (plan the pipeline) → `/model-scaffold` (build) → `/model-validation` → |
| 25 | `/model-evaluation`. |
| 26 | |
| 27 | ## When to use |
| 28 | - You have a dataset and a task, and need to know what the data will and will not support before |
| 29 | committing to a plan. |
| 30 | - You inherited a dataset and need its integrity established (labels intact, splits labelled, |
| 31 | label values as declared) before anyone trains on it. |
| 32 | - You are about to write a Methods section that describes the cohort and its acquisition. |
| 33 | |
| 34 | ## When NOT to use |
| 35 | - Tabular / clinical variables → `/generate-codebook` (data dictionary) and `/clean-data`. |
| 36 | - Designing the preprocessing pipeline and auditing it for data-stage leakage → |
| 37 | `/preprocess-imaging` (it consumes what this skill describes). |
| 38 | - Auditing the train/val/test split table → `/model-validation`. |
| 39 | - Choosing an architecture → `/architecture-zoo`. Building the repo → `/model-scaffold`. |
| 40 | - Held-out metrics, calibration, subgroup results → `/model-evaluation` then `/analyze-stats`. |
| 41 | |
| 42 | ## Workflow |
| 43 | |
| 44 | ### Step 1 — profile every case |
| 45 | |
| 46 | ```bash |
| 47 | python3 scripts/profile_imaging_dataset.py \ |
| 48 | --split train:imagesTr:labelsTr \ |
| 49 | --split test:imagesTs \ |
| 50 | --dataset "MSD Task09 Spleen" \ |
| 51 | --declared-labels 0=background,1=spleen \ |
| 52 | --plan resample=true,reorient=false,loss=dice_ce,metrics=dice+hd95 \ |
| 53 | --out eda/profile.json |
| 54 | ``` |
| 55 | |
| 56 | One record per case: grid, spacing, orientation, intensity percentiles, the label values actually |
| 57 | present, foreground fraction, and target volume in mL. A `--split` given no label directory is |
| 58 | recorded as **unlabelled** — which is itself a finding. |
| 59 | |
| 60 | Requires `nibabel` + `numpy` (it has to open images). The gate below does not. |
| 61 | |
| 62 | ### Step 2 — gate the profile against the declared plan |
| 63 | |
| 64 | ```bash |
| 65 | python3 scripts/check_dataset_profile.py --profile eda/profile.json \ |
| 66 | --out qc/dataset_profile.json --strict |
| 67 | ``` |
| 68 | |
| 69 | Stdlib-only, so the audit re-runs anywhere the JSON travels. Verdicts: |
| 70 | |
| 71 | | Verdict | Severity | Fires when | |
| 72 | |---|---|---| |
| 73 | | `LABEL_SHAPE_MISMATCH` | Major | label grid ≠ image grid | |
| 74 | | `LABEL_EMPTY` | Major | a labelled case has zero foreground | |
| 75 | | `LABEL_VALUE_UNEXPECTED` | Major | label values |