pandas-dev/pandas · error · TypeError
Unordered Categoricals can only compare equality or not
Error message
Unordered Categoricals can only compare equality or not
What it means
Raised when an ordering comparison (__lt__, __gt__, __le__, __ge__) is attempted on a Categorical that was created without `ordered=True`. Unordered categoricals represent nominal data with no defined rank, so pandas forbids greater/less-than semantics; only equality (__eq__/__ne__) is meaningful.
Source
Thrown at pandas/core/arrays/categorical.py:141
Index,
Series,
)
def _cat_compare_op(op):
opname = f"__{op.__name__}__"
fill_value = op is operator.ne
@unpack_zerodim_and_defer(opname)
def func(self, other):
hashable = is_hashable(other)
if is_list_like(other) and len(other) != len(self) and not hashable:
# in hashable case we may have a tuple that is itself a category
raise ValueError("Lengths must match.")
if not self.ordered:
if opname in ["__lt__", "__gt__", "__le__", "__ge__"]:
raise TypeError(
"Unordered Categoricals can only compare equality or not"
)
if isinstance(other, Categorical):
# Two Categoricals can only be compared if the categories are
# the same (maybe up to ordering, depending on ordered)
msg = "Categoricals can only be compared if 'categories' are the same."
if not self._categories_match_up_to_permutation(other):
raise TypeError(msg)
if not self.ordered and not self.categories.equals(other.categories):
# both unordered and different order
other_codes = recode_for_categories(
other.codes, other.categories, self.categories, copy=False
)
else:
other_codes = other._codes
View on GitHub (pinned to 71959b8cb9)
Solutions
- Recreate the categorical as ordered: `cat = pd.Categorical(cat, categories=[...], ordered=True)` or `cat.cat.as_ordered()`.
- If you only need equality semantics, switch to `==`/`!=` or `.isin([...]).`
- For a DataFrame column: `df['col'] = df['col'].cat.set_categories(['low','med','high'], ordered=True)`.
Example fix
# before cat = pd.Categorical(['low', 'high', 'med']) cat < 'high' # after cat = pd.Categorical(['low', 'high', 'med'], categories=['low','med','high'], ordered=True) cat < 'high'
Defensive patterns
Strategy: validation
Validate before calling
def require_ordered(cat, opname):
if not getattr(cat, 'ordered', False) and opname in ('__lt__','__gt__','__le__','__ge__'):
raise TypeError(f"{opname} requires an ordered Categorical")
return cat
# usage: require_ordered(cat, '__lt__'); cat < x Type guard
def is_ordered_categorical(x) -> bool:
import pandas as pd
return isinstance(getattr(x, 'dtype', None), pd.CategoricalDtype) and x.dtype.ordered Try / catch
try:
cat < threshold
except TypeError as e:
if 'Unordered Categoricals' in str(e):
cat = cat.cat.as_ordered()
result = cat < threshold
else:
raise Prevention
- Declare ordered=True at construction for ordinal label columns.
- Centralize a shared CategoricalDtype with ordered=True for repeated use.
- Audit comparisons before running; only == / != work on unordered categoricals.
When it happens
Trigger: Calling `cat < x`, `cat > x`, `cat <= x`, or `cat >= x` on a `pd.Categorical([...])` or `astype('category')` column that is unordered (the default). Sorting with a custom key that invokes `<` also triggers it.
Common situations: Treating an ordinal label column ('low','med','high') as ordered without setting ordered=True; or assuming string categories compare lexicographically once cast to 'category'.
Related errors
- Categoricals can only be compared if 'categories' are the sa
- Cannot compare a Categorical for op {opname} with type {type
- Lengths must match.
- Categorical input must be list-like
- 'values' is not ordered, please explicitly specify the categ
AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07).
Data as JSON: /api/errors/29051e60f8e19fa5.
Report an issue: GitHub.