Skip to content

Commit 420f723

Browse files
committed
Refactor LRT calculation
1 parent e5584be commit 420f723

1 file changed

Lines changed: 36 additions & 23 deletions

File tree

IBDReduce/ibdreduce_v3.py

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,41 @@ def ibdlen(fpath: str, gmap: GeneticMap) -> Tuple[int, float]:
167167
return breakpoints, total
168168

169169

170+
def compute_likelihood_ratio(obs_rates: np.ndarray, ncase: int, ncontrol: int) -> np.ndarray:
171+
"""Compute per-breakpoint likelihood ratios for the localization test.
172+
173+
Args:
174+
obs_rates: Observed rates for the breakpoint, with case-case and case-control
175+
rates stored in the first two columns.
176+
ncase: Number of cases in the phenotype.
177+
ncontrol: Number of controls in the phenotype.
178+
179+
Returns:
180+
An array of likelihood ratios corresponding to the supplied breakpoints.
181+
"""
182+
183+
cscs = ncase * (ncase - 1.0) / 2.0
184+
cscn = ncase * ncontrol
185+
186+
obs_counts = obs_rates[:, 0:2].copy()
187+
obs_counts[:, 0] *= cscs
188+
obs_counts[:, 1] *= cscn
189+
obs_counts = np.rint(obs_counts).astype(np.int64)
190+
191+
weights = np.array([cscs / (cscs + cscn), cscn / (cscs + cscn)], dtype=np.float64)
192+
total_counts = np.sum(obs_counts * weights, axis=1)
193+
194+
llik_ratio = np.zeros(obs_counts.shape[0], dtype=np.float64)
195+
for idx in range(obs_counts.shape[0]):
196+
null = stats.poisson.logpmf(obs_counts[idx, 0], weights[0] * total_counts[idx])
197+
null += stats.poisson.logpmf(obs_counts[idx, 1], weights[1] * total_counts[idx])
198+
alt = stats.poisson.logpmf(obs_counts[idx, 0], obs_counts[idx, 0])
199+
alt += stats.poisson.logpmf(obs_counts[idx, 1], obs_counts[idx, 1])
200+
llik_ratio[idx] = -2 * (null - alt)
201+
202+
return llik_ratio
203+
204+
170205
def parse_pheno(ifile: str, phenotype: Optional[str] = None) -> Tuple[int, int]:
171206
"""
172207
@@ -332,29 +367,7 @@ def main():
332367
if args.lrt:
333368
ncase, ncontrol = parse_pheno(args.lrt, args.phenotype_name)
334369

335-
cscs = ncase * (ncase - 1.) / 2.
336-
cscn = ncase * ncontrol
337-
338-
obs_counts = obs_rates[:, 0:2]
339-
340-
obs_counts[:, 0] *= cscs
341-
obs_counts[:, 1] *= cscn
342-
obs_counts = obs_counts.astype(np.int64)
343-
344-
weights = np.array([cscs / (cscs + cscn), cscn / (cscs + cscn)])
345-
346-
total_counts = np.sum(obs_counts * weights, 1)
347-
total_counts = total_counts.astype(np.int64)
348-
mean_rates = np.sum(obs_rates[:, 0:2] * weights, 1)
349-
350-
for i in range(len(mean_rates)):
351-
# Null is Pois(obs_cscs, Expected_counts[cscs]) * Pois(obs_cscn, Expected_counts[cscn])
352-
null = stats.poisson.logpmf(obs_counts[i, 0], weights[0] * total_counts[i])
353-
null += stats.poisson.logpmf(obs_counts[i, 1], weights[1] * total_counts[i])
354-
alt = stats.poisson.logpmf(obs_counts[i, 0], obs_counts[i, 0])
355-
alt += stats.poisson.logpmf(obs_counts[i, 1], obs_counts[i, 1])
356-
357-
llik_ratio[i] = -2 * (null - alt)
370+
llik_ratio = compute_likelihood_ratio(obs_rates, ncase, ncontrol)
358371

359372
def subtract(a):
360373
return a - avgs

0 commit comments

Comments
 (0)