v2 CN: real-data validation vs NYGC 30x SVs (interim), noise gate on normalised LRR (K-027)

GSE165845 360 arrays: constitutional DEL/DUP calls 77/74 % in the NYGC SV truth, LOH
reproduced across replicates 74 %; mosaic calls are mostly false positives (12-23 %),
sensitivity for 25 kb-1 Mb events 7-13 % at QUAL >= 20. All samples had been flagged
SampleQuality by the summary logr_dev (cluster-file mismatch); the gate now uses the SD
of the LRR after the batch reference. Validation script: --ignore-filter.
This commit is contained in:
kemal committed 2026-09-29 07:42:06 +01:00
1 parent 1e41acef27
commit 6ad0c53664
6 files changed
+252 -3

No files matched your search

+6 -2
View File
@@ -323,8 +323,11 @@ def call_sample(si: SampleInput, ctx: dict[str, Any], opts: CnCallOptions) -> di
lrr, gcfit = gc_correct(lrr, model.gc, auto)
lrr = lrr - float(np.nanmedian(lrr[auto]))
logr_dev = si.logr_dev if math.isfinite(si.logr_dev) else float(np.nanstd(lrr[auto]))
noisy = logr_dev > 0.2
whole_chrom_only = logr_dev > 0.3
# CYTO-014 gates on the noise of the LRR the caller actually uses (after the batch reference and GC correction):
# the summary's logr_dev also measures cluster-file mismatch, which the reference removes (K-027)
gate_sd = float(np.nanstd(lrr[auto])) if model.ref_lrr is not None else logr_dev
noisy = gate_sd > 0.2
whole_chrom_only = gate_sd > 0.3
if noisy:
flags.append("high_noise")
if whole_chrom_only:
@@ -417,6 +420,7 @@ def call_sample(si: SampleInput, ctx: dict[str, Any], opts: CnCallOptions) -> di
if excess:
row["qc_flags"] = ";".join([*flags, "excess_events:" + ",".join(excess)])
row["lrr_sd_segmentation"] = seg_sd
row["lrr_sd_gate"] = gate_sd
row["baf_sd"] = baf_sd
# CYTO-033 sample and chromosome statistics (unsmoothed LRR), for cn annotate
la = lrr[auto & np.isfinite(lrr)]