Skip to content

Commit d6a0a2f

Browse files
Oliver Hofkensproost
Oliver Hofkens
authored andcommitted
BUG: min/max on empty categorical fails (pandas-dev#30227)
1 parent f32fb91 commit d6a0a2f

File tree

3 files changed

+48
-7
lines changed

3 files changed

+48
-7
lines changed

doc/source/whatsnew/v1.0.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,7 @@ Categorical
681681
same type as if one used the :meth:`.str.` / :meth:`.dt.` on a :class:`Series` of that type. E.g. when accessing :meth:`Series.dt.tz_localize` on a
682682
:class:`Categorical` with duplicate entries, the accessor was skipping duplicates (:issue:`27952`)
683683
- Bug in :meth:`DataFrame.replace` and :meth:`Series.replace` that would give incorrect results on categorical data (:issue:`26988`)
684+
- Bug where calling :meth:`Categorical.min` or :meth:`Categorical.max` on an empty Categorical would raise a numpy exception (:issue:`30227`)
684685

685686

686687
Datetimelike

pandas/core/arrays/categorical.py

+16
Original file line numberDiff line numberDiff line change
@@ -2115,6 +2115,10 @@ def min(self, skipna=True):
21152115
21162116
Only ordered `Categoricals` have a minimum!
21172117
2118+
.. versionchanged:: 1.0.0
2119+
2120+
Returns an NA value on empty arrays
2121+
21182122
Raises
21192123
------
21202124
TypeError
@@ -2125,6 +2129,10 @@ def min(self, skipna=True):
21252129
min : the minimum of this `Categorical`
21262130
"""
21272131
self.check_for_ordered("min")
2132+
2133+
if not len(self._codes):
2134+
return self.dtype.na_value
2135+
21282136
good = self._codes != -1
21292137
if not good.all():
21302138
if skipna:
@@ -2142,6 +2150,10 @@ def max(self, skipna=True):
21422150
21432151
Only ordered `Categoricals` have a maximum!
21442152
2153+
.. versionchanged:: 1.0.0
2154+
2155+
Returns an NA value on empty arrays
2156+
21452157
Raises
21462158
------
21472159
TypeError
@@ -2152,6 +2164,10 @@ def max(self, skipna=True):
21522164
max : the maximum of this `Categorical`
21532165
"""
21542166
self.check_for_ordered("max")
2167+
2168+
if not len(self._codes):
2169+
return self.dtype.na_value
2170+
21552171
good = self._codes != -1
21562172
if not good.all():
21572173
if skipna:

pandas/tests/arrays/categorical/test_analytics.py

+31-7
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,23 @@
55

66
from pandas.compat import PYPY
77

8-
from pandas import Categorical, Index, Series
8+
from pandas import Categorical, Index, NaT, Series, date_range
99
from pandas.api.types import is_scalar
1010
import pandas.util.testing as tm
1111

1212

1313
class TestCategoricalAnalytics:
14-
def test_min_max(self):
15-
14+
@pytest.mark.parametrize("aggregation", ["min", "max"])
15+
def test_min_max_not_ordered_raises(self, aggregation):
1616
# unordered cats have no min/max
1717
cat = Categorical(["a", "b", "c", "d"], ordered=False)
1818
msg = "Categorical is not ordered for operation {}"
19-
with pytest.raises(TypeError, match=msg.format("min")):
20-
cat.min()
21-
with pytest.raises(TypeError, match=msg.format("max")):
22-
cat.max()
19+
agg_func = getattr(cat, aggregation)
20+
21+
with pytest.raises(TypeError, match=msg.format(aggregation)):
22+
agg_func()
2323

24+
def test_min_max_ordered(self):
2425
cat = Categorical(["a", "b", "c", "d"], ordered=True)
2526
_min = cat.min()
2627
_max = cat.max()
@@ -35,6 +36,29 @@ def test_min_max(self):
3536
assert _min == "d"
3637
assert _max == "a"
3738

39+
@pytest.mark.parametrize(
40+
"categories,expected",
41+
[
42+
(list("ABC"), np.NaN),
43+
([1, 2, 3], np.NaN),
44+
pytest.param(
45+
Series(date_range("2020-01-01", periods=3), dtype="category"),
46+
NaT,
47+
marks=pytest.mark.xfail(
48+
reason="https://github.com/pandas-dev/pandas/issues/29962"
49+
),
50+
),
51+
],
52+
)
53+
@pytest.mark.parametrize("aggregation", ["min", "max"])
54+
def test_min_max_ordered_empty(self, categories, expected, aggregation):
55+
# GH 30227
56+
cat = Categorical([], categories=list("ABC"), ordered=True)
57+
58+
agg_func = getattr(cat, aggregation)
59+
result = agg_func()
60+
assert result is expected
61+
3862
@pytest.mark.parametrize("skipna", [True, False])
3963
def test_min_max_with_nan(self, skipna):
4064
# GH 25303

0 commit comments

Comments
 (0)