diff options
Diffstat (limited to 'numpy/lib/tests/test_function_base.py')
-rw-r--r-- | numpy/lib/tests/test_function_base.py | 257 |
1 files changed, 176 insertions, 81 deletions
diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index 66110b479..b67a31b18 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -553,6 +553,11 @@ class TestInsert: with pytest.raises(IndexError): np.insert([0, 1, 2], np.array([], dtype=float), []) + @pytest.mark.parametrize('idx', [4, -4]) + def test_index_out_of_bounds(self, idx): + with pytest.raises(IndexError, match='out of bounds'): + np.insert([0, 1, 2], [idx], [3, 4]) + class TestAmax: @@ -2862,7 +2867,7 @@ class TestPercentile: assert_equal(np.percentile(x, 50), 1.75) x[1] = np.nan assert_equal(np.percentile(x, 0), np.nan) - assert_equal(np.percentile(x, 0, interpolation='nearest'), np.nan) + assert_equal(np.percentile(x, 0, method='nearest'), np.nan) def test_fraction(self): x = [Fraction(i, 2) for i in range(8)] @@ -2898,36 +2903,95 @@ class TestPercentile: [1, 1, 1]]) assert_array_equal(np.percentile(x, 50, axis=0), [1, 1, 1]) - def test_linear(self): - - # Test defaults - assert_equal(np.percentile(range(10), 50), 4.5) - - # explicitly specify interpolation_method 'linear' (the default) - assert_equal(np.percentile(range(10), 50, - interpolation='linear'), 4.5) - - def test_lower_higher(self): - - # interpolation_method 'lower'/'higher' - assert_equal(np.percentile(range(10), 50, - interpolation='lower'), 4) - assert_equal(np.percentile(range(10), 50, - interpolation='higher'), 5) - - def test_midpoint(self): - assert_equal(np.percentile(range(10), 51, - interpolation='midpoint'), 4.5) - assert_equal(np.percentile(range(11), 51, - interpolation='midpoint'), 5.5) - assert_equal(np.percentile(range(11), 50, - interpolation='midpoint'), 5) - - def test_nearest(self): - assert_equal(np.percentile(range(10), 51, - interpolation='nearest'), 5) - assert_equal(np.percentile(range(10), 49, - interpolation='nearest'), 4) + @pytest.mark.parametrize("dtype", np.typecodes["AllFloat"]) + def test_linear_nan_1D(self, dtype): + # METHOD 1 of H&F + arr = np.asarray([15.0, np.NAN, 35.0, 40.0, 50.0], dtype=dtype) + res = np.percentile( + arr, + 40.0, + method="linear") + np.testing.assert_equal(res, np.NAN) + np.testing.assert_equal(res.dtype, arr.dtype) + + H_F_TYPE_CODES = [(int_type, np.float64) + for int_type in np.typecodes["AllInteger"] + ] + [(np.float16, np.float64), + (np.float32, np.float64), + (np.float64, np.float64), + (np.longdouble, np.longdouble), + (np.complex64, np.complex128), + (np.complex128, np.complex128), + (np.clongdouble, np.clongdouble), + (np.dtype("O"), np.float64)] + + @pytest.mark.parametrize(["input_dtype", "expected_dtype"], H_F_TYPE_CODES) + @pytest.mark.parametrize(["method", "expected"], + [("inverted_cdf", 20), + ("averaged_inverted_cdf", 27.5), + ("closest_observation", 20), + ("interpolated_inverted_cdf", 20), + ("hazen", 27.5), + ("weibull", 26), + ("linear", 29), + ("median_unbiased", 27), + ("normal_unbiased", 27.125), + ]) + def test_linear_interpolation(self, + method, + expected, + input_dtype, + expected_dtype): + arr = np.asarray([15.0, 20.0, 35.0, 40.0, 50.0], dtype=input_dtype) + actual = np.percentile(arr, 40.0, method=method) + + np.testing.assert_almost_equal(actual, expected, 14) + + if method in ["inverted_cdf", "closest_observation"]: + if input_dtype == "O": + np.testing.assert_equal(np.asarray(actual).dtype, np.float64) + else: + np.testing.assert_equal(np.asarray(actual).dtype, + np.dtype(input_dtype)) + else: + np.testing.assert_equal(np.asarray(actual).dtype, + np.dtype(expected_dtype)) + + TYPE_CODES = np.typecodes["AllInteger"] + np.typecodes["AllFloat"] + "O" + + @pytest.mark.parametrize("dtype", TYPE_CODES) + def test_lower_higher(self, dtype): + assert_equal(np.percentile(np.arange(10, dtype=dtype), 50, + method='lower'), 4) + assert_equal(np.percentile(np.arange(10, dtype=dtype), 50, + method='higher'), 5) + + @pytest.mark.parametrize("dtype", TYPE_CODES) + def test_midpoint(self, dtype): + assert_equal(np.percentile(np.arange(10, dtype=dtype), 51, + method='midpoint'), 4.5) + assert_equal(np.percentile(np.arange(9, dtype=dtype) + 1, 50, + method='midpoint'), 5) + assert_equal(np.percentile(np.arange(11, dtype=dtype), 51, + method='midpoint'), 5.5) + assert_equal(np.percentile(np.arange(11, dtype=dtype), 50, + method='midpoint'), 5) + + @pytest.mark.parametrize("dtype", TYPE_CODES) + def test_nearest(self, dtype): + assert_equal(np.percentile(np.arange(10, dtype=dtype), 51, + method='nearest'), 5) + assert_equal(np.percentile(np.arange(10, dtype=dtype), 49, + method='nearest'), 4) + + def test_linear_interpolation_extrapolation(self): + arr = np.random.rand(5) + + actual = np.percentile(arr, 100) + np.testing.assert_equal(actual, arr.max()) + + actual = np.percentile(arr, 0) + np.testing.assert_equal(actual, arr.min()) def test_sequence(self): x = np.arange(8) * 0.5 @@ -2955,19 +3019,19 @@ class TestPercentile: assert_equal( np.percentile(x, (25, 50, 75), axis=1).shape, (3, 3, 5, 6)) assert_equal(np.percentile(x, (25, 50), - interpolation="higher").shape, (2,)) + method="higher").shape, (2,)) assert_equal(np.percentile(x, (25, 50, 75), - interpolation="higher").shape, (3,)) + method="higher").shape, (3,)) assert_equal(np.percentile(x, (25, 50), axis=0, - interpolation="higher").shape, (2, 4, 5, 6)) + method="higher").shape, (2, 4, 5, 6)) assert_equal(np.percentile(x, (25, 50), axis=1, - interpolation="higher").shape, (2, 3, 5, 6)) + method="higher").shape, (2, 3, 5, 6)) assert_equal(np.percentile(x, (25, 50), axis=2, - interpolation="higher").shape, (2, 3, 4, 6)) + method="higher").shape, (2, 3, 4, 6)) assert_equal(np.percentile(x, (25, 50), axis=3, - interpolation="higher").shape, (2, 3, 4, 5)) + method="higher").shape, (2, 3, 4, 5)) assert_equal(np.percentile(x, (25, 50, 75), axis=1, - interpolation="higher").shape, (3, 3, 5, 6)) + method="higher").shape, (3, 3, 5, 6)) def test_scalar_q(self): # test for no empty dimensions for compatibility with old percentile @@ -2993,33 +3057,33 @@ class TestPercentile: # test for no empty dimensions for compatibility with old percentile x = np.arange(12).reshape(3, 4) - assert_equal(np.percentile(x, 50, interpolation='lower'), 5.) + assert_equal(np.percentile(x, 50, method='lower'), 5.) assert_(np.isscalar(np.percentile(x, 50))) r0 = np.array([4., 5., 6., 7.]) - c0 = np.percentile(x, 50, interpolation='lower', axis=0) + c0 = np.percentile(x, 50, method='lower', axis=0) assert_equal(c0, r0) assert_equal(c0.shape, r0.shape) r1 = np.array([1., 5., 9.]) - c1 = np.percentile(x, 50, interpolation='lower', axis=1) + c1 = np.percentile(x, 50, method='lower', axis=1) assert_almost_equal(c1, r1) assert_equal(c1.shape, r1.shape) out = np.empty((), dtype=x.dtype) - c = np.percentile(x, 50, interpolation='lower', out=out) + c = np.percentile(x, 50, method='lower', out=out) assert_equal(c, 5) assert_equal(out, 5) out = np.empty(4, dtype=x.dtype) - c = np.percentile(x, 50, interpolation='lower', axis=0, out=out) + c = np.percentile(x, 50, method='lower', axis=0, out=out) assert_equal(c, r0) assert_equal(out, r0) out = np.empty(3, dtype=x.dtype) - c = np.percentile(x, 50, interpolation='lower', axis=1, out=out) + c = np.percentile(x, 50, method='lower', axis=1, out=out) assert_equal(c, r1) assert_equal(out, r1) def test_exception(self): assert_raises(ValueError, np.percentile, [1, 2], 56, - interpolation='foobar') + method='foobar') assert_raises(ValueError, np.percentile, [1], 101) assert_raises(ValueError, np.percentile, [1], -1) assert_raises(ValueError, np.percentile, [1], list(range(50)) + [101]) @@ -3033,18 +3097,18 @@ class TestPercentile: y = np.zeros((3,)) p = (1, 2, 3) np.percentile(x, p, out=y) - assert_equal(y, np.percentile(x, p)) + assert_equal(np.percentile(x, p), y) x = np.array([[1, 2, 3], [4, 5, 6]]) y = np.zeros((3, 3)) np.percentile(x, p, axis=0, out=y) - assert_equal(y, np.percentile(x, p, axis=0)) + assert_equal(np.percentile(x, p, axis=0), y) y = np.zeros((3, 2)) np.percentile(x, p, axis=1, out=y) - assert_equal(y, np.percentile(x, p, axis=1)) + assert_equal(np.percentile(x, p, axis=1), y) x = np.arange(12).reshape(3, 4) # q.dim > 1, float @@ -3060,12 +3124,12 @@ class TestPercentile: # q.dim > 1, int r0 = np.array([[0, 1, 2, 3], [4, 5, 6, 7]]) out = np.empty((2, 4), dtype=x.dtype) - c = np.percentile(x, (25, 50), interpolation='lower', axis=0, out=out) + c = np.percentile(x, (25, 50), method='lower', axis=0, out=out) assert_equal(c, r0) assert_equal(out, r0) r1 = np.array([[0, 4, 8], [1, 5, 9]]) out = np.empty((2, 3), dtype=x.dtype) - c = np.percentile(x, (25, 50), interpolation='lower', axis=1, out=out) + c = np.percentile(x, (25, 50), method='lower', axis=1, out=out) assert_equal(c, r1) assert_equal(out, r1) @@ -3082,10 +3146,10 @@ class TestPercentile: assert_array_equal(np.percentile(d, 50, axis=-4).shape, (1, 2, 1)) assert_array_equal(np.percentile(d, 50, axis=2, - interpolation='midpoint').shape, + method='midpoint').shape, (11, 1, 1)) assert_array_equal(np.percentile(d, 50, axis=-2, - interpolation='midpoint').shape, + method='midpoint').shape, (11, 1, 1)) assert_array_equal(np.array(np.percentile(d, [10, 50], axis=0)).shape, @@ -3108,10 +3172,10 @@ class TestPercentile: def test_no_p_overwrite(self): p = np.linspace(0., 100., num=5) - np.percentile(np.arange(100.), p, interpolation="midpoint") + np.percentile(np.arange(100.), p, method="midpoint") assert_array_equal(p, np.linspace(0., 100., num=5)) p = np.linspace(0., 100., num=5).tolist() - np.percentile(np.arange(100.), p, interpolation="midpoint") + np.percentile(np.arange(100.), p, method="midpoint") assert_array_equal(p, np.linspace(0., 100., num=5).tolist()) def test_percentile_overwrite(self): @@ -3189,14 +3253,14 @@ class TestPercentile: o = np.zeros((4,)) d = np.ones((3, 4)) assert_equal(np.percentile(d, 0, 0, out=o), o) - assert_equal(np.percentile(d, 0, 0, interpolation='nearest', out=o), o) + assert_equal(np.percentile(d, 0, 0, method='nearest', out=o), o) o = np.zeros((3,)) assert_equal(np.percentile(d, 1, 1, out=o), o) - assert_equal(np.percentile(d, 1, 1, interpolation='nearest', out=o), o) + assert_equal(np.percentile(d, 1, 1, method='nearest', out=o), o) o = np.zeros(()) assert_equal(np.percentile(d, 2, out=o), o) - assert_equal(np.percentile(d, 2, interpolation='nearest', out=o), o) + assert_equal(np.percentile(d, 2, method='nearest', out=o), o) def test_out_nan(self): with warnings.catch_warnings(record=True): @@ -3206,15 +3270,15 @@ class TestPercentile: d[2, 1] = np.nan assert_equal(np.percentile(d, 0, 0, out=o), o) assert_equal( - np.percentile(d, 0, 0, interpolation='nearest', out=o), o) + np.percentile(d, 0, 0, method='nearest', out=o), o) o = np.zeros((3,)) assert_equal(np.percentile(d, 1, 1, out=o), o) assert_equal( - np.percentile(d, 1, 1, interpolation='nearest', out=o), o) + np.percentile(d, 1, 1, method='nearest', out=o), o) o = np.zeros(()) assert_equal(np.percentile(d, 1, out=o), o) assert_equal( - np.percentile(d, 1, interpolation='nearest', out=o), o) + np.percentile(d, 1, method='nearest', out=o), o) def test_nan_behavior(self): a = np.arange(24, dtype=float) @@ -3269,13 +3333,13 @@ class TestPercentile: b[:, 1] = np.nan b[:, 2] = np.nan assert_equal(np.percentile(a, [0.3, 0.6], (0, 2)), b) - # axis02 not zerod with nearest interpolation + # axis02 not zerod with method='nearest' b = np.percentile(np.arange(24, dtype=float).reshape(2, 3, 4), - [0.3, 0.6], (0, 2), interpolation='nearest') + [0.3, 0.6], (0, 2), method='nearest') b[:, 1] = np.nan b[:, 2] = np.nan assert_equal(np.percentile( - a, [0.3, 0.6], (0, 2), interpolation='nearest'), b) + a, [0.3, 0.6], (0, 2), method='nearest'), b) def test_nan_q(self): # GH18830 @@ -3288,15 +3352,25 @@ class TestPercentile: 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 + def test_max_ulp(self): + x = [0.0, 0.2, 0.4] + a = np.quantile(x, 0.45) + # The default linear method would result in 0 + 0.2 * (0.45/2) = 0.18. + # 0.18 is not exactly representable and the formula leads to a 1 ULP + # different result. Ensure it is this exact within 1 ULP, see gh-20331. + np.testing.assert_array_max_ulp(a, 0.18, maxulp=1) + def test_basic(self): x = np.arange(8) * 0.5 assert_equal(np.quantile(x, 0), 0.) assert_equal(np.quantile(x, 1), 3.5) assert_equal(np.quantile(x, 0.5), 1.75) + @pytest.mark.xfail(reason="See gh-19154") def test_correct_quantile_value(self): a = np.array([True]) tf_quant = np.quantile(True, False) @@ -3305,12 +3379,11 @@ class TestQuantile: a = np.array([False, True, True]) quant_res = np.quantile(a, a) assert_array_equal(quant_res, a) - assert_equal(a.dtype, quant_res.dtype) + assert_equal(quant_res.dtype, a.dtype) def test_fraction(self): # fractional input, integral quantile x = [Fraction(i, 2) for i in range(8)] - q = np.quantile(x, 0) assert_equal(q, 0) assert_equal(type(q), Fraction) @@ -3339,20 +3412,36 @@ class TestQuantile: # this is worth retesting, because quantile does not make a copy p0 = np.array([0, 0.75, 0.25, 0.5, 1.0]) p = p0.copy() - np.quantile(np.arange(100.), p, interpolation="midpoint") + np.quantile(np.arange(100.), p, method="midpoint") assert_array_equal(p, p0) p0 = p0.tolist() p = p.tolist() - np.quantile(np.arange(100.), p, interpolation="midpoint") + np.quantile(np.arange(100.), p, method="midpoint") assert_array_equal(p, p0) - def test_quantile_monotonic(self): + @pytest.mark.parametrize("dtype", np.typecodes["AllInteger"]) + def test_quantile_preserve_int_type(self, dtype): + res = np.quantile(np.array([1, 2], dtype=dtype), [0.5], + method="nearest") + assert res.dtype == dtype + + @pytest.mark.parametrize("method", + ['inverted_cdf', 'averaged_inverted_cdf', 'closest_observation', + 'interpolated_inverted_cdf', 'hazen', 'weibull', 'linear', + 'median_unbiased', 'normal_unbiased', + 'nearest', 'lower', 'higher', 'midpoint']) + def test_quantile_monotonic(self, method): # GH 14685 # test that the return value of quantile is monotonic if p0 is ordered - p0 = np.arange(0, 1, 0.01) + # Also tests that the boundary values are not mishandled. + p0 = np.linspace(0, 1, 101) 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) + 8, 8, 7]) * 0.1, p0, method=method) + assert_equal(np.sort(quantile), quantile) + + # Also test one where the number of data points is clearly divisible: + quantile = np.quantile([0., 1., 2., 3.], p0, method=method) assert_equal(np.sort(quantile), quantile) @hypothesis.given( @@ -3365,6 +3454,12 @@ class TestQuantile: quantile = np.quantile(arr, p0) assert_equal(np.sort(quantile), quantile) + def test_quantile_scalar_nan(self): + a = np.array([[10., 7., 4.], [3., 2., 1.]]) + a[0][1] = np.nan + actual = np.quantile(a, 0.5) + assert np.isscalar(actual) + assert_equal(np.quantile(a, 0.5), np.nan) class TestLerp: @hypothesis.given(t0=st.floats(allow_nan=False, allow_infinity=False, @@ -3375,9 +3470,9 @@ class TestLerp: 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) + def test_linear_interpolation_formula_monotonic(self, t0, t1, a, b): + l0 = nfb._lerp(a, b, t0) + l1 = nfb._lerp(a, b, t1) if t0 == t1 or a == b: assert l0 == l1 # uninteresting elif (t0 < t1) == (a < b): @@ -3391,11 +3486,11 @@ class TestLerp: 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): + def test_linear_interpolation_formula_bounded(self, t, a, b): if a <= b: - assert a <= np.lib.function_base._lerp(a, b, t) <= b + assert a <= nfb._lerp(a, b, t) <= b else: - assert b <= np.lib.function_base._lerp(a, b, t) <= a + assert b <= nfb._lerp(a, b, t) <= a @hypothesis.given(t=st.floats(allow_nan=False, allow_infinity=False, min_value=0, max_value=1), @@ -3403,17 +3498,17 @@ class TestLerp: 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): + def test_linear_interpolation_formula_symmetric(self, t, a, b): # double subtraction is needed to remove the extra precision of t < 0.5 - left = np.lib.function_base._lerp(a, b, 1 - (1 - t)) - right = np.lib.function_base._lerp(b, a, 1 - t) + left = nfb._lerp(a, b, 1 - (1 - t)) + right = nfb._lerp(b, a, 1 - t) assert left == right - def test_lerp_0d_inputs(self): + def test_linear_interpolation_formula_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 + assert nfb._lerp(a, b, t) == 2.6 class TestMedian: |