summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Sheppard <bashtage@users.noreply.github.com>2021-04-22 14:35:43 +0100
committerGitHub <noreply@github.com>2021-04-22 08:35:43 -0500
commit341316d5158477b06f877db60049b0995ab78128 (patch)
tree3cabe19b30eaed52551ba58a7dfa4945f688fda6
parentf048051926bdc1f145b4e6a9516b0ee55b5d1e8e (diff)
downloadnumpy-341316d5158477b06f877db60049b0995ab78128.tar.gz
BUG: Prevent nan being used in percentile (gh-18831)
Reject NaN as a percentile/quantile value. Previously NaNs could pass the range check `0 <= q <= 1`. closes #18830
-rw-r--r--numpy/lib/function_base.py5
-rw-r--r--numpy/lib/tests/test_function_base.py22
2 files changed, 24 insertions, 3 deletions
diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py
index af5a6e45c..0bb41c270 100644
--- a/numpy/lib/function_base.py
+++ b/numpy/lib/function_base.py
@@ -3957,11 +3957,10 @@ def _quantile_is_valid(q):
# avoid expensive reductions, relevant for arrays with < O(1000) elements
if q.ndim == 1 and q.size < 10:
for i in range(q.size):
- if q[i] < 0.0 or q[i] > 1.0:
+ if not (0.0 <= q[i] <= 1.0):
return False
else:
- # faster than any()
- if np.count_nonzero(q < 0.0) or np.count_nonzero(q > 1.0):
+ if not (np.all(0 <= q) and np.all(q <= 1)):
return False
return True
diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py
index 761ea83a3..0b66ccf8c 100644
--- a/numpy/lib/tests/test_function_base.py
+++ b/numpy/lib/tests/test_function_base.py
@@ -2750,6 +2750,10 @@ class TestPercentile:
assert_equal(p, Fraction(7, 4))
assert_equal(type(p), Fraction)
+ p = np.percentile(x, [Fraction(50)])
+ assert_equal(p, np.array([Fraction(7, 4)]))
+ assert_equal(type(p), np.ndarray)
+
def test_api(self):
d = np.ones(5)
np.percentile(d, 5, None, None, False)
@@ -3144,6 +3148,16 @@ class TestPercentile:
assert_equal(np.percentile(
a, [0.3, 0.6], (0, 2), interpolation='nearest'), b)
+ def test_nan_q(self):
+ # GH18830
+ with pytest.raises(ValueError, match="Percentiles must be in"):
+ np.percentile([1, 2, 3, 4.0], np.nan)
+ with pytest.raises(ValueError, match="Percentiles must be in"):
+ np.percentile([1, 2, 3, 4.0], [np.nan])
+ q = np.linspace(1.0, 99.0, 16)
+ q[0] = np.nan
+ with pytest.raises(ValueError, match="Percentiles must be in"):
+ np.percentile([1, 2, 3, 4.0], q)
class TestQuantile:
# most of this is already tested by TestPercentile
@@ -3180,6 +3194,14 @@ class TestQuantile:
assert_equal(q, Fraction(7, 4))
assert_equal(type(q), Fraction)
+ q = np.quantile(x, [Fraction(1, 2)])
+ assert_equal(q, np.array([Fraction(7, 4)]))
+ assert_equal(type(q), np.ndarray)
+
+ q = np.quantile(x, [[Fraction(1, 2)]])
+ assert_equal(q, np.array([[Fraction(7, 4)]]))
+ assert_equal(type(q), np.ndarray)
+
# repeat with integral input but fractional quantile
x = np.arange(8)
assert_equal(np.quantile(x, Fraction(1, 2)), Fraction(7, 2))