Written and maintained by CASRAI Editorial Board
Last updated
Combining microarray or RNA-seq samples that were processed on different days, by different technicians, on different flow cells, or at different facilities introduces systematic technical variation on top of the biology you actually care about — a batch effect. ComBat is the standard tool for removing it: an empirical Bayes method, distributed in the Bioconductor sva package, that adjusts each batch’s expression values so they sit on a common scale before downstream analysis. Used correctly, it recovers real biological signal that would otherwise be swamped by batch noise. Used on a study design where batch and biology can’t be told apart, it can quietly remove the biological signal along with the artifact. This guide covers what ComBat actually does, the one design property that determines whether it will help or hurt, and how to check for that property before you run it.
What ComBat actually does
ComBat was introduced by Johnson, Li, and Rabinovic (2007, Biostatistics) for microarray data and is implemented today in the sva Bioconductor package’s ComBat() function, alongside ComBat_seq(), a later extension built for RNA-seq read counts. The two share the same underlying logic but different distributional assumptions:
- ComBat (microarray / normalized continuous data): models each gene’s batch-specific mean shift (an additive effect) and variance inflation (a multiplicative effect) against a normal distribution.
- ComBat-seq (RNA-seq raw counts): replaces the normal-distribution assumptions with a negative binomial model, matching how count data actually behaves, so it can be applied directly to raw or lightly filtered counts rather than log-normalized values.
The empirical Bayes step is what distinguishes ComBat from a simple per-batch mean-centering: instead of estimating each gene’s batch-specific location and scale parameters independently (which is noisy when a batch has few samples), ComBat treats those parameters as draws from a common distribution estimated across all genes in that batch, then shrinks each gene’s individual estimate toward that common distribution. Genes borrow statistical strength from each other, which is why ComBat tends to outperform naive per-gene batch correction on the small-to-moderate batch sizes typical of genomics studies.
The prerequisite that determines whether ComBat helps or hurts
ComBat needs batch membership supplied explicitly — it does not detect batches on its own. You pass it a batch label per sample (e.g., batch = c(1,1,1,2,2,2)) and, ideally, a model matrix specifying the biological variable(s) you want preserved, so the correction adjusts for batch while protecting your variable of interest.
That second part only works if batch and biology are not perfectly confounded in your design — the single most important caveat in using ComBat correctly. If every sample in Batch 1 is also entirely your control condition, and every sample in Batch 2 is entirely your treatment condition, there is no way — for ComBat or any other statistical method — to distinguish “this changed because of batch” from “this changed because of treatment.” The two explanations are mathematically indistinguishable from the data alone. Run ComBat on a design like this and it will do exactly what it’s designed to do: flatten the difference between the batches. It just so happens that in a fully confounded design, the difference between the batches is the biological effect you were trying to measure, so ComBat removes your real signal along with the technical artifact. This is not a bug or a misuse of the tool; it is a fundamental identifiability limit that no downstream statistical correction can fix. The fix has to happen at the design stage, not the analysis stage — see RNA-seq: Experimental Design Through Analysis for how to plan sample-to-batch allocation before sequencing begins.
Checking your design before you run ComBat
Before touching the correction step, cross-tabulate batch against your biological variable of interest — a simple two-way table of sample counts, batch as rows and biological group as columns. This takes a minute and tells you exactly what kind of design you’re working with:
- Balanced / fully crossed: every batch contains a roughly even mix of every biological group. This is the ideal case — batch and biology vary independently, so ComBat can cleanly separate the two sources of variation.
- Partially crossed: most batches contain a mix of groups, but not perfectly even. ComBat can still work, though the correction is more reliable the more balance you have; report this limitation if the imbalance is severe.
- Fully confounded: at least one batch contains only one biological group (a table cell of zero for every other group in that batch). This is the design ComBat cannot rescue. If you’re still at the planning stage, redesign sample allocation so each batch spans multiple biological conditions — a blocked design is the standard way to do this deliberately rather than by luck. If the confounded data already exists and re-collecting isn’t an option, don’t run ComBat expecting it to fix things; report the batch/biology confound as a limitation and treat the resulting comparison with the appropriate skepticism, since no computational correction can retroactively unconfound a design.
This same confounding logic is why batch is worth treating as a formal confounding variable at the experimental design stage, not an afterthought discovered during analysis.
Verifying the correction actually worked: PCA before and after
Don’t take a successful ComBat run on faith — a completed function call with no error is not evidence the correction did what you wanted. The standard check is a principal component analysis (PCA) of the expression matrix, run twice: once before correction, once after, with points colored by batch in one version and by biological group in the other.
- Before correction: if a batch effect is present, samples typically separate by batch along one of the first few principal components, sometimes more strongly than they separate by biological group. This is the pattern that motivates running ComBat in the first place.
- After correction, colored by batch: batch clusters should largely dissolve — samples from different batches should now intermix rather than forming distinct groups along the leading components.
- After correction, colored by biological group: your biological groups should still separate, ideally more cleanly than before, since removing batch noise should make the biological signal easier to see rather than harder. If biological separation collapses along with batch separation, that is the practical symptom of the confounding problem above — ComBat has removed real signal, and it’s a sign to go back and check the design table rather than proceed to downstream analysis.
Run this same before/after PCA check regardless of which ComBat variant you used, and keep both plots as part of your analysis record — a reviewer asking “how do you know the batch correction didn’t just remove your effect” is a reasonable question to expect, and the before/after PCA is the direct answer.
Where ComBat fits in the pipeline, and when something else is a better fit
For bulk microarray or RNA-seq data, ComBat (or ComBat-seq for raw counts) is typically applied after normalization and before differential expression testing — see Differential Gene Expression Analysis for where that step sits in the broader workflow, and DESeq2 vs edgeR for the tools that typically consume ComBat-seq’s corrected counts downstream. Corrected results are commonly visualized as a volcano plot once differential expression is run.
ComBat was designed for bulk data with a modest, discrete number of known batches. For single-cell RNA-seq integration across multiple samples, datasets, or sequencing runs, methods built for that setting — Harmony, mutual nearest neighbors (MNN), and canonical correlation analysis (CCA)-based integration — are generally preferred over applying bulk ComBat to single-cell data, since they’re designed to handle the far larger cell-to-cell variance and non-linear batch structure typical of single-cell experiments; see Leiden Clustering for Single-Cell Data for related single-cell analysis steps. If your batch variable is continuous or unknown rather than a discrete labeled factor, ComBat is also the wrong tool — that’s the situation surrogate variable analysis (also in the sva package) is built for instead.
Frequently asked questions
Can I use ComBat if I don’t know what caused the batch effect?
Yes — ComBat only needs a batch label per sample (which processing day, facility, or run each sample came from), not a mechanistic explanation of what technical factor caused the difference. What it does need is that the label be genuinely known and recorded before analysis, not inferred after the fact from the expression data itself.
Does ComBat work on data with more than two batches?
Yes. Both ComBat() and ComBat_seq() accept any number of batch levels; the same balanced-versus-confounded design check applies regardless of how many batches you have — check every batch against every biological group in the cross-tabulation, not just the first two.
Should I run ComBat before or after normalizing my data?
For microarray or already-normalized continuous expression values, ComBat is applied after normalization. For RNA-seq, ComBat-seq is applied directly to raw or minimally filtered count data, before the normalization step built into tools like DESeq2 or edgeR, because it’s modeling count-scale, not normalized-scale, variation.
What if my design is confounded and I can’t collect more data?
There is no statistical correction that reconstructs information a confounded design never captured. The honest options are to report the confound explicitly as a limitation, treat the affected comparison as exploratory rather than confirmatory, and, where possible, design the next study so batch and biological group are crossed rather than confounded.







