Skip to content

Commit 21a10d1

Browse files
more informative error message with np.min or np.max on unordered Categorical (#34053)
1 parent 1f48d3d commit 21a10d1

File tree

3 files changed

+38
-2
lines changed

3 files changed

+38
-2
lines changed

doc/source/whatsnew/v1.1.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,7 @@ Other
883883
- Bug in :meth:`DataFrame.__dir__` caused a segfault when using unicode surrogates in a column name (:issue:`25509`)
884884
- Bug in :meth:`DataFrame.plot.scatter` caused an error when plotting variable marker sizes (:issue:`32904`)
885885
- :class:`IntegerArray` now implements the ``sum`` operation (:issue:`33172`)
886+
- More informative error message with ``np.min`` or ``np.max`` on unordered :class:`Categorical` (:issue:`33115`)
886887
- Bug in :class:`Tick` comparisons raising ``TypeError`` when comparing against timedelta-like objects (:issue:`34088`)
887888

888889
.. ---------------------------------------------------------------------------

pandas/core/arrays/categorical.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
from pandas._libs import NaT, algos as libalgos, hashtable as htable
1111
from pandas._typing import ArrayLike, Dtype, Ordered, Scalar
12+
from pandas.compat.numpy import function as nv
1213
from pandas.util._decorators import cache_readonly, deprecate_kwarg, doc
1314
from pandas.util._validators import validate_bool_kwarg, validate_fillna_kwargs
1415

@@ -2077,7 +2078,7 @@ def _reduce(self, name, axis=0, **kwargs):
20772078
return func(**kwargs)
20782079

20792080
@deprecate_kwarg(old_arg_name="numeric_only", new_arg_name="skipna")
2080-
def min(self, skipna=True):
2081+
def min(self, skipna=True, **kwargs):
20812082
"""
20822083
The minimum value of the object.
20832084
@@ -2096,6 +2097,7 @@ def min(self, skipna=True):
20962097
-------
20972098
min : the minimum of this `Categorical`
20982099
"""
2100+
nv.validate_min((), kwargs)
20992101
self.check_for_ordered("min")
21002102

21012103
if not len(self._codes):
@@ -2112,7 +2114,7 @@ def min(self, skipna=True):
21122114
return self.categories[pointer]
21132115

21142116
@deprecate_kwarg(old_arg_name="numeric_only", new_arg_name="skipna")
2115-
def max(self, skipna=True):
2117+
def max(self, skipna=True, **kwargs):
21162118
"""
21172119
The maximum value of the object.
21182120
@@ -2131,6 +2133,7 @@ def max(self, skipna=True):
21312133
-------
21322134
max : the maximum of this `Categorical`
21332135
"""
2136+
nv.validate_max((), kwargs)
21342137
self.check_for_ordered("max")
21352138

21362139
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
@@ -93,6 +94,37 @@ def test_deprecate_numeric_only_min_max(self, method):
9394
with tm.assert_produces_warning(expected_warning=FutureWarning):
9495
getattr(cat, method)(numeric_only=True)
9596

97+
@pytest.mark.parametrize("method", ["min", "max"])
98+
def test_numpy_min_max_raises(self, method):
99+
cat = Categorical(["a", "b", "c", "b"], ordered=False)
100+
msg = (
101+
f"Categorical is not ordered for operation {method}\n"
102+
"you can use .as_ordered() to change the Categorical to an ordered one"
103+
)
104+
method = getattr(np, method)
105+
with pytest.raises(TypeError, match=re.escape(msg)):
106+
method(cat)
107+
108+
@pytest.mark.parametrize("kwarg", ["axis", "out", "keepdims"])
109+
@pytest.mark.parametrize("method", ["min", "max"])
110+
def test_numpy_min_max_unsupported_kwargs_raises(self, method, kwarg):
111+
cat = Categorical(["a", "b", "c", "b"], ordered=True)
112+
msg = (
113+
f"the '{kwarg}' parameter is not supported in the pandas implementation "
114+
f"of {method}"
115+
)
116+
kwargs = {kwarg: 42}
117+
method = getattr(np, method)
118+
with pytest.raises(ValueError, match=msg):
119+
method(cat, **kwargs)
120+
121+
@pytest.mark.parametrize("method, expected", [("min", "a"), ("max", "c")])
122+
def test_numpy_min_max_axis_equals_none(self, method, expected):
123+
cat = Categorical(["a", "b", "c", "b"], ordered=True)
124+
method = getattr(np, method)
125+
result = method(cat, axis=None)
126+
assert result == expected
127+
96128
@pytest.mark.parametrize(
97129
"values,categories,exp_mode",
98130
[

0 commit comments

Comments
 (0)