PGx CN: scan-date batch warning (PCN-006), CN-consistent BAF evidence (PCN-010, --bafs-in-cn),
noise-outlier exclusion + robustness test (PCN-017/EDGE-026), platform from the CSV manifest (CLI-032) Also: star-allele calls are checked for one manifest/build per run (PGX-011), duplications at the CN cap are named xN (PGX-022), and tandem names attach supporting variants to their full copy.
This commit is contained in:
1 parent
ed5e92b859
commit
1cb7b59559
8 files changed
+216
-25
No files matched your search
+30
-2
@@ -195,9 +195,37 @@ def posterior(x: float, fit: RegionFit) -> F64:
|
||||
return out
|
||||
|
||||
|
||||
def call_cn(x: float, fit: RegionFit) -> tuple[int, int, F64]:
|
||||
"""PCN-009 steps 5–6: (CN, QUAL, posterior)."""
|
||||
def baf_loglik(baf: F64, pfb: F64 | None = None, sd: float = 0.05) -> F64:
|
||||
"""PCN-010: per-CN-state log-likelihood of a region's SNP BAFs: for CN c the BAF is k/c with binomial weights
|
||||
C(c, k) p^k (1 − p)^(c − k) from the probe's population B-allele frequency p (0.5 when unknown); CN 0 → uniform
|
||||
[LIT: Wang et al. 2007 (PennCNV BAF emissions); OURS: region-level use]."""
|
||||
ok = np.isfinite(baf)
|
||||
b = baf[ok]
|
||||
p = np.clip(np.nan_to_num(pfb[ok] if pfb is not None else np.full(len(b), 0.5), nan=0.5), 0.01, 0.99)
|
||||
out = np.zeros(len(CNS))
|
||||
if len(b) == 0:
|
||||
return out
|
||||
for c in CNS:
|
||||
if c == 0:
|
||||
out[c] = 0.0 # uniform on [0, 1]
|
||||
continue
|
||||
k = np.arange(c + 1)
|
||||
means = k / c
|
||||
w = np.array([math.comb(c, int(j)) for j in k])[None, :] * p[:, None] ** k[None, :] * (1 - p[:, None]) ** (
|
||||
c - k[None, :]) # fmt: skip
|
||||
dens = np.exp(-0.5 * ((b[:, None] - means[None, :]) / sd) ** 2) / (sd * math.sqrt(2 * math.pi))
|
||||
out[c] = float(np.log(0.98 * (w * dens).sum(axis=1) + 0.02).sum())
|
||||
return out
|
||||
|
||||
|
||||
def call_cn(x: float, fit: RegionFit, baf_ll: F64 | None = None) -> tuple[int, int, F64]:
|
||||
"""PCN-009 steps 5–6: (CN, QUAL, posterior); ``baf_ll`` (PCN-010, experimental ``--bafs-in-cn``) is added to the
|
||||
log posterior."""
|
||||
p = posterior(x, fit)
|
||||
if baf_ll is not None:
|
||||
lp = np.log(np.maximum(p, 1e-300)) + baf_ll
|
||||
p = np.exp(lp - lp.max())
|
||||
p = p / p.sum()
|
||||
cn = int(np.argmax(p))
|
||||
pmax = float(p[cn])
|
||||
qual = 60 if pmax >= 1.0 else int(min(60, max(0, round(-10 * math.log10(max(1e-300, 1 - pmax))))))
|
||||
|
||||
Reference in new issue
Block a user