diff options
author | Charles Harris <charlesr.harris@gmail.com> | 2017-05-06 10:51:35 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-05-06 10:51:35 -0600 |
commit | bde121f9aefd4ad15aab7a7652efc5a9ee0897d9 (patch) | |
tree | 55bff00bb3d53c62286263e5c7c4462ee280b8f5 | |
parent | c33241fa8857b7f39eae68a779567c90de80cfe9 (diff) | |
parent | 156af61c8d19024bb9a71436d645b019cf35670b (diff) | |
download | python-numpy-bde121f9aefd4ad15aab7a7652efc5a9ee0897d9.tar.gz python-numpy-bde121f9aefd4ad15aab7a7652efc5a9ee0897d9.tar.bz2 python-numpy-bde121f9aefd4ad15aab7a7652efc5a9ee0897d9.zip |
Merge pull request #8939 from eric-wieser/deprecate-mini
DEP: Deprecate `np.ma.MaskedArray.mini
-rw-r--r-- | doc/release/1.13.0-notes.rst | 15 | ||||
-rw-r--r-- | numpy/ma/core.py | 100 | ||||
-rw-r--r-- | numpy/ma/tests/test_core.py | 10 | ||||
-rw-r--r-- | numpy/ma/tests/test_deprecations.py | 75 | ||||
-rw-r--r-- | numpy/ma/tests/test_old_ma.py | 8 |
5 files changed, 130 insertions, 78 deletions
diff --git a/doc/release/1.13.0-notes.rst b/doc/release/1.13.0-notes.rst index 2f32ddb28..3deca6a8c 100644 --- a/doc/release/1.13.0-notes.rst +++ b/doc/release/1.13.0-notes.rst @@ -28,10 +28,17 @@ Deprecations * Use of the C-API ``NPY_CHAR`` type number deprecated since version 1.7 will now raise deprecation warnings at runtime. Extensions built with older f2py versions need to be recompiled to remove the warning. -* ``np.ma.argsort`` should be called with an explicit `axis` argument when - applied to arrays with more than 2 dimensions, as the default value of - this argument (``None``) is inconsistent with the rest of numpy (``-1``). - +* ``np.ma.argsort``, ``np.ma.minimum.reduce``, and ``np.ma.maximum.reduce`` + should be called with an explicit `axis` argument when applied to arrays with + more than 2 dimensions, as the default value of this argument (``None``) is + inconsistent with the rest of numpy (``-1``, ``0``, and ``0``, respectively). +* ``np.ma.MaskedArray.mini`` is deprecated, as it almost duplicates the + functionality of ``np.MaskedArray.min``. Exactly equivalent behaviour + can be obtained with ``np.ma.minimum.reduce``. +* The single-argument form of ``np.ma.minimum`` and ``np.ma.maximum`` is + deprecated. ``np.maximum``. ``np.ma.minimum(x)`` should now be spelt + ``np.ma.minimum.reduce(x)``, which is consistent with how this would be done + with ``np.minimum``. Build System Changes ==================== diff --git a/numpy/ma/core.py b/numpy/ma/core.py index 20cc77bc4..bccb0bce1 100644 --- a/numpy/ma/core.py +++ b/numpy/ma/core.py @@ -5621,6 +5621,14 @@ class MaskedArray(ndarray): """ Return the array minimum along the specified axis. + .. deprecated:: 1.13.0 + This function is identical to both: + + * ``self.min(keepdims=True, axis=axis).squeeze(axis=axis)`` + * ``np.ma.minimum.reduce(self, axis=axis)`` + + Typically though, ``self.min(axis=axis)`` is sufficient. + Parameters ---------- axis : int, optional @@ -5650,11 +5658,22 @@ class MaskedArray(ndarray): >>> print(x.mini(axis=1)) [0 2 4] + There is a small difference between `mini` and `min`: + + >>> x[:,1].mini(axis=0) + masked_array(data = --, + mask = True, + fill_value = 999999) + >>> x[:,1].min(axis=0) + masked """ - if axis is None: - return minimum(self) - else: - return minimum.reduce(self, axis) + + # 2016-04-13, 1.13.0, gh-8764 + warnings.warn( + "`mini` is deprecated; use the `min` method or " + "`np.ma.minimum.reduce instead.", + DeprecationWarning, stacklevel=2) + return minimum.reduce(self, axis) def max(self, axis=None, out=None, fill_value=None, keepdims=np._NoValue): """ @@ -6348,31 +6367,52 @@ class _extrema_operation(object): `_minimum_operation`. """ + def __init__(self, ufunc, compare, fill_value): + self.ufunc = ufunc + self.compare = compare + self.fill_value_func = fill_value + self.__doc__ = ufunc.__doc__ + self.__name__ = ufunc.__name__ def __call__(self, a, b=None): "Executes the call behavior." if b is None: + # 2016-04-13, 1.13.0 + warnings.warn( + "Single-argument form of np.ma.{0} is deprecated. Use " + "np.ma.{0}.reduce instead.".format(self.__name__), + DeprecationWarning, stacklevel=2) return self.reduce(a) return where(self.compare(a, b), a, b) - def reduce(self, target, axis=None): + def reduce(self, target, axis=np._NoValue): "Reduce target along the given axis." target = narray(target, copy=False, subok=True) m = getmask(target) - if axis is not None: - kargs = {'axis': axis} + + if axis is np._NoValue and target.ndim > 1: + # 2017-05-06, Numpy 1.13.0: warn on axis default + warnings.warn( + "In the future the default for ma.{0}.reduce will be axis=0, " + "not the current None, to match np.{0}.reduce. " + "Explicitly pass 0 or None to silence this warning.".format( + self.__name__ + ), + MaskedArrayFutureWarning, stacklevel=2) + axis = None + + if axis is not np._NoValue: + kwargs = dict(axis=axis) else: - kargs = {} - target = target.ravel() - if not (m is nomask): - m = m.ravel() + kwargs = dict() + if m is nomask: - t = self.ufunc.reduce(target, **kargs) + t = self.ufunc.reduce(target, **kwargs) else: target = target.filled( self.fill_value_func(target)).view(type(target)) - t = self.ufunc.reduce(target, **kargs) - m = umath.logical_and.reduce(m, **kargs) + t = self.ufunc.reduce(target, **kwargs) + m = umath.logical_and.reduce(m, **kwargs) if hasattr(t, '_mask'): t._mask = m elif m: @@ -6395,34 +6435,6 @@ class _extrema_operation(object): result._mask = m return result - -class _minimum_operation(_extrema_operation): - - "Object to calculate minima" - - def __init__(self): - """minimum(a, b) or minimum(a) -In one argument case, returns the scalar minimum. - """ - self.ufunc = umath.minimum - self.afunc = amin - self.compare = less - self.fill_value_func = minimum_fill_value - - -class _maximum_operation(_extrema_operation): - - "Object to calculate maxima" - - def __init__(self): - """maximum(a, b) or maximum(a) - In one argument case returns the scalar maximum. - """ - self.ufunc = umath.maximum - self.afunc = amax - self.compare = greater - self.fill_value_func = maximum_fill_value - def min(obj, axis=None, out=None, fill_value=None, keepdims=np._NoValue): kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims} @@ -6518,9 +6530,9 @@ copy = _frommethod('copy') diagonal = _frommethod('diagonal') harden_mask = _frommethod('harden_mask') ids = _frommethod('ids') -maximum = _maximum_operation() +maximum = _extrema_operation(umath.maximum, greater, maximum_fill_value) mean = _frommethod('mean') -minimum = _minimum_operation() +minimum = _extrema_operation(umath.minimum, less, minimum_fill_value) nonzero = _frommethod('nonzero') prod = _frommethod('prod') product = _frommethod('prod') diff --git a/numpy/ma/tests/test_core.py b/numpy/ma/tests/test_core.py index f807fc8ae..e72088692 100644 --- a/numpy/ma/tests/test_core.py +++ b/numpy/ma/tests/test_core.py @@ -1049,8 +1049,8 @@ class TestMaskedArrayArithmetic(TestCase): xr = np.ravel(x) xmr = ravel(xm) # following are true because of careful selection of data - assert_equal(max(xr), maximum(xmr)) - assert_equal(min(xr), minimum(xmr)) + assert_equal(max(xr), maximum.reduce(xmr)) + assert_equal(min(xr), minimum.reduce(xmr)) assert_equal(minimum([1, 2, 3], [4, 0, 9]), [1, 0, 3]) assert_equal(maximum([1, 2, 3], [4, 0, 9]), [4, 2, 9]) @@ -1060,12 +1060,12 @@ class TestMaskedArrayArithmetic(TestCase): y[0] = masked assert_equal(minimum(x, y), where(less(x, y), x, y)) assert_equal(maximum(x, y), where(greater(x, y), x, y)) - assert_(minimum(x) == 0) - assert_(maximum(x) == 4) + assert_(minimum.reduce(x) == 0) + assert_(maximum.reduce(x) == 4) x = arange(4).reshape(2, 2) x[-1, -1] = masked - assert_equal(maximum(x), 2) + assert_equal(maximum.reduce(x, axis=None), 2) def test_minimummaximum_func(self): a = np.ones((2, 2)) diff --git a/numpy/ma/tests/test_deprecations.py b/numpy/ma/tests/test_deprecations.py index d66980031..8eea42fae 100644 --- a/numpy/ma/tests/test_deprecations.py +++ b/numpy/ma/tests/test_deprecations.py @@ -6,35 +6,68 @@ from __future__ import division, absolute_import, print_function import numpy as np from numpy.testing import TestCase, run_module_suite, assert_warns from numpy.ma.testutils import assert_equal - +from numpy.ma.core import MaskedArrayFutureWarning class TestArgsort(TestCase): - """ gh-8701 """ - def _test_base(self, argsort, cls): - arr_0d = np.array(1).view(cls) - argsort(arr_0d) + """ gh-8701 """ + def _test_base(self, argsort, cls): + arr_0d = np.array(1).view(cls) + argsort(arr_0d) + + arr_1d = np.array([1, 2, 3]).view(cls) + argsort(arr_1d) + + # argsort has a bad default for >1d arrays + arr_2d = np.array([[1, 2], [3, 4]]).view(cls) + result = assert_warns( + np.ma.core.MaskedArrayFutureWarning, argsort, arr_2d) + assert_equal(result, argsort(arr_2d, axis=None)) + + # should be no warnings for explictly specifiying it + argsort(arr_2d, axis=None) + argsort(arr_2d, axis=-1) + + def test_function_ndarray(self): + return self._test_base(np.ma.argsort, np.ndarray) + + def test_function_maskedarray(self): + return self._test_base(np.ma.argsort, np.ma.MaskedArray) + + def test_method(self): + return self._test_base(np.ma.MaskedArray.argsort, np.ma.MaskedArray) + + +class TestMinimumMaximum(TestCase): + def test_minimum(self): + assert_warns(DeprecationWarning, np.ma.minimum, np.ma.array([1, 2])) + + def test_maximum(self): + assert_warns(DeprecationWarning, np.ma.maximum, np.ma.array([1, 2])) + + def test_axis_default(self): + # NumPy 1.13, 2017-05-06 - arr_1d = np.array([1, 2, 3]).view(cls) - argsort(arr_1d) + data1d = np.ma.arange(6) + data2d = data1d.reshape(2, 3) - # argsort has a bad default for >1d arrays - arr_2d = np.array([[1, 2], [3, 4]]).view(cls) - result = assert_warns( - np.ma.core.MaskedArrayFutureWarning, argsort, arr_2d) - assert_equal(result, argsort(arr_2d, axis=None)) + ma_min = np.ma.minimum.reduce + ma_max = np.ma.maximum.reduce - # should be no warnings for explictly specifiying it - argsort(arr_2d, axis=None) - argsort(arr_2d, axis=-1) + # check that the default axis is still None, but warns on 2d arrays + result = assert_warns(MaskedArrayFutureWarning, ma_max, data2d) + assert_equal(result, ma_max(data2d, axis=None)) - def test_function_ndarray(self): - return self._test_base(np.ma.argsort, np.ndarray) + result = assert_warns(MaskedArrayFutureWarning, ma_min, data2d) + assert_equal(result, ma_min(data2d, axis=None)) - def test_function_maskedarray(self): - return self._test_base(np.ma.argsort, np.ma.MaskedArray) + # no warnings on 1d, as both new and old defaults are equivalent + result = ma_min(data1d) + assert_equal(result, ma_min(data1d, axis=None)) + assert_equal(result, ma_min(data1d, axis=0)) - def test_method(self): - return self._test_base(np.ma.MaskedArray.argsort, np.ma.MaskedArray) + result = ma_max(data1d) + assert_equal(result, ma_max(data1d, axis=None)) + assert_equal(result, ma_max(data1d, axis=0)) if __name__ == "__main__": diff --git a/numpy/ma/tests/test_old_ma.py b/numpy/ma/tests/test_old_ma.py index 2ea53683d..51fa6ac36 100644 --- a/numpy/ma/tests/test_old_ma.py +++ b/numpy/ma/tests/test_old_ma.py @@ -182,8 +182,8 @@ class TestMa(TestCase): xmr = ravel(xm) # true because of careful selection of data - self.assertTrue(eq(max(xr), maximum(xmr))) - self.assertTrue(eq(min(xr), minimum(xmr))) + self.assertTrue(eq(max(xr), maximum.reduce(xmr))) + self.assertTrue(eq(min(xr), minimum.reduce(xmr))) def test_testAddSumProd(self): # Test add, sum, product. @@ -444,8 +444,8 @@ class TestMa(TestCase): y[0] = masked assert_(eq(minimum(x, y), where(less(x, y), x, y))) assert_(eq(maximum(x, y), where(greater(x, y), x, y))) - assert_(minimum(x) == 0) - assert_(maximum(x) == 4) + assert_(minimum.reduce(x) == 0) + assert_(maximum.reduce(x) == 4) def test_testTakeTransposeInnerOuter(self): # Test of take, transpose, inner, outer products |