Skip to content

Commit

Permalink
REF: Make CategoricalIndex comparison defer to Categorical comparison (
Browse files Browse the repository at this point in the history
  • Loading branch information
jbrockmendel authored and jreback committed Aug 13, 2019
1 parent 6572497 commit 3e4b196
Show file tree
Hide file tree
Showing 5 changed files with 24 additions and 25 deletions.
3 changes: 3 additions & 0 deletions pandas/core/arrays/categorical.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ def f(self, other):
return NotImplemented

other = lib.item_from_zerodim(other)
if is_list_like(other) and len(other) != len(self):
# TODO: Could this fail if the categories are listlike objects?
raise ValueError("Lengths must match.")

if not self.ordered:
if opname in ["__lt__", "__gt__", "__le__", "__ge__"]:
Expand Down
8 changes: 6 additions & 2 deletions pandas/core/indexes/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
)
from pandas.core.dtypes.concat import concat_compat
from pandas.core.dtypes.generic import (
ABCCategorical,
ABCDataFrame,
ABCDateOffset,
ABCDatetimeArray,
Expand Down Expand Up @@ -99,11 +100,14 @@

def _make_comparison_op(op, cls):
def cmp_method(self, other):
if isinstance(other, (np.ndarray, Index, ABCSeries)):
if isinstance(other, (np.ndarray, Index, ABCSeries, ExtensionArray)):
if other.ndim > 0 and len(self) != len(other):
raise ValueError("Lengths must match to compare")

if is_object_dtype(self) and not isinstance(self, ABCMultiIndex):
if is_object_dtype(self) and isinstance(other, ABCCategorical):
left = type(other)(self._values, dtype=other.dtype)
return op(left, other)
elif is_object_dtype(self) and not isinstance(self, ABCMultiIndex):
# don't pass MultiIndex
with np.errstate(all="ignore"):
result = ops._comp_method_OBJECT_ARRAY(op, self.values, other)
Expand Down
25 changes: 3 additions & 22 deletions pandas/core/indexes/category.py
Original file line number Diff line number Diff line change
Expand Up @@ -899,31 +899,12 @@ def _make_compare(op):
opname = "__{op}__".format(op=op.__name__)

def _evaluate_compare(self, other):

# if we have a Categorical type, then must have the same
# categories
if isinstance(other, CategoricalIndex):
other = other._values
elif isinstance(other, Index):
other = self._create_categorical(other._values, dtype=self.dtype)

if isinstance(other, (ABCCategorical, np.ndarray, ABCSeries)):
if len(self.values) != len(other):
raise ValueError("Lengths must match to compare")

if isinstance(other, ABCCategorical):
if not self.values.is_dtype_equal(other):
raise TypeError(
"categorical index comparisons must "
"have the same categories and ordered "
"attributes"
)

result = op(self.values, other)
with np.errstate(all="ignore"):
result = op(self.array, other)
if isinstance(result, ABCSeries):
# Dispatch to pd.Categorical returned NotImplemented
# and we got a Series back; down-cast to ndarray
result = result.values
result = result._values
return result

return compat.set_function_name(_evaluate_compare, opname, cls)
Expand Down
8 changes: 7 additions & 1 deletion pandas/core/ops/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -832,8 +832,14 @@ def wrapper(self, other, axis=None):
# Defer to DataFrame implementation; fail early
return NotImplemented

elif isinstance(other, ABCSeries) and not self._indexed_same(other):
if isinstance(other, ABCSeries) and not self._indexed_same(other):
raise ValueError("Can only compare identically-labeled Series objects")
elif (
is_list_like(other)
and len(other) != len(self)
and not isinstance(other, (set, frozenset))
):
raise ValueError("Lengths must match")

elif (
is_list_like(other)
Expand Down
5 changes: 5 additions & 0 deletions pandas/tests/indexes/test_category.py
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,11 @@ def test_equals_categorical(self):
msg = (
"categorical index comparisons must have the same categories"
" and ordered attributes"
"|"
"Categoricals can only be compared if 'categories' are the same. "
"Categories are different lengths"
"|"
"Categoricals can only be compared if 'ordered' is the same"
)
with pytest.raises(TypeError, match=msg):
ci1 == ci2
Expand Down

0 comments on commit 3e4b196

Please sign in to comment.