Describe the bug
DUMMY emits a spurious UserWarning — "Computed threshold 1.0000000000000002 is outside the range of 0 and 1" — on essentially every call, including the default configuration.
Decision scores are min-max normalized to [0, 1], so np.percentile(decision, perc) is also in [0, 1]. eval then adds machine epsilon (limit = percentile + eps) so that, at contam=0, the top-scoring point stays an inlier (cut uses decision >= limit). But it passes that eps-bumped limit to _check_threshold, so when the percentile is the maximum (== 1), limit == 1 + eps > 1 trips the range check and warns — even though the threshold is valid and the labels are correct.
The project's own test suite triggers this 10 times, all from tests/test_dummy.py.
Steps/Code to Reproduce
import warnings
import numpy as np
from pythresh.thresholds.dummy import DUMMY
rng = np.random.RandomState(0)
scores = np.r_[rng.normal(0, 1, 45), rng.normal(6, 1, 5)]
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
labels = DUMMY().eval(scores) # default contam=None -> 0 outliers
print(len(w), "warning(s):", str(w[0].message))
# 1 warning(s): Computed threshold 1.0000000000000002 is outside the range of 0 and 1. ...
Expected behavior
No warning: the percentile-based threshold is always in range, and the + eps is an intentional boundary nudge (to keep the maximum-scoring point an inlier at contam=0), not an out-of-range threshold.
Fix
Validate the in-range percentile with _check_threshold instead of the eps-bumped limit. The stored thresh_ and the returned labels are unchanged. PR incoming.
Versions
pythresh 1.1.1
numpy 2.4.6, scipy 1.18.0, scikit-learn 1.9.0
Python 3.12.13
Describe the bug
DUMMYemits a spuriousUserWarning— "Computed threshold 1.0000000000000002 is outside the range of 0 and 1" — on essentially every call, including the default configuration.Decision scores are min-max normalized to
[0, 1], sonp.percentile(decision, perc)is also in[0, 1].evalthen adds machine epsilon (limit = percentile + eps) so that, atcontam=0, the top-scoring point stays an inlier (cutusesdecision >= limit). But it passes that eps-bumpedlimitto_check_threshold, so when the percentile is the maximum (== 1),limit == 1 + eps > 1trips the range check and warns — even though the threshold is valid and the labels are correct.The project's own test suite triggers this 10 times, all from
tests/test_dummy.py.Steps/Code to Reproduce
Expected behavior
No warning: the percentile-based threshold is always in range, and the
+ epsis an intentional boundary nudge (to keep the maximum-scoring point an inlier atcontam=0), not an out-of-range threshold.Fix
Validate the in-range percentile with
_check_thresholdinstead of the eps-bumpedlimit. The storedthresh_and the returned labels are unchanged. PR incoming.Versions