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

+4 -1
View File
@@ -47,6 +47,7 @@ def main() -> int:
ap.add_argument("--truth", required=True, type=Path)
ap.add_argument("--bpm", required=True)
ap.add_argument("--min-qual", type=float, default=20)
ap.add_argument("--ignore-filter", action="append", default=[], help="FILTER values not to exclude (repeatable)")
ap.add_argument("--out", required=True, type=Path)
a = ap.parse_args()
a.out.mkdir(parents=True, exist_ok=True)
@@ -66,7 +67,8 @@ def main() -> int:
for s in side["samples"]:
if s.get("status") != "OK":
continue
calls[s["sample_id"]] = [e for e in s["events"] if e["quality"] >= a.min_qual and e["filters"] == ["PASS"]]
ign = set(a.ignore_filter) | {"PASS"}
calls[s["sample_id"]] = [e for e in s["events"] if e["quality"] >= a.min_qual and set(e["filters"]) <= ign]
truth: dict[str, list[tuple[str, int, int, str]]] = defaultdict(list)
with a.truth.open() as fh:
for line in fh:
@@ -142,6 +144,7 @@ def main() -> int:
summary = {
"samples": len(per_sample),
"min_qual": a.min_qual,
"ignored_filters": sorted(a.ignore_filter),
"sensitivity": {
t: {b: {"found": v[0], "truth": v[1], "rate": rate(v)} for b, v in sorted(d.items())}
for t, d in sens.items()