Skip to content

more informative error message with np.min or np.max on unordered Categorical #34053

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
May 19, 2020
1 change: 1 addition & 0 deletions doc/source/whatsnew/v1.1.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -883,6 +883,7 @@ Other
- Bug in :meth:`DataFrame.__dir__` caused a segfault when using unicode surrogates in a column name (:issue:`25509`)
- Bug in :meth:`DataFrame.plot.scatter` caused an error when plotting variable marker sizes (:issue:`32904`)
- :class:`IntegerArray` now implements the ``sum`` operation (:issue:`33172`)
- More informative error message with ``np.min`` or ``np.max`` on unordered :class:`Categorical` (:issue:`33115`)
- Bug in :class:`Tick` comparisons raising ``TypeError`` when comparing against timedelta-like objects (:issue:`34088`)

.. ---------------------------------------------------------------------------
Expand Down
7 changes: 5 additions & 2 deletions pandas/core/arrays/categorical.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

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

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

@deprecate_kwarg(old_arg_name="numeric_only", new_arg_name="skipna")
def min(self, skipna=True):
def min(self, skipna=True, **kwargs):
"""
The minimum value of the object.

Expand All @@ -2096,6 +2097,7 @@ def min(self, skipna=True):
-------
min : the minimum of this `Categorical`
"""
nv.validate_min((), kwargs)
self.check_for_ordered("min")

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

@deprecate_kwarg(old_arg_name="numeric_only", new_arg_name="skipna")
def max(self, skipna=True):
def max(self, skipna=True, **kwargs):
"""
The maximum value of the object.

Expand All @@ -2131,6 +2133,7 @@ def max(self, skipna=True):
-------
max : the maximum of this `Categorical`
"""
nv.validate_max((), kwargs)
self.check_for_ordered("max")

if not len(self._codes):
Expand Down
32 changes: 32 additions & 0 deletions pandas/tests/arrays/categorical/test_analytics.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import re
import sys

import numpy as np
Expand Down Expand Up @@ -93,6 +94,37 @@ def test_deprecate_numeric_only_min_max(self, method):
with tm.assert_produces_warning(expected_warning=FutureWarning):
getattr(cat, method)(numeric_only=True)

@pytest.mark.parametrize("method", ["min", "max"])
def test_numpy_min_max_raises(self, method):
cat = Categorical(["a", "b", "c", "b"], ordered=False)
msg = (
f"Categorical is not ordered for operation {method}\n"
"you can use .as_ordered() to change the Categorical to an ordered one"
)
method = getattr(np, method)
with pytest.raises(TypeError, match=re.escape(msg)):
method(cat)

@pytest.mark.parametrize("kwarg", ["axis", "out", "keepdims"])
@pytest.mark.parametrize("method", ["min", "max"])
def test_numpy_min_max_unsupported_kwargs_raises(self, method, kwarg):
cat = Categorical(["a", "b", "c", "b"], ordered=True)
msg = (
f"the '{kwarg}' parameter is not supported in the pandas implementation "
f"of {method}"
)
kwargs = {kwarg: 42}
method = getattr(np, method)
with pytest.raises(ValueError, match=msg):
method(cat, **kwargs)

@pytest.mark.parametrize("method, expected", [("min", "a"), ("max", "c")])
def test_numpy_min_max_axis_equals_none(self, method, expected):
cat = Categorical(["a", "b", "c", "b"], ordered=True)
method = getattr(np, method)
result = method(cat, axis=None)
assert result == expected

@pytest.mark.parametrize(
"values,categories,exp_mode",
[
Expand Down