@@ -101,6 +101,7 @@ def wang_binomial_ci(
101101 precision ,
102102 grid_one ,
103103 grid_two ,
104+ verbose ,
104105 )
105106 if verbose :
106107 print (f"Left CI: { ci_l } " )
@@ -114,6 +115,7 @@ def wang_binomial_ci(
114115 precision ,
115116 grid_one ,
116117 grid_two ,
118+ verbose ,
117119 )
118120 if verbose :
119121 print (f"Right CI: { ci_u } " )
@@ -122,7 +124,7 @@ def wang_binomial_ci(
122124 return ConfidenceInterval (lower , upper , estimate , conf_level , "wang" , sides_val )
123125 else :
124126 ci = binomial_ci_one_sided (
125- n_positive , n_total , ref_positive , ref_total , conf_level , sides_val , precision , grid_one , grid_two
127+ n_positive , n_total , ref_positive , ref_total , conf_level , sides_val , precision , grid_one , grid_two , verbose
126128 )
127129 return ConfidenceInterval (ci [1 ], ci [2 ], ci [0 ], conf_level , "wang" , sides_val )
128130
@@ -137,6 +139,7 @@ def binomial_ci_one_sided(
137139 precision : float ,
138140 grid_one : int ,
139141 grid_two : int ,
142+ verbose : bool = False ,
140143) -> List [float ]:
141144 """Helper function that calculates one-sided confidence interval.
142145
@@ -160,11 +163,13 @@ def binomial_ci_one_sided(
160163 "right-sided" (aliases "right_sided", "right", "rs", "r"),
161164 case insensitive.
162165 precision : float, optional
163- Precision for the search algorithm, by default 1e-5
166+ Precision for the search algorithm, by default 1e-5.
164167 grid_one : int, optional
165- Number of grid points in first step, by default 30
168+ Number of grid points in first step, by default 30.
166169 grid_two : int, optional
167- Number of grid points in second step, by default 20
170+ Number of grid points in second step, by default 20.
171+ verbose : bool, optional
172+ Verbosity for debug message, by default False.
168173
169174 Returns
170175 -------
@@ -204,7 +209,7 @@ def binomial_ci_one_sided(
204209 f [:, 2 ] = (p1hat - p0hat ) / np .sqrt (denom )
205210
206211 # Sort f by the third column in descending order
207- f = f [(- f [:, 2 ]).argsort (), :]
212+ f = f [(- f [:, 2 ]).argsort (kind = "stable" ), :]
208213
209214 allvector = np .round (f [:, 0 ] * (m + 2 ) + f [:, 1 ]).astype (int )
210215 allvectormove = np .round ((f [:, 0 ] + 1 ) * (m + 3 ) + (f [:, 1 ] + 1 )).astype (int )
@@ -268,7 +273,7 @@ def binomial_ci_one_sided(
268273
269274 # Generate N
270275 n_arr = np .unique (np .vstack ((a , b )), axis = 0 )
271- nvector = ((n_arr [:, 0 ] + 1 ) * (m + 3 ) + n_arr [:, 1 ] + 1 ).astype (int )
276+ nvector = ((n_arr [:, 0 ] + 1 ) * (m + 3 ) + n_arr [:, 1 ] + 1 ).astype (int ) # type: ignore
272277 nvector = nvector [np .isin (nvector , allvectormove )]
273278
274279 skvector = ((s [:kk , 0 ] + 1 ) * (m + 3 ) + s [:kk , 1 ] + 1 ).astype (int )
@@ -303,6 +308,7 @@ def binomial_ci_one_sided(
303308 else :
304309 length_nc = nc_arr .shape [0 ]
305310
311+ ncmax = 0 # avoid pylance warning
306312 for ci in range (length_nc ):
307313 ls_arr [kk , 0 :2 ] = nc_arr [ci , 0 :2 ]
308314 i1_vec = ls_arr [: (kk + 1 ), 0 ]
@@ -363,7 +369,7 @@ def binomial_ci_one_sided(
363369 if length_nc >= 2 :
364370 valid = ~ np .isnan (nc_arr [:, 0 ])
365371 ncnomiss = nc_arr [valid ]
366- ncnomiss = ncnomiss [(- ncnomiss [:, 2 ]).argsort (), :]
372+ ncnomiss = ncnomiss [(- ncnomiss [:, 2 ]).argsort (kind = "stable" ), :]
367373 morepoint = np .sum (ncnomiss [:, 2 ] >= ncnomiss [0 , 2 ] - delta )
368374 if morepoint >= 2 :
369375 ls_arr [kk : kk + morepoint , 0 :2 ] = ncnomiss [:morepoint , 0 :2 ]
@@ -429,7 +435,8 @@ def binomial_ci_one_sided(
429435
430436 kk1 = kk
431437
432- output = [val .item () if isinstance (val , np .generic ) else val for val in output ]
438+ # output = [val.item() if isinstance(val, np.generic) else val for val in output]
439+ output = np .array (output ).tolist ()
433440
434441 return output
435442
@@ -456,27 +463,32 @@ def _prob2step(delv, delta, n, m, i1, i2, grid_one, grid_two):
456463 p0 = np .linspace (- delv + delta , 1 - delta , grid_one )
457464 else :
458465 p0 = np .linspace (delta , 1 - delv - delta , grid_one )
466+
459467 i1 = np .atleast_1d (i1 )
460468 i2 = np .atleast_1d (i2 )
461469 part1 = np .log (comb (n , i1 ))[:, None ] + np .outer (i1 , np .log (p0 + delv )) + np .outer (n - i1 , np .log (1 - p0 - delv ))
462470 part2 = np .log (comb (m , i2 ))[:, None ] + np .outer (i2 , np .log (p0 )) + np .outer (m - i2 , np .log (1 - p0 ))
463471 sumofprob = np .exp (part1 + part2 ).sum (axis = 0 )
464472
465- # plateau-aware refinement (R: which(sumofprob == max(sumofprob)) )
466- mansum = sumofprob . max ( )
467- atol = 1e-14 * ( mansum if mansum > 0 else 1.0 )
468- plateau_idx = np .where (np . isclose ( sumofprob , mansum , rtol = 0.0 , atol = atol ))[0 ]
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 ]
469477 leftmost = plateau_idx .min ()
470478 rightmost = plateau_idx .max ()
471479
472- stepv = (p0 [- 1 ] - p0 [0 ]) / grid_one
473- lowerb = max (p0 [0 ], p0 [rightmost ] - stepv ) + delta
474- upperb = min (p0 [- 1 ], p0 [leftmost ] + stepv ) - delta
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
475484
476- # stepv = (p0[-1] - p0[0]) / grid_one
477- # maxloc = np.argmax(sumofprob)
478- # lowerb = max(p0[0], p0[maxloc] - stepv) + delta
479- # upperb = min(p0[-1], p0[maxloc] + stepv) - delta
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
480492
481493 p0 = np .linspace (lowerb , upperb , grid_two )
482494 part1 = np .log (comb (n , i1 ))[:, None ] + np .outer (i1 , np .log (p0 + delv )) + np .outer (n - i1 , np .log (1 - p0 - delv ))
@@ -490,28 +502,25 @@ def _prob2steplmin(delv, delta, n, m, i1, i2, grid_one, grid_two):
490502 p0 = np .linspace (- delv + delta , 1 - delta , grid_one )
491503 else :
492504 p0 = np .linspace (delta , 1 - delv - delta , grid_one )
505+
493506 i1 = np .atleast_1d (i1 )
494507 i2 = np .atleast_1d (i2 )
495508 part1 = np .log (comb (n , i1 ))[:, None ] + np .outer (i1 , np .log (p0 + delv )) + np .outer (n - i1 , np .log (1 - p0 - delv ))
496509 part2 = np .log (comb (m , i2 ))[:, None ] + np .outer (i2 , np .log (p0 )) + np .outer (m - i2 , np .log (1 - p0 ))
497510 sumofprob = np .exp (part1 + part2 ).sum (axis = 0 )
498511
499- # plateau-aware refinement for minima (R: which(sumofprob == min(sumofprob)) )
500- mansum = sumofprob . min ( )
501- atol = 1e-14 * ( abs ( mansum ) if mansum != 0 else 1.0 )
502- plateau_idx = np .where (np . isclose ( sumofprob , mansum , rtol = 0.0 , atol = atol ))[0 ]
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 ]
503516 leftmost = plateau_idx .min ()
504517 rightmost = plateau_idx .max ()
505518
506- stepv = (p0 [- 1 ] - p0 [0 ]) / grid_one
519+ denom = (grid_one - 1 ) if grid_one > 1 else 1
520+ stepv = (p0 [- 1 ] - p0 [0 ]) / denom
507521 lowerb = max (p0 [0 ], p0 [rightmost ] - stepv ) + delta
508522 upperb = min (p0 [- 1 ], p0 [leftmost ] + stepv ) - delta
509523
510- # stepv = (p0[-1] - p0[0]) / grid_one
511- # minloc = np.argmin(sumofprob)
512- # lowerb = max(p0[0], p0[minloc] - stepv) + delta
513- # upperb = min(p0[-1], p0[minloc] + stepv) - delta
514-
515524 p0 = np .linspace (lowerb , upperb , grid_two )
516525 part1 = np .log (comb (n , i1 ))[:, None ] + np .outer (i1 , np .log (p0 + delv )) + np .outer (n - i1 , np .log (1 - p0 - delv ))
517526 part2 = np .log (comb (m , i2 ))[:, None ] + np .outer (i2 , np .log (p0 )) + np .outer (m - i2 , np .log (1 - p0 ))
0 commit comments