Data availability: The
data/directory is not included in this repository. It is archived separately on Zenodo (DOI: 10.5281/zenodo.21878615) and must be downloaded and unpacked into your local clone — see Downloading the Data below.
EXPRESSO (EXpression-Profile-RESponSe-Optimizer) is a drug-specific supervised LASSO logistic regression framework for transcriptome-based treatment response prediction. It evaluates predictive power of drug targets and biomarkers across patient cohorts using a Leave-One-Cohort-Out Cross-Validation (LOCOCV) strategy.
Two model variants are implemented:
- EXPRESSO-T: LASSO model with the known drug target gene(s) as penalty-free (regularization-exempt) features, with the rest of the transcriptome included as penalized predictors.
- EXPRESSO-B: Extends EXPRESSO-T by additionally including context-specific biomarkers — identified via a nested LOCOCV differential expression procedure — as penalty-free features alongside the target gene(s).
Two baseline models are included for comparison:
- Vanilla LASSO (
noTargetmode): Supervised LASSO with no biological prior; the full transcriptome is penalized equally. - Unsupervised target-only: Ranks patients by the expression of the target gene alone, with no model training.
project/
│
├── expresso_all.R # Main LOCOCV script (EXPRESSO-T / -B / vanilla)
├── expresso_biomarker_search.R # Nested LOCOCV biomarker discovery (EXPRESSO-B)
├── gene_signature_benchmarking.R # Gene signature benchmarking (LOCOCV)
├── expressoT_MLmodels_generate.py # Train/evaluate alternative ML models (EXPRESSO-T context)
├── expressoB_MLmodels_generate.py # Train/evaluate alternative ML models (EXPRESSO-B context)
├── Methods_benchmarking.ipynb # Jupyter notebook: Other methods benchmarking walkthrough
├── source_EXPRESSO_func.R # All shared R helper functions
├── renv.lock # Pinned R package versions (see Software Requirements)
├── renv/ # renv scaffolding (activate.R, settings.json)
├── SESSION_INFO.txt # sessionInfo() from the original analysis environment
├── environment.yml # Conda environment for the Python benchmarking scripts
├── spec-file.txt # Exact conda package spec (alternate reproducible install)
│
├── prospective/ # Prospective / independent validation pipeline
│ ├── source_EXPRESSO_func.R # All shared R helper functions
│ ├── expresso_prospective_predict.R # Get prediction for new cohort(s)
│ ├── expresso_single_cohort_predict.sh # Shell script to run full prospective pipeline
│ ├── pooled_models/ # Pooled models trained on all original cohorts, per drug
│ ├── prospec_data/ # Independent/prospective test cohorts -NOT included in this repo — download from Zenodo (DOI: 10.5281/zenodo.21878615 (https://doi.org/10.5281/zenodo.21878615)) (same layout as data/)
│ └── expresso_test_prospec/ # Prediction outputs (AUC summaries) written here
│
├── data/ # NOT included in this repo — download from Zenodo
│ │ # (see "Downloading the Data" below); layout once unpacked:
│ ├── <cohort>/ # One directory per drug cohort group
│ │ ├── metadata.tsv # Cohort metadata (cohort, cancer, type, drug, targets)
│ │ │ # TRAINING COHORTS ONLY — test cohorts must be excluded
│ │ ├── response.tsv # Sample-level treatment response labels
│ │ └── mrna/
│ │ └── <cohort_id>.rds # Expression matrix (genes × samples, numeric matrix)
│ ├── biomarkers/
│ │ └── <cohort>_biomarkers.tsv # Per-fold target/biomarker gene definitions
│ └── MultiAssayExperiment/
│ └── MAE_<drug>.rds # Publicly available cohorts as MAE objects, per drug
│
├── comparisons/
│ ├── final_signatures.tsv # Index of all 16 published gene signatures
│ ├── <signature_name>.tsv # One file per gene signature (gene lists)
│ └── ...
│
└── results/ # All output TSV files written here
prospective/pooled_models/is included directly in this repository. The top-leveldata/directory (original training cohorts, biomarker gene lists, and MultiAssayExperiment objects) andprospective/prospec_data/are hosted separately on Zenodo due to its size — see Downloading the Data below.
The data/ directory — cohort-level expression matrices, response labels, biomarker gene
lists, and MultiAssayExperiment objects — is archived separately on Zenodo rather than committed
to this repository.
- Zenodo record (DOI): 10.5281/zenodo.21878615
- Archive file:
expresso_aug2026.tar.gz
prospective/pooled_models/ and prospective/prospec_data/ are already included in this GitHub
repository and do not require this step — only the top-level data/ directory needs to be
downloaded.
-
Clone this repository, if you haven't already, and
cdinto it:git clone https://github.com/ruppinlab/EXPRESSO.git cd EXPRESSO -
Download the archive from Zenodo:
curl -L -o expresso_aug2026.tar.gz \ "https://zenodo.org/records/21878615/files/expresso_aug2026.tar.gz?download=1"(or use
wget -O expresso_aug2026.tar.gz "<same URL>", or download it directly from the Zenodo record page in a browser) -
Extract the archive:
tar -xzf expresso_aug2026.tar.gz
-
Move the extracted
data/directory into the repository root, so it sits alongsidecomparisons/andprospective/. Place theprospective/prospec_data/directory for validation cohorts. Check where extraction placed it first — some archive tools unpack into their own top-level folder (e.g.expresso_aug2026/data/) rather than directly into the current directory:ls # confirm where data/ landed after extraction mv expresso_aug2026/data ./data # adjust the source path if it differs
-
Confirm the directory landed in the right place:
ls data # beva biomarkers brafi cyclop MultiAssayExperiment pacli pd1mel pd1oth tras -
(Optional) remove the downloaded archive once extraction is confirmed:
rm expresso_aug2026.tar.gz
Once data/ is in place, the repository matches the structure described throughout this README,
and the pipeline can be run as documented below.
| Column | Description |
|---|---|
cohort |
Unique cohort identifier (e.g. GSE78220) |
cancer |
Cancer type |
type |
Sample type |
drug |
Drug/intervention name |
targets |
Drug target gene(s) |
| Column | Description |
|---|---|
cohort |
Cohort identifier (must match metadata.tsv) |
sample |
Sample ID (must match column names in expression matrix) |
response |
Responder or Non-responder |
A numeric R matrix with genes as row names and sample IDs as column names. Gene expression values should be in raw or log-scale; normalization is applied internally (see Normalization section).
| Column | Description |
|---|---|
test_id |
Cohort held out as test set for this fold |
target |
Comma-separated target gene(s) for target mode |
biomarkers |
Comma-separated biomarker genes for biomarker mode |
Raw gene expression values are rank-normalized within each sample (converting expression values to fractional ranks in [0, 1]) using the rank_normalization() function in source_EXPRESSO_func.R. This within-sample normalization is applied uniformly across all cohorts prior to model training.
The --normalization argument (default: "ranked") controls this behavior:
| Value | Description |
|---|---|
ranked |
Within-sample rank normalization to [0,1] — default, recommended |
NPN |
Nonparanormal transformation (rank + probit) |
raw |
No normalization applied |
This repository includes an renv.lock file (plus renv/activate.R and renv/settings.json) that pins the exact R package versions used for the analysis. Recommended setup:
install.packages("renv")
renv::restore() # reads renv.lock and installs the matching package versionsSESSION_INFO.txt records the full sessionInfo() output from the original analysis environment as an additional reference if you need to check a specific package version.
Alternatively, install the required packages manually:
install.packages(c(
"tidyverse", "data.table", "glmnet", "caret",
"rsample", "pROC", "limma", "parallel", "metap"
))
# For differential expression:
if (!requireNamespace("BiocManager", quietly = TRUE))
install.packages("BiocManager")
BiocManager::install("limma")pip install numpy pandas scipy matplotlibThis repository also includes environment.yml and spec-file.txt for reproducing the exact conda environment used for the benchmarking scripts:
conda env create -f environment.yml
# or, for an exact package-for-package match:
conda create --name expresso --file spec-file.txtAll stochastic procedures use fixed random seeds for full reproducibility:
set.seed(31052024)is called immediately before eachcv.glmnet()model build insource_EXPRESSO_func.R- The bootstrap CI functions in the Python comparison scripts use
np.random.default_rng(42)
Runs LOCOCV for a single drug and produces AUCs, odds ratios, and selected features.
Rscript expresso_all.R <intervention> <cohort> <biomarker_file> <mode> [normalization] [response_weights]| Argument | Description |
|---|---|
intervention |
Drug name (e.g. ICB, trastuzumab) |
cohort |
Cohort directory under data/ (e.g. pd1mel) |
biomarker_file |
TSV file under data/biomarkers/ with per-fold target/biomarker genes |
mode |
target (EXPRESSO-T), biomarker (EXPRESSO-B), or noTarget |
normalization |
(optional) ranked (default), NPN, or raw |
response_weights |
(optional) TRUE (default) or FALSE |
Drug-cohort reference table:
| Drug | intervention | cohort | biomarker_file |
|---|---|---|---|
| ICB – melanoma | ICB |
pd1mel |
pd1mel_biomarkers.tsv |
| ICB – non-melanoma | ICB |
pd1oth |
pd1oth_biomarkers.tsv |
| Trastuzumab | trastuzumab |
tras |
tras_biomarkers.tsv |
| Bevacizumab | bevacizumab |
beva |
beva_biomarkers.tsv |
| BRAFi | BRAFi |
brafi |
brafi_biomarkers.tsv |
| Paclitaxel | paclitaxel |
pacli |
pacli_biomarkers.tsv |
| Chemo-FAC-FEC | cyclophos |
cyclop |
cyclop_biomarkers.tsv |
Examples:
# EXPRESSO-T for Chemo-FAC-FEC
Rscript expresso_all.R cyclophos cyclop cyclop_biomarkers.tsv target
# EXPRESSO-B for ICB-melanoma
Rscript expresso_all.R ICB pd1mel pd1mel_biomarkers.tsv biomarker
# Vanilla LASSO (no target prior) for paclitaxel
Rscript expresso_all.R paclitaxel pacli pacli_biomarkers.tsv noTargetOutputs written to results/:
| File | Contents |
|---|---|
<intervention>_<cohort>_<mode>_expresso_AUCs.tsv |
Per-cohort AUC and odds ratio (mid.OR), plus Mean/Median summary rows |
<intervention>_<cohort>_<mode>_expresso_features.tsv |
Genes selected per fold with LASSO coefficients |
<intervention>_<cohort>_<mode>_expresso_features_frequency.tsv |
Aggregated gene selection frequency across all folds |
Note on filename convention for downstream comparison scripts: The Python comparison scripts (
expressoT_MLmodels_generate.py,expressoB_MLmodels_generate.py) expect AUC files named<intervention>_LOCOCV_lasso_AUCs.tsv. Rename or symlink the output fromexpresso_all.Raccordingly before running comparison scripts.
Runs the nested LOCOCV biomarker discovery procedure used to produce the per-fold biomarker gene lists for EXPRESSO-B. For each outer fold, identifies differentially expressed genes from the training cohorts using limma, combines fold-level p-values using Brown's method (to account for inter-fold dependence from overlapping training sets), and selects genes that improve LOCOCV AUC by ≥ 0.02 (ΔAUC criterion).
Rscript expresso_biomarker_search.R <intervention> <cohort> <target> [options]| Argument | Description |
|---|---|
intervention |
Drug name |
cohort |
Cohort identifier |
target |
Target gene(s), comma-separated (e.g. CD274 or TOP2A,TYMS) |
Key options:
| Option | Default | Description |
|---|---|---|
--de_fdr |
0.05 |
FDR cutoff for DE gene selection |
--de_logfc |
0.4 |
Minimum mean absolute log-fold-change |
--delta_auc |
0.02 |
Minimum ΔAUC to accept a biomarker gene |
--delta_pval |
0.05 |
Wilcoxon p-value threshold for ΔAUC test |
--max_biom |
3 |
Maximum biomarker genes to add per fold |
--ncores |
auto | Parallel cores for deltaAUC computation |
--result_dir |
<cohort>_cv_fold_results |
Output directory |
Examples:
Rscript expresso_biomarker_search.R ICB pd1mel CD274
Rscript expresso_biomarker_search.R trastuzumab tras ERBB2 --ncores 8 --max_biom 3Outputs written to --result_dir:
| File | Contents |
|---|---|
<intervention>_<cohort>_cv_result_<test_id>.rds |
Per-fold RDS with DE summary, deltaAUC results, selected biomarker genes |
<intervention>_<cohort>_summary_auc_results.tsv |
Summary AUC table across all folds |
The per-fold RDS files are used to populate the biomarkers column in <cohort>_biomarkers.tsv for input to expresso_all.R.
Evaluates a set of published gene signatures against all cohorts in a prospective (non-cross-validated) manner. Each signature is scored by the mean rank-normalized expression of its member genes; AUC is computed per cohort.
Rscript gene_signature_benchmarking.R <intervention> <cohort> <signatures_file> [options]| Argument | Description |
|---|---|
intervention |
Drug name (used in output filename) |
cohort |
Cohort identifier |
signatures_file |
TSV file with a signatures column listing signature names |
Key options:
| Option | Default | Description |
|---|---|---|
--sig_dir |
comparisons |
Directory containing per-signature TSV gene list files |
--result_dir |
comparisons |
Directory for output TSV |
--drug_label |
same as intervention |
Human-readable label in output table |
Example:
Rscript gene_signature_benchmarking.R trastuzumab tras comparisons/final_signatures.tsv \
--sig_dir comparisons --result_dir results --drug_label "Trastuzumab"Output: <intervention>_<cohort>_aucs_comparison_gene_signatures_long_loco_pros.tsv
Contains columns: cohort, AUC, drug, predictor (signature name).
The comparisons/ directory contains gene lists for all 16 published signatures used for benchmarking (e.g., TIDE, IMPRES, CYT, MammaPrint, OncotypeDX), each as a separate TSV file, along with references to the original publications. Signatures were implemented according to their original scoring procedures using the same rank-normalized expression data as EXPRESSO.
Generate LOCOCV AUC results for alternative machine learning models (Random Forest, XGBoost, SVM, KNN, MLP) in the EXPRESSO-T and EXPRESSO-B contexts respectively, for direct comparison with EXPRESSO. Both scripts also run paired Wilcoxon signed-rank tests against the LASSO reference, compute bootstrap 95% confidence intervals, and produce a publication-ready boxplot.
Output files follow the naming convention:
results/<intervention>_LOCOCV_<model>_AUCs.tsv
python expressoT_MLmodels_generate.py \
--results_dir results \
--intervention ICBmel \
--reference lasso \
--output_dir figures
python expressoB_MLmodels_generate.py \
--results_dir results \
--intervention ICBmel \
--reference lasso \
--output_dir figures| Option | Default | Description |
|---|---|---|
--results_dir |
(required) | Directory with <intervention>_LOCOCV_<model>_AUCs.tsv files |
--intervention |
(required) | Drug name matching the file prefix |
--reference |
lasso |
Reference model for Wilcoxon test |
--min_cohort_size |
0 |
Minimum cohort size filter |
--output_dir |
figures |
Directory for output PDF/PNG and stats TSV |
--n_boot |
2000 |
Bootstrap iterations for CI computation |
Outputs:
| File | Contents |
|---|---|
<intervention>_model_stats.tsv |
Mean AUC, 95% CI, Wilcoxon statistic, p-value, significance per model |
<intervention>_boxplot_AUC.pdf/.png |
Boxplot with per-cohort AUCs, jittered points, and significance stars |
A Jupyter notebook demonstrating a full end-to-end run of EXPRESSO-T and EXPRESSO-B for a single drug and cohort, including data loading, model training, AUC evaluation, and signature benchmarking. Intended as a reproducibility reference and example for new users.
The prospective/ directory contains scripts for applying a trained EXPRESSO model to new, completely unseen cohorts. Pre-trained pooled models (pooled_models/) and the independent/prospective cohort data (prospec_data/) are already included under prospective/, so reproducing the manuscript's prospective results only requires the prediction step below — no separate model training or download is needed.
data/
└── <cohort>/
├── metadata.tsv ← TRAINING cohorts only (test cohorts must be excluded)
├── response.tsv
└── mrna/
prospective/
├── prospec_data/
│ └── <cohort>/
│ ├── metadata.tsv ← TEST cohorts only
│ ├── response.tsv
│ └── mrna/
│ └── <cohort_id>.rds
│
├── pooled_models/ ← pooled model trained on all original cohorts, per drug
│ ├── <intervention>_<cohort>_target_expresso_pooled_model.rds
│ ├── <intervention>_<cohort>_target_gene_list.tsv
│ └── <intervention>_<cohort>_target_scale_params.rds ← training-data scaling params, applied to new cohorts before prediction
│
└── expresso_test_prospec/ ← prediction outputs written here
Important:
data/<cohort>/metadata.tsvmust contain training cohorts only. Test cohorts must be completely absent from this file. Mixing them in will produce a model that has seen the test data during training, invalidating the prospective evaluation.
Loads a saved pooled model and evaluates it on one or more new cohorts. Uses summarize_ORs() from source_EXPRESSO_func.R exactly as the training pipeline does, so AUC and OR values are directly comparable to LOCOCV results.
Rscript prospective/expresso_prospective_predict.R \
<model_rds> <gene_list_tsv> <data_dir> [cohort_names] [normalization]| Argument | Description |
|---|---|
model_rds |
Path to pooled model RDS, e.g. prospective/pooled_models/<...>_expresso_pooled_model.rds |
gene_list_tsv |
Path to the matching gene list TSV in the same directory |
data_dir |
Directory with metadata.tsv, response.tsv, mrna/ for test cohorts |
cohort_names |
(optional) comma-separated cohort IDs to evaluate — default: all in directory |
normalization |
(optional) ranked (default) — must match what was used during training |
The matching <...>_scale_params.rds file in pooled_models/ is loaded automatically alongside the model to standardize new-cohort expression consistently with training.
Examples:
# Evaluate all cohorts in the prospective directory
Rscript prospective/expresso_prospective_predict.R \
prospective/pooled_models/trastuzumab_tras_target_expresso_pooled_model.rds \
prospective/pooled_models/trastuzumab_tras_target_gene_list.tsv \
prospective/prospec_data/tras
# Evaluate specific cohorts only
Rscript prospective/expresso_prospective_predict.R \
prospective/pooled_models/ICB_pd1oth_target_expresso_pooled_model.rds \
prospective/pooled_models/ICB_pd1oth_target_gene_list.tsv \
prospective/prospec_data/pd1oth \
GSE281729_p1,GSE281729_p2,GSE274975Output written to prospective/expresso_test_prospec/:
| File | Contents |
|---|---|
<intervention>_<cohort>_<mode>_<dir>_AUC_summary.tsv |
Per-cohort AUC and OR (mid.OR), plus Mean/Median summary rows |
Shell wrapper that runs expresso_prospective_predict.R for all drug/cohort combinations below in one call:
bash prospective/expresso_single_cohort_predict.shDrug-cohort reference for prospective validation:
| Drug | intervention | cohort | Test cohorts |
|---|---|---|---|
| ICB – melanoma | ICB |
pd1mel |
davar24 |
| ICB – non-melanoma | ICB |
pd1oth |
GSE281729_p1, GSE281729_p2, GSE274975 |
ICB – lung (NSCLC-specific sub-model of pd1oth) |
ICB |
icblung |
GSE274975 |
| Trastuzumab | trastuzumab |
tras |
GSE130788, GSE243375, phs003576 |
| Chemo-FAC-FEC | cyclophos |
cyclop |
GSE122630, GSE123845_p2, GSE14764, GSE16716, GSE21974, GSE22226, GSE231629, GSE240671_p2, GSE25066, GSE260693, GSE32603, GSE34138, GSE41656, GSE42822_p2, GSE4779 |
Step 1: Biomarker discovery (produces per-fold biomarker gene lists)
└─ expresso_biomarker_search.R → <cohort>_biomarkers.tsv
Step 2: LOCOCV model evaluation
├─ expresso_all.R (mode=target) → EXPRESSO-T AUCs + features
├─ expresso_all.R (mode=biomarker) → EXPRESSO-B AUCs + features
└─ expresso_all.R (mode=noTarget) → Vanilla LASSO AUCs
Step 3: Alternative ML model evaluation
├─ expressoT_MLmodels_generate.py → RF, XGB, SVM, KNN, MLP AUCs (T context)
└─ expressoB_MLmodels_generate.py → RF, XGB, SVM, KNN, MLP AUCs (B context)
Step 4: Signature benchmarking
├─ gene_signature_benchmarking.R → Published signature AUCs per cohort
└─ Methods_benchmarking.ipynb → Interactive benchmarking walkthrough
Step 5: Statistical comparison and visualization
├─ expressoT_MLmodels_generate.py → EXPRESSO-T boxplot vs ML models
└─ expressoB_MLmodels_generate.py → EXPRESSO-B boxplot vs ML models
Step 6: Prospective validation (pooled models & test cohorts already included)
├─ prospective/expresso_prospective_predict.R → Predict on new cohort(s)
└─ prospective/expresso_single_cohort_predict.sh → Run all drug/cohort combinations at once
- The helper functions in
source_EXPRESSO_func.Rmust be in the same directory as the calling script, or the--source_filepath must be updated. - Cohorts containing dbGaP-restricted data require data access approval; results for those cohorts will differ from the manuscript until access is granted.
- Genes are restricted to those measured in at least 3 cohorts (controlled by
gene_cohort_cutoff_) to enable consistent cross-cohort model fitting. - For prospective validation,
data/<cohort>/metadata.tsvmust contain training cohorts only. Test cohorts live inprospective/prospec_data/<cohort>/metadata.tsv. - The gene list embedded in the saved model (read from
rownames(coef(mod))) is the authoritative source of gene ordering for prediction — it takes precedence over thegene_list.tsvfile. - The full list of cohorts used per drug is provided in Supplementary Table S1 of the manuscript.