๐Ÿงฌ Single-Cell Drug Response Prediction

A User-Intent Guided Repository (2021-2025)

Navigating the landscape of computational pharmacology. Whether you need zero-shot prediction on unseen cell types, mechanistic pathway interpretation, or large-scale screening simulations, find the right AI tool for your specific biological question.

Healshu in tennis whites on a teal court, reading match footage on a tablet while a wall chart shows four opponent profiles and a tray of tagged balls sits beside a pill marker
๐ŸŽพ Tennis analogy ยท Scouting stage

You scout the opponent before you play the point.

Predicting how a cell will respond to a drug is a scouting problem. Nobody has seen this particular tumour play, but thousands of hours of related footage already exist: bulk cell-line panels with measured IC50s. The job is to compress that footage into a report that still holds up against an opponent you have never faced โ€” a single cell, profiled with far noisier equipment.

1
Watch the tapes: train on what has already been measured โ€” GDSC and CCLE bulk cell-line panels with known IC50 or AUC values for each drug.
2
Write the report: distil those tapes into a transferable signature or model โ€” beyondcell's drug-signature enrichment, scDEAL's shared latent space โ€” rather than memorising per-line answers that never generalise.
3
Predict the match-up: apply the report to single cells. This needs explicit domain adaptation (SCAD's adversarial alignment, scDEAL's DaNN) because bulk and single-cell expression differ in dropout, sequencing depth and dynamic range.
4
Rewrite after the first set: check the prediction against observed response and update. A scouting report is provisional โ€” a cell that scores "resistant" may simply be cycling, low-depth, or badly represented in the training panel.
Three poses of Healshu: studying a tablet next to a magnified profile card, hitting a ball toward a pill-and-target marker, and standing ready with a racquet facing a shadowy unseen opponent
Scout Learn from labelled bulk cell lines.
Report Compress into a transferable signature.
Match-up Transfer to single cells, then check.
Figure: The Method Landscape โ€” Taxonomy by Learning Paradigm
The Method Landscape - Taxonomy by Learning Paradigm
Navigate the field at a glance: A hierarchical organization of all 19 methods by their underlying ML paradigm โ€” Discriminative (predict labels/scores), Generative (predict post-treatment states), Multi-modal (integrate modalities), and Agentic (autonomous pipelines). Use the Quick Selection Guide to find the best starting point for your specific task.

๐ŸŽฎ Concept: The Perturbation Vector

Before exploring specific tools, visualize the core challenge: moving a cell from a "Control" state to a "Treated" state. Modern AI methods (like CRISP) learn this vector field in high-dimensional space, while methods like State account for resistant subpopulations.

Gene Expression Dimension 1 Dimension 2
Control
Sensitive
Resistant
Figure: The Core Problem โ€” Perturbation Prediction as Vector Field Learning
The Core Problem: Perturbation Prediction as Vector Field Learning
Understanding the ML formulation: Drug response prediction is NOT binary classification โ€” it's learning a conditional transformation. Left: The biological question of predicting how cells change after treatment (Xtreated = f(Xcontrol, d)). Center: Modern methods (CRISP, State, CellOT) predict vector fields ฮ”x or transport maps T: P(control) โ†’ P(treated). Right: Why single-cell resolution matters โ€” bulk RNA-seq averages hide resistant subpopulations that determine treatment failure.

๐Ÿš€ Foundation Models & Transfer Learning

Goal: "I want to predict drug responses in new cell types or tissues that weren't in my training data, leveraging massive pre-trained knowledge."

CRISP

2025 Foundation Transfer

Uses embeddings from large foundation models (like scGPT) to enable zero-shot prediction of drug responses in unseen cell types. It maps perturbation effects across different cellular contexts.

State

2025 Transformer

A general-purpose Transformer trained on 100M+ cells. Uses set-based attention to model how entire populations of cells shift states under perturbation, rather than just single cells.

scFoundation

2024 100M Params

Large-scale pre-trained model on 50M+ cells using xTrimoGene architecture. Offers zero-shot capabilities for various downstream tasks, including drug response classification.

TransCDR

2024 Domain Adaptation

A deep learning model for cancer drug response prediction that transfers knowledge from bulk RNA-seq cell line data to single-cell patient data.

scDEAL

2022 Deep Transfer

Deep transfer learning framework that integrates bulk and single-cell RNA-seq to predict cancer drug responses, harmonizing feature spaces between the two modalities.

C2S-Scale

2025 27B LLM

LLMs (up to 27B params) trained on 1B+ transcriptomic tokens using Cell2Sentence. Enables zero-shot cell classification, perturbation prediction, and experimentally validated virtual drug screening.

๐Ÿงช Generative Perturbation (The "What If" Engines)

Goal: "I want to generate a synthetic gene expression profile or image of what a specific cell would look like after treatment."

CellOT

2023 Optimal Transport

Uses Neural Optimal Transport to learn a mapping between untreated and treated cell populations. Unlike standard style transfer, it respects the mathematical geometry of the cell state space.

FCR

2024 Causal VAE

Factorized Causal Representations. A VAE that disentangles cell identity from treatment effects, allowing for the generation of "counterfactual" single-cell states (e.g., "What if this specific cell had been treated?").

IMPA

2025 Image GAN

Generative model for morphological perturbations. Uses style transfer GANs to predict how cell shape and structure change under chemical or genetic perturbation from microscopy images.

SAMS-VAE

2023 Sparse VAE

Sparse Additive Mechanism Shift VAE. Models perturbation effects as sparse, additive shifts in latent space. Enables interpretable and composable predictions for drug combinations.

MORPH

2025 Cross-Modal VAE

Discrepancy-based VAE with attention for predicting perturbation outcomes across conditions and data modalities. First method to handle both transcriptomic and imaging data in a unified framework.

๐Ÿงฌ Mechanism & Interpretability

Goal: "I don't just want a prediction; I want to understand why a cell is sensitive. Which pathways or gene sets are driving the response?"

scPDS

2025 Pathway Transformer

Transforms gene expression into pathway activation scores before processing. Uses self-attention to capture interactions between biological pathways, offering high interpretability.

scGSDR

2025 Gene Semantics

Gene semantics-based profiling. It integrates cellular states with signaling pathways to identify interpretable resistance phenotypes rather than just black-box probabilities.

scDrug+

2024 GRN

Matrix factorization and SVM with molecular fingerprints show superior performance. Published in Biomedicine & Pharmacotherapy.

Beyondcell

2021 Enrichment

Uses drug signatures (collections of genes targeted by drugs) to calculate an enrichment score for each single cell, determining its "therapeutic state."

๐ŸŽฏ Synergy, Prioritization & Screening

Goal: "I have a patient sample. Which drug (or combination of drugs) should I prioritize for treatment?"

BAITSAO

2025 LLM Synergy

Unified drug synergy model powered by GPT-3.5 embeddings. It predicts how two drugs will interact (synergy/antagonism) across hundreds of thousands of combinations.

scDrugPrio

2024 Prioritization

An unbiased cell type-centric framework that prioritizes drugs based on single-cell disease signatures, helping identify candidates for repurposing.

scPharm

2025 Subpopulations

Identifies pharmacological subpopulations of single cells to reveal cell-type-specific vulnerabilities, aiding in precision oncology.

ASGARD

2023 Repurposing

Single-cell Guided pipeline to Aid Repurposing of Drugs. Designed to connect cell-specific targets to existing drug databases for new indications.

CaDRReS-Sc

2021 Recommender

A matrix factorization-based recommender system (like Netflix for drugs) that predicts clone-specific therapeutic vulnerabilities.

DrugReflector

2025 Active Learning

Deep learning ensemble trained on CMap signatures. Uses active reinforcement learning to iteratively refine hit discovery, achieving 13-17ร— improvement over random screening.

PBMF

2025 Biomarker

Predictive Biomarker Modeling Framework uses contrastive learning to distinguish treatment-specific predictive biomarkers from prognostic markers, improving clinical trial patient selection.

Combocat

2025 Combination

Open-source platform combining acoustic liquid handling with ML for drug combination screening. Sparse mode reduces measurements by 90% to enable the largest single-cell-line combo screen (9,045 pairs).

๐Ÿ“ธ Multi-Modal & Morphological

Goal: "I have image data (Cell Painting) or want to link molecular structures to phenotypes."
Figure: Multi-Modal Integration โ€” Beyond Transcriptomics
Multi-Modal Integration - Beyond Transcriptomics
Two paradigms for integrating imaging with drug response: Left (MolPhenix): Contrastive learning aligns Cell Painting images with molecular structures for zero-shot drug retrieval โ€” "find molecules that produce THIS phenotype." Right (GigaTIME): Translates cheap H&E slides into virtual 21-channel multiplex immunofluorescence (IF), predicting immunotherapy response biomarkers (CD8, PD-L1) as accurately as real IF. Bottom: Why multi-modal matters โ€” complementary information at different cost points enables cross-modal prediction as cheap proxy for expensive assays.

MolPhenix

2024 Image-to-Drug

Contrastive phenomolecular retrieval framework. It matches cell-painting images to molecular structures in a zero-shot manner, enabling virtual screening based on phenotype.

GigaTIME

2026 Virtual mIF

Cross-modal AI that translates H&E slides into virtual 21-channel multiplex IF images (40M cells trained). Enables population-scale tumor immune microenvironment analysis for drug response.

๐Ÿ“š Atlases, Databases & Benchmarks

Goal: "I need data to train my own model, or a standardized benchmark to test it."

Tahoe-100M

2025 bioRxiv

The largest single-cell perturbation atlas to date (95.6M cells). Profiles 379 drugs across 47 cancer cell lines with 1,138 drug-dose conditions. The "ImageNet" of perturbation biology.

ScDrugAct

2025 NAR

A comprehensive database characterizing drug activity at the single-cell level. Useful for retrieving reference activity signatures for specific compounds.

TDC-2

2024 NeurIPS

Therapeutics Data Commons 2. The gold standard for benchmarking. Includes specific tasks for single-cell drug target identification and perturbation prediction.

scDrug (Workflow)

2022 CSBJ

A one-stop software pipeline that takes raw scRNA-seq data and performs analysis through to drug response prediction. Good for users wanting a complete "box" solution.

๐Ÿค– AI Agents & Clinical Decision Support

Goal: "I want autonomous AI systems that can orchestrate multi-step drug discovery workflows or support clinical decisions."

Agentic AI in Drug Discovery

2025 Review

Comprehensive review of LLM-based agents with perception, computation, action, and memory tools. Documents case studies compressing drug discovery workflows from months to hours.

MTBBench

2025 NeurIPS

First agentic benchmark for molecular tumor board-style decisions. Tests multimodal, longitudinal reasoning with tool-augmented agents achieving 11.2% gains over baseline LLMs.

๐Ÿงซ Experimental Platforms & Translational Tools

Goal: "I need integrated wet-lab and computational platforms for drug testing or personalized therapy design."
Figure: From Prediction to Clinic โ€” The Translational Gap
From Prediction to Clinic - The Translational Gap
The complete pipeline from computation to clinical trial:

โ— Computational: scRNA-seq โ†’ AI Model (CRISP/State) โ†’ Prediction ("Drug X will affect Clone A")

โ— Experimental: Two validation case studies โ€” Tumor-on-a-Chip (Nat Biotech 2025) enhances CAR-T trafficking 8ร— through DPP4 inhibition (vildagliptin) via CXCR3-CXCL10/11 axis; MTBBench (NeurIPS 2025) benchmarks AI clinical decision support showing tool-augmented agents reach 69.1% accuracy (+9โ€“11.2% gain).

โ— Clinical: Phase I/II trials โ€” the validation hierarchy from in silico (publication) through in vitro, ex vivo, animal models, to human trials (FDA approval).

Current frontier: Tahoe-100M (95.6M cells, 379 drugs) and Tumor-on-a-Chip pushing methods to Level 2โ€“3 (ex vivo).

Tumor-on-a-Chip for CAR-T

2025 Nat Biotech

Microengineered tumor-on-a-chip enabling vascularized human tumor explants and CAR-T cell perfusion. Identified DPP4/CXCR3 axis as combination therapy target via ligand-receptor analysis.

CancerPAM

2025 Nat Comm

Multi-omics pipeline for personalized CRISPR gene therapy. Identifies tumor-specific PAM sites for cytokine knock-in to remodel tumor microenvironment and enhance CAR-T efficacy.

๐Ÿ› ๏ธ Hands-On Practice

The walkthrough below takes a QC'd tumour AnnData object all the way to a per-cell drug-sensitivity readout, along the two routes the field actually uses. Path A is training-free: score every cell against a curated drug signature collection (the beyondcell SSc/PSc idea, run here with decoupler in Python). Path B is the bulk-to-single-cell transfer route made popular by scDEAL and SCAD: train a sensitivity model on GDSC/CCLE cell-line expression with measured IC50 labels, then move it onto unlabelled single cells with an explicit domain-adaptation term. Everything is computational and retrospective โ€” no assay is run, and every conclusion is a hypothesis to be checked against existing data.

Environment & packages

The Python side (scanpy + decoupler + torch) covers signature scoring and the transfer model. beyondcell itself is an R/Seurat package, so it is installed separately if you want its native SSc/PSc collections and BCS ranking plots; the signature tables it ships can also be exported and consumed from Python.

# conda / mamba recommended
conda create -n scdrug python=3.10 -y
conda activate scdrug

pip install scanpy anndata decoupler
pip install torch --index-url https://download.pytorch.org/whl/cpu   # or a CUDA wheel

# optional: beyondcell (R/Seurat) for native SSc + PSc signature collections
# R: install.packages(c("Seurat", "remotes"))
# R: remotes::install_github("cnio-bu/beyondcell")

Hardware. Signature scoring on ~50k cells against a few thousand drug signatures runs in minutes on a laptop (8โ€“16 GB RAM). The transfer model in Path B is small โ€” a two-layer encoder over a few thousand shared genes โ€” and trains on CPU in under a minute; a GPU only matters if you scale to hundreds of drugs or use a large autoencoder pretraining stage as scDEAL does.

Data structures & formats

  • AnnData (target domain) โ€” the single-cell object: adata.X normalised/log1p expression, adata.obs per-cell metadata, adata.obsm for the cells ร— drugs score matrices produced below. No drug labels exist here โ€” that is the whole problem.
  • Bulk expression matrix (source domain) โ€” GDSC or CCLE cell lines ร— genes, typically log2 TPM or RMA-normalised microarray. A few hundred to ~1,000 rows only, which is why overfitting is a real risk.
  • Drug response table โ€” one row per (cell line, drug) pair with LN_IC50 and/or AUC. Binarising at the per-drug median gives the sensitive/resistant labels used for classification; keeping ln(IC50) continuous turns it into regression.
  • Drug signature collection โ€” long-format table of drug, gene, weight. beyondcell's SSc signatures are built from genes that separate sensitive from resistant cell lines; its PSc signatures are the transcriptional changes caused by the drug itself (LINCS L1000 / CMap). decoupler consumes exactly this long format as its net.
  • Score matrix (BCS-equivalent) โ€” cells ร— drugs enrichment scores, stored in adata.obsm["mlm_estimate"]; ranking cells within a drug, or drugs within a cell, is the usual downstream move.
  • Model artefacts โ€” the shared gene list, the per-domain scaling parameters, and the encoder weights must be saved together. Re-applying a model without the exact gene order and scaler it was trained with silently produces garbage.

Minimal code walkthrough

Path A scores cells against a signature collection with no training at all. Path B trains on GDSC bulk with a held-out cell-line split, then transfers to single cells while an MMD penalty pulls the two domains' latent distributions together โ€” the step that makes bulk-trained weights usable on dropout-heavy, shallow single-cell profiles.

import scanpy as sc
import numpy as np
import pandas as pd
import decoupler as dc
import torch
import torch.nn as nn

# =====================================================================
# PATH A - signature scoring (beyondcell-style): no training required
# =====================================================================

# 1. Load a QC'd tumour object and normalise. Signature scoring expects
#    log-normalised values, NOT raw counts.
adata = sc.read_h5ad("tumor_qc.h5ad")
sc.pp.normalize_total(adata, target_sum=1e4)
sc.pp.log1p(adata)

# 2. Drug signature collection as a long table: drug -> gene -> weight.
#    SSc = genes separating sensitive from resistant cell lines.
#    PSc = genes changed BY the drug (LINCS/CMap perturbation profiles).
#    Restrict to genes actually measured in this dataset, or the scores
#    are diluted by signature members that can never be detected.
sig = pd.read_csv("lincs_drug_signatures.tsv", sep="\t")   # drug, gene, weight
sig = sig[sig["gene"].isin(adata.var_names)]
sig = sig.groupby("drug").filter(lambda g: len(g) >= 15)   # drop thin signatures

# 3. Score every cell against every drug signature.
dc.run_mlm(mat=adata, net=sig, source="drug", target="gene",
           weight="weight", use_raw=False, verbose=True)
bcs = adata.obsm["mlm_estimate"]            # cells x drugs, the BCS analogue
adata.obs["bortezomib_sig"] = bcs["bortezomib"].values

# 4. Immediately ask whether a "resistant-looking" group is real biology.
#    Overlay depth and cell-cycle phase on the same embedding: low-depth
#    or cycling cells routinely masquerade as a resistant subpopulation.
sc.pl.umap(adata, color=["bortezomib_sig", "total_counts", "phase", "leiden"])

# =====================================================================
# PATH B - bulk -> single-cell transfer (the scDEAL / SCAD idea)
# =====================================================================

# 5. SOURCE domain: GDSC bulk cell lines with measured drug response.
#    IC50 is a POPULATION summary - one number per cell line, per drug.
#    There is no per-cell equivalent anywhere in this pipeline.
expr = pd.read_csv("GDSC_expression.tsv", sep="\t", index_col=0)   # lines x genes
resp = pd.read_csv("GDSC_ic50.tsv", sep="\t", index_col=0)["Bortezomib"]

lines = expr.index.intersection(resp.dropna().index)
genes = expr.columns.intersection(adata.var_names)                 # shared features
Xb = expr.loc[lines, genes].to_numpy("float32")
yb = (resp.loc[lines] < resp.loc[lines].median()).to_numpy("float32")  # 1 = sensitive

# 6. TARGET domain: the single cells, same gene order, zero labels.
Xs = adata[:, genes].X
Xs = np.asarray(Xs.todense() if hasattr(Xs, "todense") else Xs, dtype="float32")

# 7. WHY DOMAIN ADAPTATION IS NOT OPTIONAL. Bulk RNA-seq of a cell line and
#    a single-cell profile of a tumour cell do not share a distribution:
#    scRNA has heavy dropout (most genes read as exact zeros), 10-100x lower
#    effective depth, and a compressed dynamic range. A model fit on bulk and
#    applied naively is evaluated far off its training manifold. Per-domain
#    standardisation is the MINIMUM, and is not sufficient on its own.
Xb = (Xb - Xb.mean(0)) / (Xb.std(0) + 1e-6)
Xs = (Xs - Xs.mean(0)) / (Xs.std(0) + 1e-6)

# 8. Held-out split ON THE SOURCE domain, so the bulk model's own skill is
#    measurable before anything is transferred. Split by cell line - never
#    let the same line appear in both halves.
rng = np.random.default_rng(0)
perm = rng.permutation(len(Xb))
cut = int(0.8 * len(Xb))
tr, te = perm[:cut], perm[cut:]

# 9. Shared encoder + sensitivity head. The adaptation term forces the encoder
#    to produce features whose bulk and single-cell distributions overlap.
#    scDEAL uses a DaNN/MMD penalty; SCAD uses an adversarial discriminator.
#    A linear-kernel MMD is shown here for readability.
class Net(nn.Module):
    def __init__(self, p):
        super().__init__()
        self.enc = nn.Sequential(
            nn.Linear(p, 512), nn.ReLU(), nn.Dropout(0.3),
            nn.Linear(512, 128), nn.ReLU(),
        )
        self.head = nn.Linear(128, 1)

    def forward(self, x):
        z = self.enc(x)
        return z, self.head(z).squeeze(-1)

def mmd(a, b):                      # linear-kernel MMD between batch means
    return ((a.mean(0) - b.mean(0)) ** 2).sum()

net = Net(len(genes))
opt = torch.optim.Adam(net.parameters(), lr=1e-3)
bce = nn.BCEWithLogitsLoss()
Xb_t, yb_t, Xs_t = torch.tensor(Xb), torch.tensor(yb), torch.tensor(Xs)

for epoch in range(300):
    net.train()
    bi = torch.randint(0, len(tr), (64,))        # labelled bulk lines
    si = torch.randint(0, len(Xs_t), (256,))     # UNLABELLED single cells
    zb, logit = net(Xb_t[tr][bi])
    zs, _     = net(Xs_t[si])
    loss = bce(logit, yb_t[tr][bi]) + 1.0 * mmd(zb, zs)   # lambda = 1.0
    opt.zero_grad()
    loss.backward()
    opt.step()

# 10. Sanity-check the SOURCE fit first; only then transfer to the cells.
net.eval()
with torch.no_grad():
    _, lo = net(Xb_t[te])
    acc_bulk = ((torch.sigmoid(lo) > 0.5).float() == yb_t[te]).float().mean()
    _, ls = net(Xs_t)
    adata.obs["pred_sensitivity"] = torch.sigmoid(ls).numpy()
print(f"held-out cell-line accuracy: {acc_bulk:.3f}")

# 11. Validation is necessarily INDIRECT - no per-cell ground truth exists.
#     (a) do the two paths agree? (b) are predicted-resistant cells enriched
#     for plausible resistance programmes? (c) does a known-sensitive vs
#     known-resistant cell line pair, pushed through the same model, come
#     out in the expected order?
print(np.corrcoef(adata.obs["pred_sensitivity"], adata.obs["bortezomib_sig"])[0, 1])
sc.tl.rank_genes_groups(adata, groupby="leiden", method="wilcoxon")
sc.pl.umap(adata, color=["pred_sensitivity", "bortezomib_sig", "leiden"])

Common pitfalls & tips

  • IC50 has no single-cell ground truth. Every label in GDSC/CCLE is a population-level summary of a bulk viability curve; nothing in a scRNA-seq experiment measures the sensitivity of an individual cell. Per-cell predictions can therefore only be validated indirectly โ€” agreement between independent methods, enrichment of known resistance programmes, or consistency with a downstream clinical/response annotation โ€” never against a per-cell IC50.
  • Cell lines do not contain a tumour microenvironment. A model trained on GDSC has never seen stroma, immune infiltrate, hypoxia gradients, or drug-penetration limits. Resistance that is microenvironment-mediated is invisible to it by construction, so restrict scoring to the malignant compartment and do not read the scores of T cells or fibroblasts as drug predictions.
  • Batch/domain shift is the dominant error source. GDSC bulk and patient scRNA differ in platform, depth, dropout, and dynamic range at once. Always check that the encoder's latent bulk and single-cell clouds actually overlap (UMAP the latent space, colour by domain); if they sit in separate blobs, the adaptation weight is too low and the transferred predictions are extrapolation.
  • Signature collections carry their own context. SSc/PSc and LINCS signatures were derived in specific cell lines at specific doses and time points. A signature built in a haematological line at 10 ยตM says little about an epithelial tumour at physiological exposure โ€” check the provenance of every collection before interpreting its scores as drug response.
  • A "resistant" cluster is often a technical cluster. Low-depth cells score flat on every signature, and cycling cells score high on anything with a proliferation component. Before believing a resistant subpopulation, colour it by total_counts, n_genes_by_counts, mitochondrial fraction, and cell-cycle phase; regress or stratify if it tracks any of them.
  • Always run a known-sensitive / known-resistant control pair. Push two cell lines with well-documented, opposite response to your drug through the identical pipeline. If the model cannot separate that pair, its single-cell output is not interpretable โ€” this is the cheapest and most informative sanity check available, and it catches gene-order and scaler mismatches immediately.
  • Do not compare raw scores across drugs. Signature scores and model logits are on arbitrary, per-drug scales driven by signature size and label balance. Rank cells within a drug, or z-score each drug across cells, before making any "drug X beats drug Y" statement.