Skip to content

Commit 96d5137

Browse files
Add attribution analyses, reproducibility metadata, and CI
1 parent 407a496 commit 96d5137

43 files changed

Lines changed: 3531 additions & 5852 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
jobs:
8+
test:
9+
runs-on: ubuntu-latest
10+
defaults:
11+
run:
12+
shell: bash -l {0}
13+
14+
steps:
15+
- uses: actions/checkout@v4
16+
17+
- uses: mamba-org/setup-micromamba@v2
18+
with:
19+
micromamba-version: latest
20+
environment-file: environment.yml
21+
init-shell: bash
22+
cache-environment: true
23+
create-args: cpuonly # CPU-only PyTorch; avoids large CUDA download on runners
24+
25+
- name: Smoke test — Phase 1 → Phase 2 on synthetic data
26+
run: bash test_run.sh
27+
28+
- name: Unit tests
29+
run: pytest -q

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ geno_ld/
55
metadata/
66

77
# Un-ignore the synthetic smoke-test generator (script only, not generated files).
8-
# data/* is used (not data/) so git can traverse into data/synthetic/ for exceptions.
9-
data/
8+
data/*
109
!data/synthetic/
1110
data/synthetic/region_blocks/
1211
data/synthetic/block_plan/
@@ -42,3 +41,4 @@ build/
4241
# IDE
4342
.vscode/
4443
.idea/
44+
.claude/

CLAUDE.md

Lines changed: 0 additions & 46 deletions
This file was deleted.

README.md

Lines changed: 77 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Block-Based Genotype Embedding Analysis
22

3+
[![CI](https://github.com/shraddhapiparia/blockbased-genotype-embedding-analysis/actions/workflows/ci.yml/badge.svg)](https://github.com/shraddhapiparia/blockbased-genotype-embedding-analysis/actions/workflows/ci.yml)
4+
5+
Status: ongoing research. README reflects current findings; documentation, CI, and tests are being added incrementally.
6+
37
Unsupervised learning of subject-level genomic representations from LD-aware blocks,
48
with application to asthma-relevant loci and downstream phenotype association.
59

@@ -32,14 +36,19 @@ The result is an embedding that is biologically interpretable (attention scores)
3236
axis of subject-level variation.
3337
- **HLA block embeddings outperform ancestry PCs.** HLA block_PC1 explains subject
3438
cluster structure beyond what genotype PC1–10 can account for, confirming genuine
35-
biological signal rather than ancestry confounding.
39+
biological signal rather than ancestry confounding. HLA sb15 η² = 0.767 vs η² = 0.051
40+
for genotype PC3 (script `02_subject_cluster_analysis.py`, step C;
41+
`results/output_regions2/ORD/clustering/hla_block_cluster_association.tsv` and
42+
`results/output_regions2/ORD/clustering/genotype_pc_cluster_association.tsv`).
3643
- **PDE4D emerges after masking HLA.** A leave-HLA-out re-clustering experiment
3744
(script `03_leave_hla_out_analysis.py`) reveals PDE4D as the next most structurally
3845
informative block — consistent with its established role in asthma and β-agonist
3946
pharmacogenomics.
4047
- **Phenotype signal is real but subtle; IgE is the strongest.** Continuous phenotypes
41-
(blood eosinophil count, IgE, lung function spirometry test, exacerbation) show the most consistent association
42-
with block-level PC features across subjects.
48+
(blood eosinophil count, IgE, lung function spirometry test, exacerbation) show the
49+
most consistent association with block-level PC features across subjects
50+
(script `01_block_embedding_phenotype_analysis.py`;
51+
`results/output_regions2/ORD/all_blocks_pheno_analysis/phenotype_block_associations.tsv`).
4352
- **Biology recovered without phenotype labels.** The model was trained unsupervised on
4453
genotype data only. The emergence of HLA class II and PDE4D in post-hoc analysis
4554
validates that the learned geometry reflects known asthma biology.
@@ -53,10 +62,12 @@ components reflect ancestry rather than disease-relevant biology. Phase 1 VAE em
5362
preserve local LD-block haplotype structure that SNP-level PCA discards. Phase 2 adds
5463
cross-block context: the Transformer learns which blocks co-vary meaningfully across
5564
subjects, reorganizing rather than destroying the Phase 1 geometry (Phase 1 vs Phase 2
56-
pairwise-distance correlation ≈ 0.68). The result is a subject-level space where HLA
57-
class II dominates the primary axis, PDE4D emerges as the next structurally informative
58-
block after HLA removal, and IgE shows stronger phenotype association — biological signal
59-
that ancestry-adjusted PCA does not recover.
65+
median pairwise-distance Spearman r ≈ 0.68 across blocks; script
66+
`06_phase1_phase2_block_comparison.py`,
67+
`results/phase_comparison/pdm_correlations.csv`). The result is a subject-level space
68+
where HLA class II dominates the primary axis, PDE4D emerges as the next structurally
69+
informative block after HLA removal, and IgE shows stronger phenotype association —
70+
biological signal that ancestry-adjusted PCA does not recover.
6071

6172
---
6273

@@ -76,11 +87,15 @@ cross-block Transformer (Phase 2) to produce subject embeddings is shown above.
7687

7788
![Subject PCA colored by cluster](docs/images/subject_pca_clusters.png)
7889

79-
PCA of Phase 2 subject embeddings reveals three reproducible strata (`k=3`; ARI = 0.999).
80-
The weak silhouette score (`0.139`) indicates the learned space is structured as a
81-
continuous gradient rather than sharply separated clinical subtypes.
90+
PCA of Phase 2 subject embeddings reveals three reproducible strata (`k=3`; mean
91+
pairwise ARI = 0.999 across 50 random seeds). The weak silhouette score (`0.139`)
92+
indicates the learned space is structured as a continuous gradient rather than sharply
93+
separated clinical subtypes.
8294

83-
*Source: `scripts/analysis/02_subject_cluster_analysis.py`.
95+
*Source: ARI from `scripts/analysis/04_cluster_stability_analysis.py`
96+
(`results/output_regions2/ORD/cluster_stability/ari_kmeans_seeds.tsv`); silhouette from
97+
`scripts/analysis/02_subject_cluster_analysis.py` step A
98+
(`results/output_regions2/ORD/clustering/clustering_metrics.csv`).
8499
Filename: `docs/images/subject_pca_clusters.png`*
85100

86101
---
@@ -90,8 +105,12 @@ Filename: `docs/images/subject_pca_clusters.png`*
90105
![HLA class II dominates the learned embedding space](docs/images/hla_embedding_dominance.png)
91106

92107
HLA class II subblocks strongly organize the Phase 2 embedding space. HLA sb15 explains
93-
far more cluster variance than ancestry PCs (η² = 0.767 vs 0.051 for genotype PC3) and
94-
correlates strongly with the main embedding axis (EmbedPC1 r = −0.88).
108+
far more cluster variance than ancestry PCs (η² = 0.767 vs 0.051 for genotype PC3;
109+
script `02_subject_cluster_analysis.py` step C,
110+
`results/output_regions2/ORD/clustering/hla_block_cluster_association.tsv`). HLA sb15
111+
block_PC1 also shows strong negative Spearman correlation with the main embedding axis;
112+
the specific value (r ≈ −0.88) was observed in exploratory analysis and is not yet
113+
tracked in a dedicated output table.
95114
*Source: `scripts/analysis/02_subject_cluster_analysis.py`.*
96115

97116
---
@@ -108,27 +127,62 @@ biologically coherent without supervised training.
108127

109128
---
110129

130+
## Limitations
131+
132+
- **Internal validation only.** All results are from a single cohort (COS/TRIO).
133+
Clustering structure, attention rankings, and phenotype associations have not been
134+
validated in an independent dataset.
135+
- **No causal inference.** Attention weights and LOBO/perturbation attribution scores
136+
identify blocks that are statistically influential for the learned embedding geometry.
137+
They are heuristic measures, not evidence of mechanistic importance or causality.
138+
- **Post-hoc phenotype associations.** Associations between embedding features and
139+
clinical phenotypes (IgE, eosinophils, FEV1, exacerbation) were tested after
140+
unsupervised training. They should be treated as hypothesis-generating and require
141+
external validation.
142+
- **Ancestry and generalizability.** The embedding was trained within a single ancestry
143+
stratum. Generalization to other ancestries or multi-ancestry cohorts has not been
144+
assessed.
145+
- **Data availability.** Input genotype and phenotype data are access-restricted and not
146+
version-controlled. Full reproduction from this repository requires obtaining restricted
147+
data access separately. The synthetic smoke test (`bash test_run.sh`) validates pipeline
148+
wiring only.
149+
- **Embedding geometry is not clinical classification.** The learned subject-level
150+
embedding space reflects genomic variation structure, not disease phenotype. Cluster
151+
membership does not imply clinical disease subtypes or therapeutic relevance.
152+
153+
---
154+
111155
## Repository Structure
112156

113157
```
114158
scripts/
115159
core/ Core pipeline — Phase 1 VAE, Phase 2 Transformer, block analysis, plotting
116-
analysis/ Numbered post-hoc scripts (01–07): phenotype association, clustering,
117-
HLA validation, confounder analysis, 17q21 validation
160+
analysis/ Numbered post-hoc scripts:
161+
01–07 phenotype association, clustering, HLA validation,
162+
confounder analysis, 17q21 validation
163+
08 clinical PC / embedding alignment (Pearson + Spearman, OLS, Ridge)
164+
09 Phase 2 block attribution — leave-one-block-out (LOBO)
165+
10 Phase 1 SNP attribution within selected blocks
118166
archive/ Superseded wrappers, exploratory one-offs, debug scripts
119-
configs/ YAML configs for Phase 1, Phase 2, and no-HLA variant
167+
configs/ YAML configs for Phase 1, Phase 2, no-HLA variant, and synthetic smoke test
120168
data/ Genotype block files and block manifest (access-restricted, not tracked)
169+
data/synthetic/ — generated synthetic data for smoke testing (gitignored)
121170
results/ Pipeline outputs (access-restricted, not tracked)
122171
metadata/ Phenotype table, eigenvec file (access-restricted, not tracked)
123172
docs/ Method notes and figures
173+
tests/ Lightweight unit tests (pytest); no real data required
124174
environment.yml
175+
pytest.ini
125176
WORKFLOW.md Step-by-step execution guide with CLI examples
126177
run_pipeline.sh Single entry point — runs full pipeline or --dry-run input check
178+
test_run.sh Smoke test — Phase 1 → Phase 2 on synthetic data (no restricted data needed)
127179
CLAUDE.md AI assistance constraints and workflow summary
128180
```
129181

130182
See [WORKFLOW.md](WORKFLOW.md) for full CLI instructions, expected inputs/outputs per
131-
step, and execution order.
183+
step, and execution order. See [docs/data_contract.md](docs/data_contract.md) for the
184+
Phase 1 → Phase 2 data format contract, subject/block ordering conventions, and common
185+
failure modes.
132186

133187
---
134188

@@ -150,6 +204,12 @@ python scripts/core/attention_phase2.py --config configs/config_phase2.yaml
150204

151205
# Post-hoc analysis (example)
152206
python scripts/analysis/03_leave_hla_out_analysis.py
207+
208+
# Attribution pipeline (scripts 08–10; requires Phase 2 outputs)
209+
python scripts/analysis/08_clinical_pc_embedding_alignment.py
210+
python scripts/analysis/09_phase2_block_attribution.py
211+
python scripts/analysis/10_phase1_snp_attribution_within_blocks.py \
212+
--selected-blocks region_9p24_IL33
153213
```
154214

155215
Use `--dry-run` on `run_pipeline.sh` or on either phase script to validate inputs without

WORKFLOW.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,34 @@ Scripts are numbered in intended execution order.
8888

8989
---
9090

91+
## Attribution scripts (08–10)
92+
93+
Run after Phase 2 and the core analysis scripts. Scripts 08–10 form a
94+
hierarchical attribution pipeline: embedding alignment → block attribution →
95+
SNP attribution.
96+
97+
| Script | Purpose | Key inputs | Key outputs |
98+
|---|---|---|---|
99+
| `08_clinical_pc_embedding_alignment.py` | Align learned Phase 2 embedding PCs with clinical phenotype PCs; Pearson + Spearman heatmaps; OLS and Ridge baselines including ancestry-PC-only model | Phase 2 `individual_embeddings.csv`, `ldpruned_997subs.eigenvec`, phenotype CSV | `correlation_heatmap_pearson.png`, `correlation_heatmap_spearman.png`, `embedding_pc_correlations.tsv`, R² comparison tables |
100+
| `09_phase2_block_attribution.py` | Leave-one-block-out (LOBO) attribution: for each of the 174 Phase 1 blocks, mean-mask it in the Phase 2 input and measure change in embedding PC1/PC2 and IgE ridge score | Phase 1 `all_blocks.npy`, Phase 2 checkpoint + `individual_embeddings.npy`, `block_order.csv`, `subjects.csv` | `phase2_PC1_leave_one_block_out.csv`, `phase2_PC2_leave_one_block_out.csv`, `phase2_log10Ige_leave_one_block_out.csv`, top-20 bar plots |
101+
| `10_phase1_snp_attribution_within_blocks.py` | For user-selected blocks from script 09: mean-mask each SNP in the Phase 1 input, re-encode through the frozen VAE, re-run Phase 2, project onto fixed PCA axes, and rank SNPs by mean absolute delta | Phase 1 block checkpoints (`.pt`), per-block `.raw` genotype files, Phase 2 checkpoint + embeddings, script 09 LOBO CSVs (optional, enables block-weighted priority) | Per-block and combined `*_snp_attribution.csv`, bar plots |
102+
103+
```bash
104+
# Run 08 (requires Phase 2 outputs at default paths)
105+
python scripts/analysis/08_clinical_pc_embedding_alignment.py
106+
107+
# Run 09
108+
python scripts/analysis/09_phase2_block_attribution.py
109+
110+
# Run 10 (requires --selected-blocks from 09 results)
111+
python scripts/analysis/10_phase1_snp_attribution_within_blocks.py \
112+
--selected-blocks region_9p24_IL33,region_6p21_HLA_classII_sb15 \
113+
--lobo-pc1-csv results/analysis/phase2_block_attribution/phase2_PC1_leave_one_block_out.csv \
114+
--lobo-pc2-csv results/analysis/phase2_block_attribution/phase2_PC2_leave_one_block_out.csv
115+
```
116+
117+
---
118+
91119
## Archive
92120

93121
`scripts/archive/` contains scripts that are **not part of the active workflow**:

0 commit comments

Comments
 (0)