Skip to main content

ugbio_mrd

This module includes MRD (Minimal Residual Disease) python scripts and utils for bioinformatics pipelines.

Statistical Detection

MRD detection is based on a Binomial test comparing the observed supporting read count at patient signature loci against a background noise model derived from synthetic (db_control) signatures.

ctDNA VAF estimation

Given:

  • N = total coverage = reads covering signature loci (signature_size × mean_coverage)
  • K = supporting reads passing the SNVQ quality threshold
  • P = SNVQ recall = fraction of true-positive reads passing the threshold (estimated from training data)
  • T = total signal = K / P (supporting reads corrected for recall)

$$\text{ctDNA VAF} = \frac{T}{N} = \frac{K/P}{N}$$

Detection p-value: P(X ≥ K | Binom(N × P, p_err)) where N × P (= corrected_coverage) is the effective Binomial trial count and p_err is the background error rate estimated from synthetic controls via Jeffreys prior.

Personal LOD

The personal Limit of Detection (LOD) is the minimum tumor fraction (TF) at which a sample would be detected with ≥ 95% probability (recall), given this patient's specific assay parameters. It is personal because it depends on the individual signature size, mean coverage, and measured noise rate.

Derivation:

  1. Detection threshold n_th: the smallest read count where the null hypothesis is rejected at FPR = 5%:

$$n_{th} = \min{k : P(X \geq k \mid \mathrm{Binom}(N,, p_{err})) < 0.05}$$

  1. LOD at configurable target recall (default 95%) and FPR (default 5%): the smallest TF such that a true positive sample crosses the threshold at the target recall rate:

$$\mathrm{LOD} = \min{\mathrm{TF} : P(X \geq n_{th} \mid \mathrm{Binom}(N,, p_{err} + \mathrm{TF})) \geq 0.95}$$

where $N_{\text{eff}} = N \times P = \text{signature_size} \times \text{mean_coverage} \times \text{SNVQ_recall}$.

The LOD decreases (improves) with larger signature size, higher coverage, or lower noise rate. It is None when no threshold satisfies the FPR constraint (e.g., signature too small or coverage too low).

Locus Filters

Two optional pre-detection filters remove noisy loci before the Binomial test is run. Both default to enabled (CLI defaults); pass None programmatically to disable.

Noisy-Loci Filter (--thresh-noise-lq-reads)

Removes loci where the number of low-quality reads (failing read_filter_query) meets or exceeds the threshold. Targets loci systematically affected by assay noise rather than true ctDNA signal.

Multi-Read Locus Filter (--thresh-multi-read-pvalue)

Removes loci whose per-locus read count is a significant outlier under a Poisson null model. The primary target is germline or mosaic variants leaking into the matched signature, but the test is applied identically to every (signature_type, signature) pair.

λ estimation: To avoid circular bias (germline outliers would inflate λ and mask themselves), λ is estimated only from background loci — those with ≤ _VAF_ESTIMATE_READ_CAP (= 6) reads:

$$\lambda = \frac{\text{reads at background loci}}{\text{corrected_coverage}} \times \text{mean_coverage}$$

A Jeffreys prior (0.5 / (N+1)) is applied when no background reads are observed.

Bonferroni N — per signature: Each (signature_type, signature) pair is tested independently using its own locus count as the family size N. This is the same logic used by the QC check (see below):

Signature type Bonferroni N
Matched matched signature's own locus count
Synthetic control (db_control) that replicate's own locus count
Cohort control that patient's own signature locus count

Using the matched signature_size as a shared N would under-correct large signatures and over-correct small ones.

A locus is flagged when:

$$p_i \times N < \text{thresh_multi_read_pvalue} \quad \text{and} \quad k_i \geq 2$$

The minimum-reads guard (k ≥ 2) prevents single-read loci from being removed; a single read is indistinguishable from background noise regardless of how small λ is. Flagged loci are removed from all reads of that signature type.

QC Checks

Up to six QC checks are displayed above the Assay Metrics in the report. They do not force an Indeterminate call — they are informational flags.

Check Threshold Rationale
Signature size ≥ 500 loci Too few loci reduce statistical power
Mean coverage ≥ 15× Low coverage inflates noise rate variance
Synthetic controls ≥ 20 Fewer controls make null distribution unreliable
Expected multi-read support distribution (matched) 0 outlier loci (Bonferroni-corrected p ≥ 1%) See below
Expected multi-read support distribution (synthetic controls) 0 outlier loci (Bonferroni-corrected p ≥ 1%) See below — only shown when synthetic controls are present
Expected multi-read support distribution (cohort controls) 0 outlier loci (Bonferroni-corrected p ≥ 1%) See below — only shown when cohort controls are present

Expected Multi-Read Support Distribution

These checks detect loci with a significantly higher read count than expected under the respective Poisson model. A flagged check may indicate germline variants (matched), contamination, or somatic variants leaking into control signatures.

Per-locus Poisson test:

For each locus with k observed supporting reads, the right-tail p-value is:

$$p_i = P(X \geq k_i \mid \mathrm{Poisson}(\lambda))$$

The expected rate λ differs by check:

Check λ per locus Bonferroni N
Matched signature mean_coverage × matched_vaf (measured tumor fraction) matched signature size
Synthetic controls (db_control) mean_coverage × p_err (background noise rate) each synthetic signature's own locus count
Cohort controls mean_coverage × p_err (background noise rate) each cohort signature's own locus count

Bonferroni correction for outliers:

A locus is declared an outlier when its p-value falls below the Bonferroni-corrected threshold:

$$p_i < \frac{\alpha}{N}$$

where α = 1%. The family size $N$ differs by group:

  • Matched signature: $N$ = matched signature size (number of filtered loci passing the signature filter).
  • Synthetic controls (db_control): each synthetic replicate is tested independently; $N$ = that replicate's own locus count. A locus is declared an outlier if the test fires for any single replicate. Synthetic controls are population-panel signatures drawn from unrelated samples, so their locus counts can differ substantially from the matched signature and from each other.
  • Cohort controls: same per-signature treatment; $N$ = each cohort patient's own signature size. Cohort controls are other patients' matched signatures evaluated on this patient's plasma, so their sizes can vary widely.

Using the matched signature_size as a shared $N$ for either control type would be incorrect: under-correcting large signatures and over-correcting small ones. The check is flagged (⚠️) when at least one outlier locus is found across any signature of that type.

Metadata

Release files for ugbio-mrd 1.31.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ugbio-mrd 1.31.0
File Size Uploaded
ugbio_mrd-1.31.0.tar.gz 77.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ugbio-mrd 1.31.0
File Interpreter ABI Platform
ugbio_mrd-1.31.0-py3-none-any.whl Python 3 none any Details

Total release size: 157.3 kB

Release files / ugbio_mrd-1.31.0.tar.gz

Download URL ugbio_mrd-1.31.0.tar.gz
Size 77.2 kB
Tags Source
SHA-256 checksum
How to use checksums
e6ea13bcddf651d1f66044349a0f28849b5884e4725d1c91e61db96aa7953d89
BLAKE2b-256 checksum
How to use checksums
8ac46589f13c84ee61e0ed08e8f983c018603aa61bce5e206aea787543708cf0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / ugbio_mrd-1.31.0-py3-none-any.whl

Download URL ugbio_mrd-1.31.0-py3-none-any.whl
Size 80.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5a3f68700dc6f78fa4e0eb52c3e9abb69db7e8771557e2cdd287b79455799939
BLAKE2b-256 checksum
How to use checksums
f1de1687cee0f32b23b063a5ddd9920fa9ab5dd29047f2fe1396db53a21893d2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

1.33.0

2 release files

1.32.0

2 release files

This release

1.31.0 This release

2 release files

1.30.1

2 release files

1.30.0

2 release files

1.29.0

2 release files

1.28.1

2 release files

1.28.0

2 release files

1.27.1

2 release files

1.27.0

2 release files

1.25.0

2 release files

1.24.1

2 release files

1.24.0

2 release files

1.23.0

2 release files

1.22.2

2 release files

1.22.1

2 release files

1.22.0

2 release files

1.21.2

2 release files

1.21.1

2 release files

1.21.0

2 release files

1.20.0

2 release files

1.18.0

2 release files

1.17.2

2 release files

1.17.1

2 release files

1.17.0

2 release files

1.16.2

2 release files

1.16.1

2 release files

1.16.0

2 release files

1.15.0

2 release files

1.14.0

2 release files

1.13.2

2 release files

1.13.1

2 release files

1.12.0

2 release files

1.11.0

2 release files

1.10.2

2 release files

1.10.1

2 release files

1.10.0

2 release files

1.8.0

2 release files

1.7.0

2 release files

1.6.1

2 release files

1.6.0

2 release files

1.5.5

2 release files

1.5.4

2 release files

1.5.3

2 release files

1.5.2

2 release files

1.5.1

2 release files

1.5.0

2 release files

1.4.3

2 release files

1.4.2

2 release files

1.4.1

2 release files

1.4.0

2 release files

1.3.4

2 release files

1.3.3

2 release files

1.3.2

2 release files

1.3.1

2 release files

1.3.0

2 release files

1.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page