diff options
author | Kevin Sheppard <bashtage@users.noreply.github.com> | 2021-04-22 14:35:43 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-22 08:35:43 -0500 |
commit | 341316d5158477b06f877db60049b0995ab78128 (patch) | |
tree | 3cabe19b30eaed52551ba58a7dfa4945f688fda6 | |
parent | f048051926bdc1f145b4e6a9516b0ee55b5d1e8e (diff) | |
download | numpy-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.py | 5 | ||||
-rw-r--r-- | numpy/lib/tests/test_function_base.py | 22 |
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)) |