summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharles Harris <charlesr.harris@gmail.com>2017-05-06 10:51:35 -0600
committerGitHub <noreply@github.com>2017-05-06 10:51:35 -0600
commitbde121f9aefd4ad15aab7a7652efc5a9ee0897d9 (patch)
tree55bff00bb3d53c62286263e5c7c4462ee280b8f5
parentc33241fa8857b7f39eae68a779567c90de80cfe9 (diff)
parent156af61c8d19024bb9a71436d645b019cf35670b (diff)
downloadpython-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.rst15
-rw-r--r--numpy/ma/core.py100
-rw-r--r--numpy/ma/tests/test_core.py10
-rw-r--r--numpy/ma/tests/test_deprecations.py75
-rw-r--r--numpy/ma/tests/test_old_ma.py8
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