|
| 1 | +# Assay Transferability Lab |
| 2 | + |
| 3 | +A reproducible external-validation study of expression-based ER-status prediction across two public breast-tumor cohorts. The central question is whether a frozen model's **probabilities and decisions** transfer, rather than whether it retains a high AUROC. |
| 4 | + |
| 5 | +[Read the findings](reports/reference/FINDINGS.md) · [Analysis contract](docs/DESIGN.md) · [Scientific decisions](docs/DECISIONS.md) · [Public data and attribution](data/README.md) · [Validation evidence](docs/VALIDATION.md) |
| 6 | + |
| 7 | +## Experiment |
| 8 | + |
| 9 | +Develop on **GSE7390 / TRANSBIG**, hold out **GSE3494 / Uppsala** as an entire external study. Use 198 development and 247 labelled external specimens on the same 22,283-probe GPL96 platform. Four target records with uncertain ER labels are explicitly excluded. Labels come from the original GEO metadata and series-level clinical tables, joined by exact specimen/patient IDs. |
| 10 | + |
| 11 | +Four fixed models compare source-prevalence, literature-motivated ESR1-only prediction, deposited-scale multivariable prediction and specimen-local rank-normalized prediction. Training-only feature selection and scaling are repeated inside each source CV fold. The external cohort is never used to tune, select, normalize or calibrate the ER predictors. All specified comparisons are reported, including failure. |
| 12 | + |
| 13 | +This is retrospective prediction of depositor-coded ER status, not a clinical assay, survival analysis, novel biomarker discovery or a demonstration of analytical equivalence. Reference-label procedures and cohort selection differ. Those limits are part of the findings. |
| 14 | + |
| 15 | +## Reproduce with Docker |
| 16 | + |
| 17 | +```sh |
| 18 | +docker compose build |
| 19 | +docker compose run --rm lab python -m pytest -q |
| 20 | +docker compose run --rm lab |
| 21 | +docker compose run --rm lab python -m transferlab.verify artifacts/run |
| 22 | +``` |
| 23 | + |
| 24 | +The first analysis run downloads about 66 MiB of public files and validates pinned SHA-256 values. Named volumes retain raw data and analysis results; subsequent runs verify and reuse the cache. No credentials are needed for GEO. The image runs as UID 10001 with one BLAS thread. Dependencies are hash-locked; the Python base is pinned by manifest digest. |
| 25 | + |
| 26 | +Export the generated results to the host without changing directory permissions: |
| 27 | + |
| 28 | +```sh |
| 29 | +docker compose run --rm -T lab tar -C /lab/artifacts -czf - run > transferability-results.tar.gz |
| 30 | +``` |
| 31 | + |
| 32 | +The archive includes the findings, PNG figures, specimen-level predictions, model artifact, selected probe coefficients, subgroup counts, data audit and source-fit receipt. To remove the project containers and networks, use `docker compose down`; add `--volumes` only if you intend to remove the cached source and generated results. |
| 33 | + |
| 34 | +## Local Python |
| 35 | + |
| 36 | +Python 3.12+ is supported; the validated container uses Python 3.13. |
| 37 | + |
| 38 | +```sh |
| 39 | +python3 -m venv .venv |
| 40 | +.venv/bin/python -m pip install --require-hashes -r requirements.lock |
| 41 | +PYTHONPATH=src .venv/bin/python -m pytest -q |
| 42 | +OPENBLAS_NUM_THREADS=1 OMP_NUM_THREADS=1 PYTHONPATH=src .venv/bin/python -m transferlab run --output artifacts/run |
| 43 | +PYTHONPATH=src .venv/bin/python -m transferlab.verify artifacts/run |
| 44 | +``` |
| 45 | + |
| 46 | +The fixed plan is in `docs/analysis-plan.json`, with an initial Git protocol commit preceding model fitting. It is internal provenance, not independent preregistration. No minimum model accuracy is required for the project to report results. |
| 47 | + |
| 48 | +## What to inspect |
| 49 | + |
| 50 | +| Engineering or scientific concern | Implementation and evidence | |
| 51 | +|---|---| |
| 52 | +| Reproducible source acquisition | `data/sources.json`, strict hash verification and ID-based joins in `data.py` | |
| 53 | +| Leakage prevention | Specimen-local rank transform; pipeline-contained variance filtering, supervised feature selection and scaling | |
| 54 | +| External evaluation | Whole-study holdout, fixed threshold, AUROC, balanced accuracy, sensitivity/specificity, probability scores and conditional confidence intervals | |
| 55 | +| Scientific controls | ESR1-only baseline, prevalence baseline, full-pipeline source-label permutations and near-duplicate profile screening | |
| 56 | +| Verification | Independent rank-sum AUROC and direct confusion/Brier checks from saved predictions; tampered-evidence tests | |
| 57 | +| Traceability | Source/label hashes, feature and specimen hashes, fold IDs, fitted-artifact hash, code/dependency hashes and exclusions | |
| 58 | +| Container behavior | Digest-pinned multi-stage Docker build, non-root runtime, cached named volumes and network-free unit tests | |
| 59 | + |
| 60 | +```mermaid |
| 61 | +flowchart LR |
| 62 | + GEO[Checksum-bound GEO files] --> Parse[Strict expression and clinical-ID joins] |
| 63 | + Parse --> Source[Development study] |
| 64 | + Parse --> External[External study] |
| 65 | + Source --> CV[Source-only fold pipelines] |
| 66 | + Source --> Frozen[Final frozen source models] |
| 67 | + Frozen --> Receipt[Fit receipt and artifact hash] |
| 68 | + Frozen --> Predict[External predictions] |
| 69 | + External --> Predict |
| 70 | + Predict --> Evaluate[Prespecified metrics and uncertainty] |
| 71 | + CV --> Evaluate |
| 72 | + Evaluate --> Verify[Independent saved-output checks] |
| 73 | + Verify --> Report[Findings, plots and limitations] |
| 74 | +``` |
| 75 | + |
| 76 | +## Project layout |
| 77 | + |
| 78 | +- `src/transferlab/data.py`: acquisition, parsing, phenotype alignment and exclusions. |
| 79 | +- `model.py`: feature contracts, single-specimen transforms and source fitting. |
| 80 | +- `audit.py`: data summaries and sample-profile similarity. |
| 81 | +- `metrics.py`: outcome measures and bootstrap comparisons. |
| 82 | +- `analysis.py`: ordered execution, frozen-source receipt and negative controls. |
| 83 | +- `report.py`: figures and findings generated from calculated results. |
| 84 | +- `verify.py`: numerical reconciliation of saved outputs without loading model pickles. |
| 85 | +- `tests/`: strict-input, leakage-canary, invariance, metric and evidence-tampering checks. |
| 86 | +- `reports/reference/`: committed outputs from the validated Docker execution. Raw downloads are not committed. |
| 87 | + |
| 88 | +## Interpretation and reuse |
| 89 | + |
| 90 | +One external cohort cannot establish robustness across all laboratories, populations, platforms or reference assays. Neither high AUROC nor confidence-based abstention establishes clinical utility. The findings distinguish numerical results from mechanistic explanations that remain untested. |
| 91 | + |
| 92 | +Code is MIT-licensed. Public source data retain their original provenance and terms; the code license does not relicense GEO records. No employer, client or restricted-access data are included. |
0 commit comments