diff options
author | Sebastian Berg <sebastian@sipsolutions.net> | 2020-06-27 11:35:27 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-27 11:35:27 -0500 |
commit | 4d5b2558c275a4a46b6ab0c486536d8e779651ce (patch) | |
tree | 29da4bc4873a88541fd3f59edec03f51c2930261 | |
parent | f156d37e63cf1f99635153e0022695285fc4a58d (diff) | |
parent | 88acbc852eeb73edd0d09c773f125725c8a0587b (diff) | |
download | numpy-4d5b2558c275a4a46b6ab0c486536d8e779651ce.tar.gz |
Merge pull request #16273 from CloseChoice/BUG-order_percentile-monotonically
BUG: Order percentile monotonically
-rw-r--r-- | numpy/lib/function_base.py | 8 | ||||
-rw-r--r-- | numpy/lib/tests/test_function_base.py | 71 |
2 files changed, 78 insertions, 1 deletions
diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index cf6f4891c..1053598b1 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -3879,7 +3879,13 @@ def _quantile_is_valid(q): def _lerp(a, b, t, out=None): """ Linearly interpolate from a to b by a factor of t """ - return add(a*(1 - t), b*t, out=out) + diff_b_a = subtract(b, a) + # asanyarray is a stop-gap until gh-13105 + lerp_interpolation = asanyarray(add(a, diff_b_a*t, out=out)) + subtract(b, diff_b_a * (1 - t), out=lerp_interpolation, where=t>=0.5) + if lerp_interpolation.ndim == 0 and out is None: + lerp_interpolation = lerp_interpolation[()] # unpack 0d arrays + return lerp_interpolation def _quantile_ureduce_func(a, q, axis=None, out=None, overwrite_input=False, diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index 9ba0be56a..5ccac62e4 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -5,6 +5,10 @@ import decimal from fractions import Fraction import math import pytest +import hypothesis +from hypothesis.extra.numpy import arrays +import hypothesis.strategies as st + import numpy as np from numpy import ma @@ -3104,6 +3108,73 @@ class TestQuantile: np.quantile(np.arange(100.), p, interpolation="midpoint") assert_array_equal(p, p0) + def test_quantile_monotonic(self): + # GH 14685 + # test that the return value of quantile is monotonic if p0 is ordered + p0 = np.arange(0, 1, 0.01) + quantile = np.quantile(np.array([0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 1, 1, 9, 9, 9, + 8, 8, 7]) * 0.1, p0) + assert_equal(np.sort(quantile), quantile) + + @hypothesis.given(arr=arrays(dtype=np.float, shape=st.integers(min_value=3, + max_value=1000), + elements=st.floats(allow_infinity=False, + allow_nan=False, + min_value=-1e300, + max_value=1e300))) + def test_quantile_monotonic_hypo(self, arr): + p0 = np.arange(0, 1, 0.01) + quantile = np.quantile(arr, p0) + assert_equal(np.sort(quantile), quantile) + + +class TestLerp: + @hypothesis.given(t0=st.floats(allow_nan=False, allow_infinity=False, + min_value=0, max_value=1), + t1=st.floats(allow_nan=False, allow_infinity=False, + min_value=0, max_value=1), + a = st.floats(allow_nan=False, allow_infinity=False, + min_value=-1e300, max_value=1e300), + b = st.floats(allow_nan=False, allow_infinity=False, + min_value=-1e300, max_value=1e300)) + def test_lerp_monotonic(self, t0, t1, a, b): + l0 = np.lib.function_base._lerp(a, b, t0) + l1 = np.lib.function_base._lerp(a, b, t1) + if t0 == t1 or a == b: + assert l0 == l1 # uninteresting + elif (t0 < t1) == (a < b): + assert l0 <= l1 + else: + assert l0 >= l1 + + @hypothesis.given(t=st.floats(allow_nan=False, allow_infinity=False, + min_value=0, max_value=1), + a=st.floats(allow_nan=False, allow_infinity=False, + min_value=-1e300, max_value=1e300), + b=st.floats(allow_nan=False, allow_infinity=False, + min_value=-1e300, max_value=1e300)) + def test_lerp_bounded(self, t, a, b): + if a <= b: + assert a <= np.lib.function_base._lerp(a, b, t) <= b + else: + assert b <= np.lib.function_base._lerp(a, b, t) <= a + + @hypothesis.given(t=st.floats(allow_nan=False, allow_infinity=False, + min_value=0, max_value=1), + a=st.floats(allow_nan=False, allow_infinity=False, + min_value=-1e300, max_value=1e300), + b=st.floats(allow_nan=False, allow_infinity=False, + min_value=-1e300, max_value=1e300)) + def test_lerp_symmetric(self, t, a, b): + # double subtraction is needed to remove the extra precision that t < 0.5 has + assert np.lib.function_base._lerp(a, b, 1 - (1 - t)) == np.lib.function_base._lerp(b, a, 1 - t) + + def test_lerp_0d_inputs(self): + a = np.array(2) + b = np.array(5) + t = np.array(0.2) + assert np.lib.function_base._lerp(a, b, t) == 2.6 + class TestMedian: |