Skip to content
/data-engineering/normalization

Normalization

Normalization is the set of transformations that make measurements comparable across samples, batches, and assays by removing technical variation such as sequencing depth, transcript length, loading amount, and instrument drift.

Normalization is the step where you rescale or transform raw measurements so that numbers from different samples mean the same thing. Without it, a gene with 400 reads in one sample and 200 in another tells you nothing, because the first library may simply have been sequenced twice as deep.

Omics data is the general term for the high-dimensional assays that measure a whole class of molecules at once: the genome (DNA sequence), transcriptome (RNA abundance), proteome (protein abundance), metabolome, and so on. All of them share the same problem. The instrument reports a relative signal, and the scale of that signal depends on how much material you loaded, how long the run was, and which machine it ran on.

How it works

Three families of correction, applied in roughly this order.

Within-sample scaling handles differences in feature length and total output. For RNA-seq, TPM divides each gene’s read count by its effective transcript length, then rescales so the sample sums to 1e6. CPM skips the length division and is fine when you only compare the same gene across samples.

Between-sample scaling handles composition. If one highly expressed gene consumes 30% of the library, every other gene’s fraction drops even though nothing changed biologically. TMM (edgeR::calcNormFactors(method="TMM")) trims the extreme log-ratios and extreme abundances, then computes a weighted mean of the remaining log fold-changes as the scaling factor. DESeq2’s median-of-ratios does something similar: build a geometric-mean pseudo-reference across samples, take per-gene ratios to it, use the median ratio as the size factor (estimateSizeFactors). Both assume most genes are not differentially expressed. That assumption holds for most human tissue comparisons and breaks badly for, say, a globin-dominated whole-blood sample against PBMCs.

Distributional transforms handle variance. Counts are heteroscedastic: high-expression genes have larger absolute variance. DESeq2::vst() or limma::voom() stabilizes this before you run PCA, clustering, or a linear model. GTEx went further for eQTL mapping, applying TMM followed by an inverse normal transform across samples per gene, which forces each gene’s cross-sample distribution to standard normal and makes the regression insensitive to outlier expression values.1

In your own data

Here is where it surfaces in the files you hold.

salmon quant writes quant.sf with columns Name, Length, EffectiveLength, TPM, NumReads. The TPM column is within-sample normalized and nothing else. Do not run DESeq2 on it. Instead pull NumReads through tximport(type="salmon", countsFromAbundance="lengthScaledTPM") and let DESeq2 estimate size factors on counts.

If your pipeline gave you featureCounts output (*.counts.txt with a summary file), check the summary first. An Unassigned_NoFeatures fraction above roughly 30% usually means a GTF/BAM chromosome naming mismatch (chr1 vs 1), and no normalization fixes that.

After normalizing, plot RLE: for each gene, subtract the median across samples from the log expression, then boxplot per sample. Well-normalized samples center on zero with similar spread. A sample whose box sits at +0.4 has a scaling problem you did not correct. This is the single most useful diagnostic and takes four lines of R.

For proteomics, your search engine output (report.pq from DIA-NN, or MaxQuant’s proteinGroups.txt) carries intensity columns that vary with injection amount by a factor of two or more between runs. Median-center on log2 intensity as a baseline, then compare against vsn::justvsn(). Check missingness first: a protein present in 3 of 8 runs is mostly reporting whether it cleared the detection threshold, not its concentration.

Blood biomarkers need a different kind of harmonization. Two labs reporting the same analyte can use different platforms and different reference intervals, so store the assay method and units alongside every value. Cross-platform agreement for the same genomic region was already a documented issue in the ENCODE pilot, where the same element measured on different assays required explicit reconciliation before the results could be pooled.2 For CGM, per-sensor calibration offsets can shift a two-week window by 10 mg/dL or more. Model sensor ID as a factor rather than concatenating streams.

Common mistake: normalizing twice. Running calcNormFactors on TPM values applies composition correction on top of a transform that already destroyed the count structure.

Limitations

Normalization removes technical variation you can model. It does not remove confounding. If all your winter samples were prepped in one batch, TMM will not rescue that, and you need the batch as a covariate or limma::removeBatchEffect for visualization only.

Global scaling methods fail when total molecular content genuinely changes between conditions, which is where spike-in controls (ERCC mixes) earn their cost. And normalization never fixes genotype-level artifacts: variant calls depend on coverage uniformity and reference panel quality, a problem recognized since the first large-scale SNP maps.3

Normalized values are inputs to interpretation, not conclusions. Any clinical reading of them belongs with a clinician.

Woolf Software builds longitudinal molecular profiles of individuals: whole-genome sequencing, RNA sequencing, proteomics, blood biomarkers, and continuous glucose data, integrated into one model of you. Build your profile.

Computational Angle

In your own longitudinal data, every cross-timepoint comparison is a normalization decision: raw counts from a January blood draw and a July blood draw differ in depth, library prep, and flow cell before any biology enters the picture.

Related Terms

References

  1. François Aguet, Ayellet V. Segrè, Beryl B. Cummings, et al.. Genetic effects on gene expression across human tissues . Nature, 2017. DOI
  2. Ewan Birney, Paul Flicek, Damian Keefe, et al.. Identification and analysis of functional elements in 1% of the human genome by the ENCODE pilot project . Nature, 2007. DOI
  3. The International SNP Map Working Group, Cold Spring Harbor Laboratories:, Ravi Sachidanandam, et al.. A map of human genome sequence variation containing 1.42 million single nucleotide polymorphisms . Nature, 2001. DOI