@@ -43,16 +43,17 @@ def wang_binomial_ci(
4343 sides : Union[str, int], optional
4444 sides: str or int, default "two-sided",
4545 the sides of the confidence interval, should be one of
46- "two-sided" (aliases "2-sided", "two_sided", "2_sided", "2-sides", "two_sides", "two-sides", "2_sides", "ts", "t", "two", "2", 2),
46+ "two-sided" (aliases "2-sided", "two_sided", "2_sided", "2-sides",
47+ "two_sides", "two-sides", "2_sides", "ts", "t", "two", "2", 2),
4748 "left-sided" (aliases "left_sided", "left", "ls", "l"),
4849 "right-sided" (aliases "right_sided", "right", "rs", "r"),
4950 case insensitive.
5051 precision : float, optional
51- Precision for the search algorithm, by default 1e-5
52+ Precision for the search algorithm, by default 1e-5.
5253 grid_one : int, optional
53- Number of grid points in first step, by default 30
54+ Number of grid points in first step, by default 30.
5455 grid_two : int, optional
55- Number of grid points in second step, by default 20
56+ Number of grid points in second step, by default 20.
5657 verbose : bool, optional
5758 Verbosity for debug message.
5859
@@ -101,7 +102,6 @@ def wang_binomial_ci(
101102 precision ,
102103 grid_one ,
103104 grid_two ,
104- verbose ,
105105 )
106106 if verbose :
107107 print (f"Left CI: { ci_l } " )
@@ -115,7 +115,6 @@ def wang_binomial_ci(
115115 precision ,
116116 grid_one ,
117117 grid_two ,
118- verbose ,
119118 )
120119 if verbose :
121120 print (f"Right CI: { ci_u } " )
@@ -124,7 +123,7 @@ def wang_binomial_ci(
124123 return ConfidenceInterval (lower , upper , estimate , conf_level , "wang" , sides_val )
125124 else :
126125 ci = binomial_ci_one_sided (
127- n_positive , n_total , ref_positive , ref_total , conf_level , sides_val , precision , grid_one , grid_two , verbose
126+ n_positive , n_total , ref_positive , ref_total , conf_level , sides_val , precision , grid_one , grid_two
128127 )
129128 return ConfidenceInterval (ci [1 ], ci [2 ], ci [0 ], conf_level , "wang" , sides_val )
130129
@@ -139,7 +138,6 @@ def binomial_ci_one_sided(
139138 precision : float ,
140139 grid_one : int ,
141140 grid_two : int ,
142- verbose : bool = False ,
143141) -> List [float ]:
144142 """Helper function that calculates one-sided confidence interval.
145143
@@ -154,11 +152,12 @@ def binomial_ci_one_sided(
154152 ref_total : int
155153 total number of samples of the reference.
156154 conf_level : float, optional
157- Confidence level, by default 0.95
155+ Confidence level, by default 0.95.
158156 sides : Union[str, int], optional
159157 sides: str or int, default "two-sided",
160158 the sides of the confidence interval, should be one of
161- "two-sided" (aliases "2-sided", "two_sided", "2_sided", "2-sides", "two_sides", "two-sides", "2_sides", "ts", "t", "two", "2", 2),
159+ "two-sided" (aliases "2-sided", "two_sided", "2_sided", "2-sides",
160+ "two_sides", "two-sides", "2_sides", "ts", "t", "two", "2", 2),
162161 "left-sided" (aliases "left_sided", "left", "ls", "l"),
163162 "right-sided" (aliases "right_sided", "right", "rs", "r"),
164163 case insensitive.
@@ -168,8 +167,6 @@ def binomial_ci_one_sided(
168167 Number of grid points in first step, by default 30.
169168 grid_two : int, optional
170169 Number of grid points in second step, by default 20.
171- verbose : bool, optional
172- Verbosity for debug message, by default False.
173170
174171 Returns
175172 -------
@@ -209,7 +206,7 @@ def binomial_ci_one_sided(
209206 f [:, 2 ] = (p1hat - p0hat ) / np .sqrt (denom )
210207
211208 # Sort f by the third column in descending order
212- f = f [(- f [:, 2 ]).argsort (kind = "stable" ), :]
209+ f = f [(- f [:, 2 ]).argsort (), :]
213210
214211 allvector = np .round (f [:, 0 ] * (m + 2 ) + f [:, 1 ]).astype (int )
215212 allvectormove = np .round ((f [:, 0 ] + 1 ) * (m + 3 ) + (f [:, 1 ] + 1 )).astype (int )
@@ -273,7 +270,7 @@ def binomial_ci_one_sided(
273270
274271 # Generate N
275272 n_arr = np .unique (np .vstack ((a , b )), axis = 0 )
276- nvector = ((n_arr [:, 0 ] + 1 ) * (m + 3 ) + n_arr [:, 1 ] + 1 ).astype (int ) # type: ignore
273+ nvector = ((n_arr [:, 0 ] + 1 ) * (m + 3 ) + n_arr [:, 1 ] + 1 ).astype (int )
277274 nvector = nvector [np .isin (nvector , allvectormove )]
278275
279276 skvector = ((s [:kk , 0 ] + 1 ) * (m + 3 ) + s [:kk , 1 ] + 1 ).astype (int )
@@ -308,7 +305,6 @@ def binomial_ci_one_sided(
308305 else :
309306 length_nc = nc_arr .shape [0 ]
310307
311- ncmax = 0 # avoid pylance warning
312308 for ci in range (length_nc ):
313309 ls_arr [kk , 0 :2 ] = nc_arr [ci , 0 :2 ]
314310 i1_vec = ls_arr [: (kk + 1 ), 0 ]
@@ -369,7 +365,7 @@ def binomial_ci_one_sided(
369365 if length_nc >= 2 :
370366 valid = ~ np .isnan (nc_arr [:, 0 ])
371367 ncnomiss = nc_arr [valid ]
372- ncnomiss = ncnomiss [(- ncnomiss [:, 2 ]).argsort (kind = "stable" ), :]
368+ ncnomiss = ncnomiss [(- ncnomiss [:, 2 ]).argsort (), :]
373369 morepoint = np .sum (ncnomiss [:, 2 ] >= ncnomiss [0 , 2 ] - delta )
374370 if morepoint >= 2 :
375371 ls_arr [kk : kk + morepoint , 0 :2 ] = ncnomiss [:morepoint , 0 :2 ]
@@ -435,8 +431,7 @@ def binomial_ci_one_sided(
435431
436432 kk1 = kk
437433
438- # output = [val.item() if isinstance(val, np.generic) else val for val in output]
439- output = np .array (output ).tolist ()
434+ output = [val .item () if isinstance (val , np .generic ) else val for val in output ]
440435
441436 return output
442437
@@ -463,32 +458,27 @@ def _prob2step(delv, delta, n, m, i1, i2, grid_one, grid_two):
463458 p0 = np .linspace (- delv + delta , 1 - delta , grid_one )
464459 else :
465460 p0 = np .linspace (delta , 1 - delv - delta , grid_one )
466-
467461 i1 = np .atleast_1d (i1 )
468462 i2 = np .atleast_1d (i2 )
469463 part1 = np .log (comb (n , i1 ))[:, None ] + np .outer (i1 , np .log (p0 + delv )) + np .outer (n - i1 , np .log (1 - p0 - delv ))
470464 part2 = np .log (comb (m , i2 ))[:, None ] + np .outer (i2 , np .log (p0 )) + np .outer (m - i2 , np .log (1 - p0 ))
471465 sumofprob = np .exp (part1 + part2 ).sum (axis = 0 )
472466
473- # mansum = sumofprob. max()
474- # atol = 1e-14 * (mansum if mansum > 0 else 1.0 )
475- # plateau_idx = np.where(np.isclose(sumofprob, mansum, rtol=0.0, atol=atol))[0]
476- plateau_idx = np .where (sumofprob == sumofprob . max ( ))[0 ]
467+ # plateau-aware refinement (R: which( sumofprob == max(sumofprob)) )
468+ mansum = sumofprob . max ( )
469+ atol = 1e-14 * ( mansum if mansum > 0 else 1.0 )
470+ plateau_idx = np .where (np . isclose ( sumofprob , mansum , rtol = 0.0 , atol = atol ))[0 ]
477471 leftmost = plateau_idx .min ()
478472 rightmost = plateau_idx .max ()
479473
480- denom = (grid_one - 1 ) if grid_one > 1 else 1
481- stepv = (p0 [- 1 ] - p0 [0 ]) / denom
482- # lowerb = max(p0[0], p0[rightmost] - stepv) + delta
483- # upperb = min(p0[-1], p0[leftmost] + stepv) - delta
474+ stepv = (p0 [- 1 ] - p0 [0 ]) / grid_one
475+ lowerb = max (p0 [0 ], p0 [rightmost ] - stepv ) + delta
476+ upperb = min (p0 [- 1 ], p0 [leftmost ] + stepv ) - delta
484477
485- raw_lowerb = max (p0 [0 ], p0 [rightmost ] - stepv ) + delta
486- raw_upperb = min (p0 [- 1 ], p0 [leftmost ] + stepv ) - delta
487- if raw_lowerb <= raw_upperb :
488- lowerb , upperb = raw_lowerb , raw_upperb
489- else :
490- # Ensure bounds are ordered for linspace; swap if necessary
491- lowerb , upperb = raw_upperb , raw_lowerb
478+ # stepv = (p0[-1] - p0[0]) / grid_one
479+ # maxloc = np.argmax(sumofprob)
480+ # lowerb = max(p0[0], p0[maxloc] - stepv) + delta
481+ # upperb = min(p0[-1], p0[maxloc] + stepv) - delta
492482
493483 p0 = np .linspace (lowerb , upperb , grid_two )
494484 part1 = np .log (comb (n , i1 ))[:, None ] + np .outer (i1 , np .log (p0 + delv )) + np .outer (n - i1 , np .log (1 - p0 - delv ))
@@ -502,25 +492,28 @@ def _prob2steplmin(delv, delta, n, m, i1, i2, grid_one, grid_two):
502492 p0 = np .linspace (- delv + delta , 1 - delta , grid_one )
503493 else :
504494 p0 = np .linspace (delta , 1 - delv - delta , grid_one )
505-
506495 i1 = np .atleast_1d (i1 )
507496 i2 = np .atleast_1d (i2 )
508497 part1 = np .log (comb (n , i1 ))[:, None ] + np .outer (i1 , np .log (p0 + delv )) + np .outer (n - i1 , np .log (1 - p0 - delv ))
509498 part2 = np .log (comb (m , i2 ))[:, None ] + np .outer (i2 , np .log (p0 )) + np .outer (m - i2 , np .log (1 - p0 ))
510499 sumofprob = np .exp (part1 + part2 ).sum (axis = 0 )
511500
512- # mansum = sumofprob. min()
513- # atol = 1e-14 * (abs( mansum) if mansum != 0 else 1.0 )
514- # plateau_idx = np.where(np.isclose(sumofprob, mansum, rtol=0.0, atol=atol))[0]
515- plateau_idx = np .where (sumofprob == sumofprob . min ( ))[0 ]
501+ # plateau-aware refinement for minima (R: which( sumofprob == min(sumofprob)) )
502+ mansum = sumofprob . min ( )
503+ atol = 1e-14 * ( abs ( mansum ) if mansum != 0 else 1.0 )
504+ plateau_idx = np .where (np . isclose ( sumofprob , mansum , rtol = 0.0 , atol = atol ))[0 ]
516505 leftmost = plateau_idx .min ()
517506 rightmost = plateau_idx .max ()
518507
519- denom = (grid_one - 1 ) if grid_one > 1 else 1
520- stepv = (p0 [- 1 ] - p0 [0 ]) / denom
508+ stepv = (p0 [- 1 ] - p0 [0 ]) / grid_one
521509 lowerb = max (p0 [0 ], p0 [rightmost ] - stepv ) + delta
522510 upperb = min (p0 [- 1 ], p0 [leftmost ] + stepv ) - delta
523511
512+ # stepv = (p0[-1] - p0[0]) / grid_one
513+ # minloc = np.argmin(sumofprob)
514+ # lowerb = max(p0[0], p0[minloc] - stepv) + delta
515+ # upperb = min(p0[-1], p0[minloc] + stepv) - delta
516+
524517 p0 = np .linspace (lowerb , upperb , grid_two )
525518 part1 = np .log (comb (n , i1 ))[:, None ] + np .outer (i1 , np .log (p0 + delv )) + np .outer (n - i1 , np .log (1 - p0 - delv ))
526519 part2 = np .log (comb (m , i2 ))[:, None ] + np .outer (i2 , np .log (p0 )) + np .outer (m - i2 , np .log (1 - p0 ))
0 commit comments