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

Skip to content

Commit 1075c1d

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

File tree

3 files changed

+77
-2
lines changed

3 files changed

+77
-2
lines changed

doc/release/1.13.0-notes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ Dropped Support
2020
Deprecations
2121
============
2222

23+
* ``np.ma.argsort`` should be called with an explicit `axis` argument when
24+
applied to arrays with more than 2 dimensions, as the default value of
25+
this argument (``None``) is inconsistent with the rest of numpy (``-1``).
26+
2327

2428
Build System Changes
2529
====================

numpy/ma/core.py

Lines changed: 32 additions & 2 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, axis):
97+
"""
98+
Takes the array argsort was called upon, and the axis argument
99+
it was called with.
100+
101+
np.ma.argsort has a long-term bug where the default of the axis argument
102+
is wrong (gh-8701), which now must be kept for backwards compatibiity.
103+
Thankfully, this only makes a difference when arrays are 2- or more-
104+
dimensional, so we only need a warning then.
105+
"""
106+
if axis is np._NoValue:
107+
if arr.ndim <= 1:
108+
# no warning needed - switch to -1 to avoid surprising subclasses
109+
return -1
110+
else:
111+
# 2017-04-10, numpy 1.13.0
112+
warnings.warn(
113+
"Unlike np.argsort, np.sort, np.ma.sort, and the "
114+
"documentation for this function, the default is "
115+
"axis=None, not axis=-1. In future, the default will be "
116+
"-1. To squash this warning, specify the axis argument "
117+
"explicitly.",
118+
MaskedArrayFutureWarning, stacklevel=2)
119+
return None
120+
else:
121+
return axis
122+
96123

97124
def doc_note(initialdoc, note):
98125
"""
@@ -5228,7 +5255,7 @@ def round(self, decimals=0, out=None):
52285255
out.__setmask__(self._mask)
52295256
return out
52305257

5231-
def argsort(self, axis=None, kind='quicksort', order=None,
5258+
def argsort(self, axis=np._NoValue, kind='quicksort', order=None,
52325259
endwith=True, fill_value=None):
52335260
"""
52345261
Return an ndarray of indices that sort the array along the
@@ -5284,6 +5311,8 @@ def argsort(self, axis=None, kind='quicksort', order=None,
52845311
52855312
"""
52865313

5314+
axis = _deprecate_argsort_axis(self, axis)
5315+
52875316
if fill_value is None:
52885317
if endwith:
52895318
# nan > inf
@@ -6503,9 +6532,10 @@ def power(a, b, third=None):
65036532
argmin = _frommethod('argmin')
65046533
argmax = _frommethod('argmax')
65056534

6506-
def argsort(a, axis=None, kind='quicksort', order=None, endwith=True, fill_value=None):
6535+
def argsort(a, axis=np._NoValue, kind='quicksort', order=None, endwith=True, fill_value=None):
65076536
"Function version of the eponymous method."
65086537
a = np.asanyarray(a)
6538+
axis = _deprecate_argsort_axis(a, axis)
65096539

65106540
if isinstance(a, MaskedArray):
65116541
return a.argsort(axis=axis, kind=kind, order=order,

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