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.32.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.32.0
File Size Uploaded
ugbio_mrd-1.32.0.tar.gz 78.3 kB Details

Built distribution (wheel)

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

Total release size: 159.5 kB

Release files / ugbio_mrd-1.32.0.tar.gz

Download URL ugbio_mrd-1.32.0.tar.gz
Size 78.3 kB
Tags Source
SHA-256 checksum
How to use checksums
cd03f0739055de96cb72f29090404f1c61dc53c09dbc7d79761d23b1fc6d0efa
BLAKE2b-256 checksum
How to use checksums
627b918befb893f6a77fc0535928f9190d6694a6eed7b3473eb1100d626a21c9
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.32.0-py3-none-any.whl

Download URL ugbio_mrd-1.32.0-py3-none-any.whl
Size 81.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
440968b4ed3b4662457d54de66aaf51139a6d49fcc1ea1e7d5b292c75e74aa31
BLAKE2b-256 checksum
How to use checksums
e935860ca3afcf0b5318b696d6c7c533e4c44b6d10365134e42b4b1163618398
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

This release

1.32.0 This release

2 release files

1.31.0

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