8000 DEP: deprecate calling ma.argsort without an axis · eric-wieser/numpy@0a8ee4c · GitHub
[go: up one dir, main page]

Skip to content

Commit 0a8ee4c

Browse files
committed
DEP: deprecate calling ma.argsort without an axis
Only deprecated when this would be ambiguous. Approaches numpy#8701
1 parent b7d3097 commit 0a8ee4c

File tree

3 files changed

+90
-4
lines changed

3 files changed

+90
-4
lines changed

doc/release/1.13.0-notes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ Deprecations
2828
* Use of the C-API ``NPY_CHAR`` type number deprecated since version 1.7 will
2929
now raise deprecation warnings at runtime. Extensions built with older f2py
3030
versions need to be recompiled to remove the warning.
31+
* ``np.ma.argsort`` should be called with an explicit `axis` argument when
32+
applied to arrays with more than 2 dimensions, as the default value of
33+
this argument (``None``) is inconsistent with the rest of numpy (``-1``).
3134

3235

3336
Build System Changes

numpy/ma/core.py

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,33 @@
9393
class MaskedArrayFutureWarning(FutureWarning):
9494
pass
9595

96+
def _deprecate_argsort_axis(arr):
97+
"""
98+
Adjust the axis passed to argsort, warning if necessary
99+
100+
Parameters
101+
----------
102+
arr
103+
The array which argsort was called on
104+
105+
np.ma.argsort has a long-term bug where the default of the axis argument
106+
is wrong (gh-8701), which now must be kept for backwards compatibiity.
107+
Thankfully, this only makes a difference when arrays are 2- or more-
108+
dimensional, so we only need a warning then.
109+
"""
110+
if arr.ndim <= 1:
111+
# no warning needed - but switch to -1 anyway, to avoid surprising
112+
# subclasses, which are more likely to implement scalar axes.
113+
return -1
114+
else:
115+
# 2017-04-11, Numpy 1.13.0, gh-8701: warn on axis default
116+
warnings.warn(
117+
"In the future the default for argsort will be axis=-1, not the "
118+
"current None, to match its documentation and np.argsort. "
119+
"Explicitly pass -1 or None to silence this warning.",
120+
MaskedArrayFutureWarning, stacklevel=3)
121+
return None
122+
96123

97124
def doc_note(initialdoc, note):
98125
"""
@@ -5285,7 +5312,7 @@ def round(self, decimals=0, out=None):
52855312
out.__setmask__(self._mask)
52865313
return out
52875314

5288-
def argsort(self, axis=None, kind='quicksort', order=None,
5315+
def argsort(self, axis=np._NoValue, kind='quicksort', order=None,
52895316
endwith=True, fill_value=None):
52905317
"""
52915318
Return an ndarray of indices that sort the array along the
@@ -5295,8 +5322,15 @@ def argsort(self, axis=None, kind='quicksort', order=None,
52955322
Parameters
52965323
----------
52975324
axis : int, optional
5298-
Axis along which to sort. The default is -1 (last axis).
5299-
If None, the flattened array is used.
5325+
Axis along which to sort. If None, the default, the flattened array
5326+
is used.
5327+
5328+
.. versionchanged:: 1.13.0
5329+
Previously, the default was documented to be -1, but that was
5330+
in error. At some future date, the default will change to -1, as
5331+
originally intended.
5332+
Until then, the axis should be given explicitly when
5333+
``arr.ndim > 1``, to avoid a FutureWarning.
53005334
kind : {'quicksort', 'mergesort', 'heapsort'}, optional
53015335
Sorting algorithm.
53025336
order : list, optional
@@ -5341,6 +5375,10 @@ def argsort(self, axis=None, kind='quicksort', order=None,
53415375
53425376
"""
53435377

5378+
# 2017-04-11, Numpy 1.13.0, gh-8701: warn on axis default
5379+
if axis is np._NoValue:
5380+
axis = _deprecate_argsort_axis(self)
5381+
53445382
if fill_value is None:
53455383
if endwith:
53465384
# nan > inf
@@ -6560,10 +6598,14 @@ def power(a, b, third=None):
65606598
argmin = _frommethod('argmin')
65616599
argmax = _frommethod('argmax')
65626600

6563-
def argsort(a, axis=None, kind='quicksort', order=None, endwith=True, fill_value=None):
6601+
def argsort(a, axis=np._NoValue, kind='quicksort', order=None, endwith=True, fill_value=None):
65646602
"Function version of the eponymous method."
65656603
a = np.asanyarray(a)
65666604

6605+
# 2017-04-11, Numpy 1.13.0, gh-8701: warn on axis default
6606+
if axis is np._NoValue:
6607+
axis = _deprecate_argsort_axis(a)
6608+
65676609
if isinstance(a, MaskedArray):
65686610
return a.argsort(axis=axis, kind=kind, order=order,
65696611
endwith=endwith, fill_value=fill_value)

numpy/ma/tests/test_deprecations.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
"""Test deprecation and future warnings.
2+
3+
"""
4+
from __future__ import division, absolute_import, print_function
5+
6+
import numpy as np
7+
from numpy.testing import TestCase, run_module_suite, assert_warns
8+
from numpy.ma.testutils import assert_equal
9+
10+
11+
class TestArgsort(TestCase):
12+
""" gh-8701 """
13+
def _test_base(self, argsort, cls):
14+
arr_0d = np.array(1).view(cls)
15+
argsort(arr_0d)
16+
17+
arr_1d = np.array([1, 2, 3]).view(cls)
18+
argsort(arr_1d)
19+
20+
# argsort has a bad default for >1d arrays
21+
arr_2d = np.array([[1, 2], [3, 4]]).view(cls)
22+
result = assert_warns(
23+
np.ma.core.MaskedArrayFutureWarning, argsort, arr_2d)
24+
assert_equal(result, argsort(arr_2d, axis=None))
25+
26+
# should be no warnings for explictly specifiying it
27+
argsort(arr_2d, axis=None)
28+
argsort(arr_2d, axis=-1)
29+
30+
def test_function_ndarray(self):
31+
return self._test_base(np.ma.argsort, np.ndarray)
32+
33+
def test_function_maskedarray(self):
34+
return self._test_base(np.ma.argsort, np.ma.MaskedArray)
35+
36+
def test_method(self):
37+
return self._test_base(np.ma.MaskedArray.argsort, np.ma.MaskedArray)
38+
39+
40+
if __name__ == "__main__":
41+
run_module_suite()

0 commit comments

Comments
 (0)
0