Concept Guide · 12 min read

Understanding Batch Effects in RNA-Seq

What they are, why they ruin your analysis, and how to fix them — explained without the jargon.

12 min read Concept guide Intermediate
PCA · Same dataset, two views
Batch A Batch B
PC1 PC2
Treated Control
PC1 PC2
When batch effects dominate, biology disappears. Same samples, same coordinates — only the coloring changes.
Batch variance PC1 explains 62% — almost entirely sequencing run, not biology.
TL;DR
  • Batch effects are technical variation introduced when samples are processed at different times, by different people, or on different machines.
  • They can completely mask the biological signal you are trying to find.
  • TransXplorer screens your metadata with PVCA + kBET + Silhouette, then adds the batch variable as a covariate in the DE model (~ batch + condition); before/after plots use limma's removeBatchEffect.
Section 01

What batch effects actually are

A batch effect is technical noise in your data that looks like biology. More precisely, it is systematic variation between groups of samples that traces back to how the samples were processed, not what they actually are.

Imagine you sequenced ten control mice on Monday and ten treated mice on Friday. The reagent lot was different. The instrument had been recalibrated. A different technician loaded the flow cell. Now when you compare expression between treated and control, you cannot tell which differences came from your treatment and which came from running the samples four days apart. The two sources of variation are tangled together.

Batch effects are sneaky for one reason: they look statistically real. Genes will appear to be differentially expressed between groups with low p-values and respectable fold changes. The math is not lying. The samples really do differ. But the difference is technical, not biological — and that is precisely what makes batch effects dangerous. They mimic the signal you are looking for.

Common sources include:

  • Different sequencing runs or lanes on the same instrument.
  • Different reagent lots (library prep kits especially).
  • Different operators handling the samples.
  • Different processing dates, even by a few days.
  • Different sample storage conditions or freeze-thaw cycles.
  • Different centers in a multi-site study.

The first defense is always experimental design: randomize samples across batches so that each condition is represented in each batch. We will get back to this later. But even with the best design, batch effects almost always sneak in — which is why detection and correction matter.

Section 02

The famous case — when batch effects pretend to be biology

The cautionary tale every bioinformatics class tells is the one Leek and colleagues used to anchor their 2010 review in Nature Reviews Genetics. Reanalysing a high-profile expression study of population differences, they noticed that the apparent biological signal was almost perfectly aligned with the date each batch of arrays had been processed. The strongest "ancestry" axis in the data was, in fact, mostly time.

The original 2007 paper by Akey and colleagues had concluded that human populations differed in the expression of many genes. The reanalysis showed that many of those genes also differed between processing dates — and because population happened to be confounded with date, the two effects could not be told apart. Once batch was accounted for, a large fraction of the reported population differences shrank or disappeared.

The lesson is uncomfortable but important: if your biological variable is confounded with batch, no statistical method can fully save you. Correction tools can adjust for batch only when the data contain enough information to distinguish batch from biology — and a confounded design destroys that information by construction.

The takeaway

Good experimental design comes first. Randomize samples across batches. If you cannot — for example, because one cohort was collected years before the other — document it, be honest about it in the paper, and apply correction with care. Reviewers know to look for this.

That 2010 review (Leek et al., Nat Rev Genet 11:733–9) is still the single best read on why this matters. The takeaway from the Akey case is not "those authors were sloppy" — it is that batch effects are so easy to miss that they have caught even careful, well-funded labs by surprise. Assume they are present in your data until you have proven otherwise.

Section 03

How to detect batch effects

A quick visual sanity check is to run a principal component analysis (PCA) and color the samples by batch. If the points cluster by batch rather than by biology, you have a problem — like the hero plot at the top of this page. But the eye is unreliable, so the field has developed three complementary quantitative metrics. Each one asks a slightly different question, and using them together is more robust than picking a favourite.

PVCA — Principal Variance Component Analysis

PVCA decomposes the total variance in your dataset into named sources: batch, condition, the batch×condition interaction, and unexplained residual variance. The output is one number per source — the percentage of variance attributable to it.

Rule of thumb: if batch explains more than ~10% of variance, you have a meaningful batch effect. If it explains 30% or more, your biological signal is almost certainly drowning. (This is general guidance; TransXplorer's own PVCA cut-off of 15% is described below.) Researchers also watch the batch×condition interaction term — a large interaction means batches behave differently across conditions, which complicates correction.

kBET — k-nearest-neighbor Batch Effect Test

kBET takes a different angle. For each sample, it looks at its k nearest neighbours in expression space and asks: do those neighbours represent batches in roughly the same proportion as the dataset overall? If yes, batches are well-mixed locally and there is no batch effect. If neighbours are mostly the same batch, samples are segregating by batch.

The output is a rejection rate: the fraction of neighbourhoods that fail the mixing test. A value below ~0.1 indicates clean data; values approaching 1.0 mean samples cluster almost entirely by batch.

Silhouette score

The silhouette score measures how well each sample fits its assigned cluster compared with the nearest other cluster. When clusters are defined by batch label, a high silhouette means samples sit comfortably with their own batch and far from others — i.e. batches separate cleanly. A low or negative silhouette means batches are intermixed.

Counterintuitively, you want a low silhouette by batch. The interpretation is the opposite of normal silhouette use: if your batches form tight, well-separated clusters, that is bad news for downstream analysis.

What TransXplorer computes

With Automatic Detection selected and a sample-metadata file uploaded, the Exploratory QC step tests every metadata column other than sample and group (columns where more than half of the values are unique, such as sample IDs, are skipped). All three metrics are computed on the top principal components (up to 10) of your normalized samples:

PVCA — a linear mixed model (lme4, REML) is fitted to each PC with all candidate variables as random effects; each variable’s variance fraction is averaged over the PCs that together reach 60% of the variance of the retained PCs, weighted by PC variance. If the joint model cannot be fitted (for example, fully confounded columns), each variable is fitted on its own instead.
kBET — for each sample, a chi-square test compares the batch labels of its k nearest neighbours (k = mean batch size, at least 5) with the overall batch frequencies; the rejection rate is the share of tests with p < 0.05 (Monte-Carlo p-values when counts are small).
Silhouette — the mean silhouette width of the batch labels in PC space.

A variable is flagged as a batch effect when at least two of three criteria hold: PVCA ≥ 0.15, kBET rejection ≥ 0.25, silhouette ≥ 0.05. These cut-offs are the 95th percentiles of each metric in simulated batch-free data (8–48 samples). Candidates are also ranked by a combined score, 0.4 × PVCA + 0.4 × kBET + 0.2 × max(0, silhouette). The report shows PVCA (%), kBET (rejection rate), silhouette and combined score for the top variable, plus a ranked table of all candidates.

How well does it work?

We tested the detector on simulated data: negative-binomial counts for 5,000 genes, with the batch shifting 30% of genes, 30 runs per scenario. Batch-free data were flagged in 0–3% of runs. Batch effects with a log2 standard deviation of 1 or more were detected in 100% of runs at every size from 8 to 48 samples. Weaker effects need more samples:

Batch effect size (log2 SD)8 samples12 samples24 samples48 samples
None (false-positive rate)0–3% of runs flagged
0.50%50%97%100%
≥ 1100%100%100%100%

In short: with fewer than about 12 samples, a subtle batch effect can go undetected, so also look at the PCA coloured by batch yourself.

Section 04

How to correct batch effects

Once you have confirmed a batch effect, the next question is which correction method to use. The right answer depends on what your data looks like and whether you know your batch labels. Three methods cover almost every practical case.

ComBat-seq

Empirical Bayes adjustment designed specifically for RNA-seq count data — a common alternative when you need to keep integer counts.

ComBat-seq is the modern successor to ComBat, redesigned to work directly on integer counts rather than log-transformed data. It models each gene as a negative binomial distribution per batch, estimates batch-specific location and scale parameters, then adjusts each count to what it would have looked like in a reference batch — while preserving the count distribution downstream methods like DESeq2 and edgeR depend on.

  • Operates on raw counts — preserves the integer count structure required by DESeq2/edgeR.
  • Empirical Bayes shrinks batch-effect estimates toward a global mean — more stable when batches contain few samples.
  • Accepts a covariate of interest (your biological condition) so it can adjust for batch without removing biology.
Zhang Y, Parmigiani G, Johnson WE (2020). ComBat-seq: batch effect adjustment for RNA-seq count data. NAR Genomics and Bioinformatics 2(3): lqaa078. doi:10.1093/nargab/lqaa078

ComBat

The original 2007 method — built for microarrays and log-transformed data.

ComBat is still in wide use, but it assumes the input is approximately normally distributed — which is true for log-CPM or log-TPM values but not for raw counts. Applying ComBat directly to integer counts distorts the variance structure and breaks downstream count-based methods. Reach for ComBat only when your data are already log-scale (microarray intensities, or RNA-seq that has been variance-stabilized).

  • Empirical Bayes shrinkage like ComBat-seq, but on the log/normal scale.
  • Good for microarray expression, methylation beta-values, or VST/RLOG-transformed RNA-seq.
  • Not appropriate for raw integer counts.
Johnson WE, Li C, Rabinovic A (2007). Adjusting batch effects in microarray expression data using empirical Bayes methods. Biostatistics 8(1): 118–127. doi:10.1093/biostatistics/kxj037

SVA / RUV

When you do not have batch labels — recover the unwanted variation from the data itself.

Sometimes you inherit a dataset and the metadata simply does not record which samples were processed together. SVA (Surrogate Variable Analysis) and RUV (Remove Unwanted Variation) infer hidden sources of variation by looking for systematic patterns that are not aligned with your biological variable. The recovered "surrogate variables" can then be included as covariates in your differential-expression model.

  • Useful when batch labels are missing or untrustworthy.
  • RUV often uses negative control genes (e.g. housekeeping genes) as a reference for what should not vary.
  • More conservative than ComBat-seq — it adds covariates to the model rather than rewriting your counts.
Leek JT, Storey JD (2007). Capturing heterogeneity in gene expression studies by surrogate variable analysis. PLoS Genetics 3(9): e161.  ·  Risso D et al. (2014). Normalization of RNA-seq data using factor analysis of control genes or samples. Nature Biotechnology 32: 896–902. doi:10.1038/nbt.2931
Method Best for Needs batch labels? Preserves counts? TransXplorer support
limma::removeBatchEffect Log-transformed expression (voom, log-CPM, log2(counts+1)) Yes No (log-scale) Yes (before/after plots)
Batch covariate in DE (~ batch + condition) Any count-based DE (DESeq2, edgeR, limma) Yes Yes (counts untouched) Yes (DE default)
ComBat-seq Bulk RNA-seq counts Yes Yes No
ComBat Microarrays, log/VST data Yes No (log-scale) No
SVA / RUV Unknown / unrecorded batches No Yes (as covariate) No
Section 05

The dangerous side — over-correction

Batch correction is not a magic eraser. If batch is confounded with your biological variable — meaning all treated samples were run in one batch and all controls in another — then any algorithm that removes batch differences will also remove biological differences. The two are mathematically indistinguishable. You will get clean PCA plots and no DEGs.

The fix is upstream of any software: balance your design so each batch contains samples from each condition. Even a small amount of mixing rescues correction. The diagram below contrasts a fatal confounded layout with a balanced one.

When over-correction shows up

Symptom: after applying batch correction, you have fewer DEGs than before, the volcano plot empties out, and PCA shows all samples in one cloud regardless of condition. This means the correction stripped real biology along with batch. Go back, examine your design matrix, and make sure your biological condition is in the model alongside batch — in the design argument of limma::removeBatchEffect, as a covariate to ComBat-seq, or as condition in a ~ batch + condition DE design — so the model knows to protect it.

Section 06

Decision flowchart — should I correct?

Here is the path most analyses follow. Read top-to-bottom: at every question, NO branches left and YES branches right. Red end-states mean stop and rethink; green means you are clear to proceed.

Section 07

How TransXplorer handles all this

Batch handling lives in the Exploratory QC step of the DEG analysis section. You upload your counts and a sample-metadata file, choose Automatic Detection (the default), Manual Selection or Skip, and run QC:

  • Automatic detection. Each candidate metadata column is scored with PVCA, kBET and silhouette on the top PCs, and flagged when it meets at least two of the three criteria (details in the box under Silhouette score). The report shows the four numbers for the top candidate and a ranked table of all candidates. In Manual Selection mode, the column named batch in your metadata is used without scoring.
  • Batch in the DE model. The flagged (or manual) batch column is added as a covariate to differential expression: ~ batch + condition for DESeq2 and the matching design matrix for edgeR and limma. Your counts are not altered. If batch is completely confounded with condition, it is left out of the model with a warning.
  • Before/after PCA and UMAP. For the plots only, the normalized QC data are adjusted with limma::removeBatchEffect, with the biological group in the design so it is preserved, and shown side by side with the unadjusted data.
  • Correction check. In Automatic mode the report also compares the silhouette width of the batch labels (on PC1–PC2) before and after adjustment, gives the percentage reduction with a short rating (from “Excellent” to “Correction ineffective”), and notes possible over-correction.
fig. 7 Side-by-side PCA plots from TransXplorer showing batch effect reduction: before correction, samples cluster by batch (day6 vs day8) along PC2; after correction, samples cluster by biological group (CMEC vs PMEC) with batch differences eliminated
Before/after PCA in TransXplorer's batch assessment panel. Left: samples cluster by sequencing batch (day6 vs day8) along PC2. Right: after limma::removeBatchEffect (used for this view only; DE models batch as a covariate), samples cluster by biology (CMEC vs PMEC) and batch separation has collapsed.

You work entirely in the browser: no R, no Python, no Docker. Detection runs as part of the Exploratory QC step, so it adds little time to a normal QC run.

Try batch detection on your own data

Free, browser-based, no login. Upload a counts file and your sample metadata, run Exploratory QC, and TransXplorer will report whether any metadata column behaves like a batch.

Launch TransXplorer
Section 08

Common pitfalls

Five mistakes that turn up over and over in published RNA-seq analyses. Each one is avoidable.

  1. Confounding batch with biology. The single most common — and most fatal — mistake. All treated samples run on day 1, all controls on day 2. No method can disentangle that. Randomize at the bench.
  2. Over-correction. Removing genuine biological signal along with batch. Usually happens when you do not pass your biological condition in the design matrix to limma::removeBatchEffect (or as a covariate to ComBat-seq), or when batch is partially confounded with condition.
  3. Ignoring batch when sample size is small. With three or four samples per group, even a modest batch effect can completely swamp biology — and the smaller the sample size, the less power any correction method has to work with. Small N demands cleaner design.
  4. Using ComBat (microarray method) on raw counts. ComBat assumes normal distributions; counts are not normal. The mismatch distorts variance and breaks downstream count-based tests. Use ComBat-seq for counts, ComBat for log-scale or microarray data.
  5. Trusting a single metric. PVCA can miss a batch effect that only shows up in local neighbourhoods (kBET catches that). kBET can miss a global linear shift (PVCA catches that). Run all three.
Section 09

Frequently asked

Do I always need to check for batch effects?
Yes — even if you think your experiment is clean. Reagent lots, instrument calibration, and operator differences can introduce variation without anyone noticing. A five-minute check in the Exploratory QC step is always worth it.
What if I don't have batch information recorded?
Use SVA (Surrogate Variable Analysis) or RUV (Remove Unwanted Variation). These methods infer hidden sources of variation directly from the data, without needing explicit batch labels. TransXplorer does not run SVA or RUV: its batch detection and batch handling need a recorded batch-type column in your sample metadata.
Can I correct batch effects after differential expression?
No. Batch has to be handled before or inside the DE model, not afterwards: once the model has been fitted without batch, the batch variance is already in the residuals and the statistics are biased. The usual approach is to include batch as a covariate in the DE design (~ batch + condition), which is what TransXplorer does. The order: detect → model batch in DE → enrichment.
Does batch correction work for single-cell RNA-seq?
The bulk methods on this page (limma::removeBatchEffect, ComBat-seq, ComBat) are not ideal for single-cell data. Single-cell pipelines use specialized integration tools such as Harmony, BBKNN, or scVI, which operate on low-dimensional embeddings rather than raw counts. TransXplorer is focused on bulk RNA-seq.
How do I report batch correction in a paper?
In the Methods section, write: “Batch effects were assessed with PVCA, kBET and silhouette width in TransXplorer, and the batch variable was included as a covariate in the differential expression model (~ batch + condition). Before/after PCA plots were drawn from data adjusted with limma::removeBatchEffect (Ritchie et al., 2015) with the biological group in the design.” Include the detection report (PVCA, kBET, silhouette) and the before/after PCA in a supplementary figure — reviewers appreciate the receipt.
Section 10

Further reading

The papers below are the foundation references for batch-effect detection and correction. If you only read one, make it Leek et al. (2010); for the methods behind TransXplorer’s detection and before/after plots, see Li et al. (2009), Büttner et al. (2019) and Ritchie et al. (2015).

  1. Leek JT, Scharpf RB, Bravo HC, Simcha D, Langmead B, Johnson WE, Geman D, Baggerly K, Irizarry RA (2010). Tackling the widespread and critical impact of batch effects in high-throughput data. Nature Reviews Genetics 11(10): 733–739. doi:10.1038/nrg2825
  2. Ritchie ME, Phipson B, Wu D, Hu Y, Law CW, Shi W, Smyth GK (2015). limma powers differential expression analyses for RNA-sequencing and microarray studies. Nucleic Acids Research 43(7): e47. doi:10.1093/nar/gkv007
  3. Zhang Y, Parmigiani G, Johnson WE (2020). ComBat-seq: batch effect adjustment for RNA-seq count data. NAR Genomics and Bioinformatics 2(3): lqaa078. doi:10.1093/nargab/lqaa078
  4. Johnson WE, Li C, Rabinovic A (2007). Adjusting batch effects in microarray expression data using empirical Bayes methods. Biostatistics 8(1): 118–127. doi:10.1093/biostatistics/kxj037
  5. Risso D, Ngai J, Speed TP, Dudoit S (2014). Normalization of RNA-seq data using factor analysis of control genes or samples. Nature Biotechnology 32: 896–902. doi:10.1038/nbt.2931
  6. Büttner M, Miao Z, Wolf FA, Teichmann SA, Theis FJ (2019). A test metric for assessing single-cell RNA-seq batch correction. Nature Methods 16: 43–49. doi:10.1038/s41592-018-0254-1
  7. Li J, Bushel PR, Chu T-M, Wolfinger RD (2009). Principal variance components analysis: estimating batch effects in microarray gene expression data. In: Scherer A (ed.), Batch Effects and Noise in Microarray Experiments. Wiley, pp. 141–154. doi:10.1002/9780470685983.ch12

What's next?

Keep building your RNA-seq intuition — or jump back to the hands-on tutorial.

Differential Expression Analysis

What does padj really mean? When to choose DESeq2 vs edgeR vs limma. The math, made readable.

Read the concept

GSEA vs ORA

Pathway enrichment explained. Why two methods exist, what each one actually tests, and how to pick.

Read the concept

10-Minute Tutorial

See batch detection, DESeq2, and pathway enrichment work end-to-end on a real published dataset.

Open tutorial