Working with CSV files — Python¶
This page explains how to load and explore your delivered CSV files using Python. Code examples use pandas, which is pre-installed on the OUH Data Science VM.
See Understanding your data first if you haven't already — it explains the folder structure and how datasets relate to each other.
Downloads¶
You can download ready-to-use scripts and open them directly on your VM:
- explore_data.py — plain Python script, run from a terminal or VS Code
- explore_data.ipynb — Jupyter Notebook, open from Jupyter or VS Code
To open Jupyter Notebook on your VM, open a terminal and run:
jupyter notebook
Setting your data path¶
All examples use a DATA_DIR variable pointing to the folder containing your dataset subfolders. Update this to match where your data is stored.
import os
import pandas as pd
# Windows
DATA_DIR = r"C:\Users\yourname\data"
# or shared storage
DATA_DIR = r"Z:\your-project\data"
# Linux
DATA_DIR = "/home/yourname/data"
Loading a dataset¶
Each dataset lives in its own subfolder containing one CSV file. This helper function finds and loads it:
def load_dataset(dataset_name):
folder = os.path.join(DATA_DIR, dataset_name)
csv_files = [f for f in os.listdir(folder) if f.endswith(".csv")]
if not csv_files:
raise FileNotFoundError(f"No CSV file found in {folder}")
filepath = os.path.join(folder, csv_files[0])
print(f"Loading: {filepath}")
return pd.read_csv(filepath)
Ignore the other files
Each folder also contains _SUCCESS, _committed_... and _started_... files. These are Spark metadata files — ignore them. The helper function above handles this automatically by only loading .csv files.
Loading demographics¶
demographics = load_dataset("demographics")
print(f"Rows: {len(demographics):,}")
print(demographics.head())
print(demographics.dtypes)
Exploring a dataset¶
# Load a clinical dataset
diagnosis = load_dataset("diagnosis")
# Basic info
print(f"Rows: {len(diagnosis):,}")
print(f"Columns: {list(diagnosis.columns)}")
# Preview
print(diagnosis.head())
# Check for missing values
print(diagnosis.isnull().sum())
# Summary statistics for numeric columns
print(diagnosis.describe())
Joining datasets¶
All datasets link to demographics via salted_warehouse_identifier. Use this as your join key:
# Inner join — only patients present in both tables
merged = demographics.merge(
diagnosis,
on="salted_warehouse_identifier",
how="inner"
)
print(f"Merged rows: {len(merged):,}")
print(f"Unique patients: {merged['salted_warehouse_identifier'].nunique():,}")
# Left join — all demographics rows, with diagnosis where available
merged_left = demographics.merge(
diagnosis,
on="salted_warehouse_identifier",
how="left"
)
Working with dates¶
Date columns are loaded as strings by default. Convert them to datetime for date-based analysis:
demographics["BIRTH_DT_TM"] = pd.to_datetime(demographics["BIRTH_DT_TM"], errors="coerce")
demographics["DECEASED_DT_TM"] = pd.to_datetime(demographics["DECEASED_DT_TM"], errors="coerce")
# Calculate age at a reference date
import datetime
reference_date = pd.Timestamp("2024-01-01")
demographics["age"] = (reference_date - demographics["BIRTH_DT_TM"]).dt.days / 365.25
print(demographics["age"].describe())
Listing all available datasets¶
datasets = [
d for d in os.listdir(DATA_DIR)
if os.path.isdir(os.path.join(DATA_DIR, d))
]
for d in sorted(datasets):
folder = os.path.join(DATA_DIR, d)
csv_files = [f for f in os.listdir(folder) if f.endswith(".csv")]
if csv_files:
size_mb = os.path.getsize(os.path.join(folder, csv_files[0])) / (1024 * 1024)
print(f"{d:<45} {size_mb:.1f} MB")
Saving results¶
Save outputs to your VM's local storage or shared storage. Do not save identifiable data.
# Save a summary table
summary = demographics["SEX"].value_counts().reset_index()
summary.columns = ["sex", "count"]
summary.to_csv(os.path.join(DATA_DIR, "sex_summary.csv"), index=False)
When you are ready to export results out of the TRE, use the airlock. See Airlock requests and Egress and disclosure control for guidance.