Skip to content

Identifying Contaminants

A more formal, method-sensitive way to flag likely contaminant taxa using the decontam package, once you've looked at your controls directly.

This page assumes you've already worked through Exploring Your Controls: labeled your controls, looked at your positive controls, and checked your negative controls for read depth and composition. decontam is a next, optional step from there, not a substitute for it.

A Starting Point, Not a Protocol to Follow Blindly

The same caution that applies to the rest of controls handling applies here, arguably more so, since decontam produces a confident-looking number that's easy to trust more than it deserves. Every project's controls and contamination sources differ, and what follows is a way to think about the problem, not a formula to apply mechanically.

What decontam Does

decontam offers a statistical route to identifying likely contaminant taxa, using either DNA concentration (the frequency method: contaminants are more prevalent in low-concentration samples), your negative controls directly (the prevalence method: taxa more common in negatives than in real samples), or both combined.

# Remove control samples that shouldn't inform the decontam model itself
ps_decontam <- subset_samples(ps, !(ControlType %in% c("LibraryPrepNegative", "LibraryPrepPositive")))
sample_data(ps_decontam)$is.neg <- sample_data(ps_decontam)$ControlType == "ExtractionNegative"

contaminants <- decontam::isContaminant(
  ps_decontam,
  method    = "combined",
  neg       = "is.neg",
  conc      = "DnaQuant",
  threshold = 0.1
)

table(contaminants$contaminant)

# The step that actually matters: removing the identified contaminants.
# Skipping this leaves your object exactly as it was.
ps_clean <- prune_taxa(!contaminants$contaminant, ps_decontam)

Don't Trust This Blindly

Decontam isn't a black box you run once and believe. A few concrete reasons for caution:

The methods disagree with each other. Frequency, prevalence, and combined classification can flag different taxa as contaminants from the same data. Run more than one method and cross-tabulate the results before deciding what to remove:

freq_result <- decontam::isContaminant(ps_decontam, method = "frequency", conc = "DnaQuant", threshold = 0.1)
prev_result <- decontam::isContaminant(ps_decontam, method = "prevalence", neg = "is.neg", threshold = 0.1)
table(freq_result$contaminant, prev_result$contaminant)

Substantial disagreement is itself information: it means the classification is sensitive to which evidence you weight, not that one method is simply right and the other wrong.

Results depend on your negative controls being good ones. The prevalence method is only as trustworthy as the negatives feeding it. Too few negatives, or negatives that don't represent the same contamination sources as your real samples, will give you a confident-looking classification that doesn't mean much.

The threshold is a real, consequential choice, not a default to leave alone. Stricter thresholds leave more real contaminants in; looser ones risk removing genuine biological signal. There's no universally correct value, try more than one and look at what changes.

Check what decontam actually removed against your own judgment. If a taxon you'd expect to be real gets flagged, investigate it, don't automatically discard it.