Skip to main content

DecontX

DecontX is a Bayesian Dirichlet-multinomial decontamination model that estimates a per-cell contamination fraction θ using LDA (Latent Dirichlet Allocation) topics to model native expression.

Reference

Yang S et al. (2020). Decontamination of ambient RNA in single-cell RNA-seq with DecontX. Genome Biology, 21, 289.

Model

Each cell's count vector is modelled as a two-component mixture:

x_i ~ Multinomial(n_i, θ_i · π + (1 − θ_i) · φ_i)

where:

  • θ_i - per-cell contamination fraction (what we estimate)
  • π - the soup (ambient) expression profile (fixed, from empty droplets)
  • φ_i - the cell's native expression profile (modelled via K shared LDA topics)

Using shared LDA topics means rare cell types borrow expression patterns from similar cells instead of relying only on their own sparse counts.

Usage

from SoupX import load_10x, set_clusters, run_decontx, adjust_counts

sc = load_10x('path/to/cellranger/outs/')
sc = set_clusters(sc, cluster_labels)

sc_decontx = run_decontx(
sc,
n_topics = 20, # LDA topics (more → better, slower)
n_iter = 500, # EM iterations
n_hvg = 3000, # highly-variable genes for PCA init
prior_rho = 0.05, # initial contamination guess
exclude_mt = True, # zero MT genes from soup (recommended)
verbose = True,
)

# Per-cell rho stored in:
print(sc_decontx.meta_data['rho'].describe())

corrected = adjust_counts(sc_decontx)

Choosing the number of topics

Use select_n_topics to find the elbow in the held-out log-likelihood curve:

from SoupX import select_n_topics

results = select_n_topics(sc, topic_range=range(2, 30, 2), n_iter=200)
# Returns dict: {'n_topics': [...], 'log_likelihood': [...]}
# Plot and find the elbow point.

Rule of thumb: K ≈ number of distinct cell types in the dataset. Values between 10 and 30 work well for most experiments.

MT gene exclusion

Mitochondrial genes leak from damaged cells into every droplet and are also genuinely expressed by real cells. When the soup profile is MT-dominated, the model mistakes real MT expression for contamination. Set exclude_mt=True to zero MT genes from the soup profile before EM:

sc_out = run_decontx(sc, exclude_mt=True)

Gene-heterogeneity variant

When soup expression substantially overlaps with cellular expression, the standard DecontX soup profile may be ambiguous. run_decontx_genehet reweights the soup profile to amplify truly ambient genes before the EM:

from SoupX import run_decontx_genehet

sc_out = run_decontx_genehet(
sc,
log_smooth = True,
min_weight = 0.5,
max_weight = 1.5,
)

Parameters reference

ParameterDefaultDescription
n_topics20LDA topics
n_iter500Maximum EM iterations
n_hvgNoneHVGs for PCA initialisation (None = all genes)
prior_rhoNoneInitial contamination guess (None = auto from auto_est_cont)
exclude_mtFalseZero MT genes from soup before EM
pca_initTrueUse PCA to initialise topic proportions
seed42Random seed
verboseTruePrint convergence progress