Skip to content

Commit bfe70aa

Browse files
Backport PR #34053 on branch 1.0.x (more informative error message with np.min or np.max on unordered Categorical) (#34246)
1 parent b3ebcb0 commit bfe70aa

File tree

4 files changed

+38
-3
lines changed

4 files changed

+38
-3
lines changed

doc/source/whatsnew/v1.0.4.rst

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Fixed regressions
2727
- Bug in :meth:`DataFrame.replace` casts columns to ``object`` dtype if items in ``to_replace`` not in values (:issue:`32988`)
2828
- Bug in :meth:`Series.groupby` would raise ``ValueError`` when grouping by :class:`PeriodIndex` level (:issue:`34010`)
2929
- Bug in :meth:`GroupBy.rolling.apply` ignores args and kwargs parameters (:issue:`33433`)
30+
- More informative error message with ``np.min`` or ``np.max`` on unordered :class:`Categorical` (:issue:`33115`)
3031
-
3132

3233
.. _whatsnew_104.bug_fixes:

pandas/compat/numpy/function.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ def validate_cum_func_with_skipna(skipna, args, kwargs, name):
209209
LOGICAL_FUNC_DEFAULTS = dict(out=None, keepdims=False)
210210
validate_logical_func = CompatValidator(LOGICAL_FUNC_DEFAULTS, method="kwargs")
211211

212-
MINMAX_DEFAULTS = dict(out=None, keepdims=False)
212+
MINMAX_DEFAULTS = dict(axis=None, out=None, keepdims=False)
213213
validate_min = CompatValidator(
214214
MINMAX_DEFAULTS, fname="min", method="both", max_fname_arg_count=1
215215
)

pandas/core/arrays/categorical.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -2125,7 +2125,7 @@ def _reduce(self, name, axis=0, **kwargs):
21252125
return func(**kwargs)
21262126

21272127
@deprecate_kwarg(old_arg_name="numeric_only", new_arg_name="skipna")
2128-
def min(self, skipna=True):
2128+
def min(self, skipna=True, **kwargs):
21292129
"""
21302130
The minimum value of the object.
21312131
@@ -2144,6 +2144,7 @@ def min(self, skipna=True):
21442144
-------
21452145
min : the minimum of this `Categorical`
21462146
"""
2147+
nv.validate_min((), kwargs)
21472148
self.check_for_ordered("min")
21482149

21492150
if not len(self._codes):
@@ -2160,7 +2161,7 @@ def min(self, skipna=True):
21602161
return self.categories[pointer]
21612162

21622163
@deprecate_kwarg(old_arg_name="numeric_only", new_arg_name="skipna")
2163-
def max(self, skipna=True):
2164+
def max(self, skipna=True, **kwargs):
21642165
"""
21652166
The maximum value of the object.
21662167
@@ -2179,6 +2180,7 @@ def max(self, skipna=True):
21792180
-------
21802181
max : the maximum of this `Categorical`
21812182
"""
2183+
nv.validate_max((), kwargs)
21822184
self.check_for_ordered("max")
21832185

21842186
if not len(self._codes):

pandas/tests/arrays/categorical/test_analytics.py

+32
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import re
12
import sys
23

34
import numpy as np
@@ -105,6 +106,37 @@ def test_deprecate_numeric_only_min_max(self, method):
105106
with tm.assert_produces_warning(expected_warning=FutureWarning):
106107
getattr(cat, method)(numeric_only=True)
107108

109+
@pytest.mark.parametrize("method", ["min", "max"])
110+
def test_numpy_min_max_raises(self, method):
111+
cat = Categorical(["a", "b", "c", "b"], ordered=False)
112+
msg = (
113+
f"Categorical is not ordered for operation {method}\n"
114+
"you can use .as_ordered() to change the Categorical to an ordered one"
115+
)
116+
method = getattr(np, method)
117+
with pytest.raises(TypeError, match=re.escape(msg)):
118+
method(cat)
119+
120+
@pytest.mark.parametrize("kwarg", ["axis", "out", "keepdims"])
121+
@pytest.mark.parametrize("method", ["min", "max"])
122+
def test_numpy_min_max_unsupported_kwargs_raises(self, method, kwarg):
123+
cat = Categorical(["a", "b", "c", "b"], ordered=True)
124+
msg = (
125+
f"the '{kwarg}' parameter is not supported in the pandas implementation "
126+
f"of {method}"
127+
)
128+
kwargs = {kwarg: 42}
129+
method = getattr(np, method)
130+
with pytest.raises(ValueError, match=msg):
131+
method(cat, **kwargs)
132+
133+
@pytest.mark.parametrize("method, expected", [("min", "a"), ("max", "c")])
134+
def test_numpy_min_max_axis_equals_none(self, method, expected):
135+
cat = Categorical(["a", "b", "c", "b"], ordered=True)
136+
method = getattr(np, method)
137+
result = method(cat, axis=None)
138+
assert result == expected
139+
108140
@pytest.mark.parametrize(
109141
"values,categories,exp_mode",
110142
[

0 commit comments

Comments
 (0)