Pseudobulk or per-cell? The differential expression choice that decides whether your paper survives

Why per-cell differential expression inflates false positives, when pseudobulk is the right answer, and exactly how to run it.

Updated 2026-07-31

Do this on your own data: the argument in this guide is only convincing when you see both tests run on the same dataset. A worked pseudobulk differential expression, per-cell test alongside it: omics.hstgenomics.com/sample-pseudobulk.

Want it done rather than explained? We do analysis only — send a count matrix, an h5ad or Seurat object, Cell Ranger output or a public accession and get publication-ready results with the code that produced them, at a fixed price agreed before any work starts: omics.hstgenomics.com/quote.

You have single-cell data from six mice, three per group, and you want the genes that differ between groups within one cell type. The default in both Seurat and scanpy will happily compare thousands of cells against thousands of cells and hand you 3,000 significant genes. Most of them are not real.

What goes wrong

Cells from the same animal are not independent observations. They share that animal's genetics, its batch, its dissociation stress and its sequencing run. A per-cell test assumes independence, so it treats 2,000 cells as 2,000 pieces of evidence when they are closer to one. The p-values are then calculated against a sample size that does not exist, and the false positive rate rises with the number of cells — the more cells you sequence, the more confident your wrong answer becomes.

Several benchmarking studies since 2021 have shown the same result: per-cell tests such as the default Wilcoxon produce large numbers of false positives in multi-subject designs, while pseudobulk approaches control the error rate close to nominal.

The fix, in five steps

  1. Subset to one cell type.
  2. Sum raw counts (not normalised values) across all cells of that type within each sample. You now have one expression profile per sample — a pseudobulk matrix with n columns, where n is your real sample size.
  3. Drop samples contributing very few cells to that type. A common threshold is fewer than 10–20 cells; below that the profile is noise. Report how many were dropped.
  4. Run a bulk method: DESeq2, edgeR or limma-voom. Include your covariates (sex, batch, donor age) as you would for any bulk experiment.
  5. Repeat per cell type, and correct for multiple testing across genes within each cell type.

When per-cell tests are still correct

They are fine when the comparison lives inside one sample and the cells really are the unit of interest: finding marker genes that distinguish cluster 3 from cluster 5 in a single dataset, for example, or comparing two cell states within the same animal. The rule of thumb: if your biological question has a sample-level design ("treated versus control"), use pseudobulk. If it is a within-sample descriptive question ("what defines this cluster"), per-cell is appropriate — but present it as description, not inference about groups.

What about mixed models?

Approaches that model the subject as a random effect are statistically attractive and can be more powerful than pseudobulk at small effect sizes. They are also slower, harder to diagnose and harder for a reviewer to check. For most projects pseudobulk is the pragmatic choice; consider mixed models when you have many subjects and a small expected effect, and when someone on the team can defend the model.

A worked example on real data

We ran both approaches on a public 8-donor dataset (control versus interferon-β, CD14+ monocytes) and published the comparison: pseudobulk versus per-cell, same cells. The two gene lists disagree on 68% of calls — and not in the direction the textbook warning implies. All ten canonical interferon-stimulated genes come out of the pseudobulk analysis, which is the check that tells you the pipeline is behaving.

The uncomfortable part

Redoing differential expression properly usually shrinks the gene list from thousands to dozens. People experience this as losing their result. It is not — it is finding out what the result actually was. A short, defensible list beats a long list that dissolves under review, and reviewers in this field now ask about it by name.

Need this done rather than explained?

We do analysis only — send a count matrix, an h5ad/Seurat object or a public accession and get publication-ready results with the code that produced them. Fixed price agreed before work starts.

→ Get a fixed quote  ·  See a full sample deliverable

More guides