Part 0 — Data Preparation#
Goal of this notebook: load the raw multi-omics TCGA-BRCA data, split patients into train/test sets, and save that split to disk so every later notebook in the workshop uses the exact same patients for training and testing.
We work with three “omic views” for each patient:
View |
What it measures |
# features |
|---|---|---|
|
gene expression (RNA-seq) |
~30,000 |
|
protein abundance |
~460 |
|
DNA methylation (epigenetic marks) |
~200,000 |
The prediction target is the PAM50 molecular subtype of breast cancer
(LumA, LumB, Basal, Her2, Normal).
1. Imports#
from pathlib import Path
import pickle
from s2_helpers import load_omics
from sklearn.model_selection import train_test_split
2. Load the multi-omics data#
load_omics reads the pre-processed TCGA-BRCA data for the requested omic views and
returns:
X_views— a dict mapping each omic name to a(patients × features)DataFramey_raw— a Series of PAM50 subtype labels, indexed by patient ID
All views and the label are aligned on the same set of patients.
# Path to the shared (workshop-wide) data directory
DATA_DIR = Path("/data/")
# Load the three omic views we'll use throughout the workshop, plus the subtype labels
X_views, y_raw = load_omics(
DATA_DIR,
omic_keys=["transcriptomics", "proteomics", "methylation"],
)
Omic view dimensions:
transcriptomics: 500 patients × 29995 features
proteomics : 500 patients × 464 features
methylation : 500 patients × 200000 features
Subtype counts:
paper_BRCA_Subtype_PAM50
LumA 237
LumB 100
Basal 97
Her2 41
Normal 25
Name: count, dtype: int64
3. Create a stratified train/test split#
We split on patient IDs only (not on any single omic matrix) so the same patients
end up in the same split across every view. stratify=y_raw keeps the proportion of
each PAM50 subtype roughly equal between train and test — important here since some
subtypes (e.g. Normal, Her2) have relatively few patients.
RANDOM_STATE is fixed so the split is reproducible across the whole workshop.
RANDOM_STATE = 42
train_ids, test_ids = train_test_split(
y_raw.index.to_numpy(), # numpy array: sklearn can't index pandas 3's arrow-backed Index
test_size=0.25, # 75% train / 25% test
random_state=RANDOM_STATE,
stratify=y_raw, # preserve subtype proportions in both splits
)
print(f"Training patients : {len(train_ids)}")
print(f"Test patients : {len(test_ids)}")
Training patients : 375
Test patients : 125
4. Save the split for later notebooks#
We persist the train/test patient IDs to a pickle file. Every subsequent notebook in the workshop loads this file instead of re-splitting, so results stay consistent and comparable across notebooks and participants.
splits_path = DATA_DIR / "patient_splits.pkl"
try:
with open(splits_path, "wb") as f:
pickle.dump({"train_ids": train_ids, "test_ids": test_ids}, f)
print(f"Saved patient splits to: {splits_path}")
except PermissionError:
# The shared workshop data dir is read-only. The split is deterministic
# (fixed seed), so the pre-generated file there must match what we just
# computed - verify that instead of writing.
with open(splits_path, "rb") as f:
existing = pickle.load(f)
assert set(existing["train_ids"]) == set(train_ids), (
f"{splits_path} does not match this run's split - "
"ask an instructor to regenerate it from the current omics.pkl")
print(f"Data dir is read-only; verified pre-generated splits at: {splits_path}")
---------------------------------------------------------------------------
PermissionError Traceback (most recent call last)
Cell In[5], line 3
1 splits_path = DATA_DIR / "patient_splits.pkl"
2
----> 3 with open(splits_path, "wb") as f:
4 pickle.dump({"train_ids": train_ids, "test_ids": test_ids}, f)
5
6 print(f"Saved patient splits to: {splits_path}")
PermissionError: [Errno 13] Permission denied: '/data/patient_splits.pkl'