{"record":{"id":"3598517defe9c86c","repo":"pandas-dev/pandas","slug":"categoricals-can-only-be-compared-if-categories","errorCode":null,"errorMessage":"Categoricals can only be compared if 'categories' are the same.","messagePattern":"Categoricals can only be compared if 'categories' are the same\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"pandas/core/arrays/categorical.py","lineNumber":150,"sourceCode":"    @unpack_zerodim_and_defer(opname)\n    def func(self, other):\n        hashable = is_hashable(other)\n        if is_list_like(other) and len(other) != len(self) and not hashable:\n            # in hashable case we may have a tuple that is itself a category\n            raise ValueError(\"Lengths must match.\")\n\n        if not self.ordered:\n            if opname in [\"__lt__\", \"__gt__\", \"__le__\", \"__ge__\"]:\n                raise TypeError(\n                    \"Unordered Categoricals can only compare equality or not\"\n                )\n        if isinstance(other, Categorical):\n            # Two Categoricals can only be compared if the categories are\n            # the same (maybe up to ordering, depending on ordered)\n\n            msg = \"Categoricals can only be compared if 'categories' are the same.\"\n            if not self._categories_match_up_to_permutation(other):\n                raise TypeError(msg)\n\n            if not self.ordered and not self.categories.equals(other.categories):\n                # both unordered and different order\n                other_codes = recode_for_categories(\n                    other.codes, other.categories, self.categories, copy=False\n                )\n            else:\n                other_codes = other._codes\n\n            ret = op(self._codes, other_codes)\n            mask = (self._codes == -1) | (other_codes == -1)\n            if mask.any():\n                ret[mask] = fill_value\n            return ret\n\n        if hashable:\n            if other in self.categories:\n                i = self._unbox_scalar(other)","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/pandas-dev/pandas/blob/3b7651241d4da534b3559b60ef128e1c34f54116/pandas/core/arrays/categorical.py#L132-L168","documentation":"Raised when comparing two Categoricals whose category sets do not agree up to permutation (checked via `_categories_match_up_to_permutation`). Even when both are ordered, the categories must be the same set; otherwise the code-by-code comparison would be meaningless because identical codes can map to different values.","triggerScenarios":"`cat1 < cat2` where `cat1.categories` and `cat2.categories` differ in membership (not just ordering) — e.g., comparing a Categorical over `['a','b','c']` against one over `['a','b','d']`.","commonSituations":"Joining/concatenating DataFrames whose category columns were defined separately, comparing columns across versions of a dataset where categories drifted, or comparing after `add_categories`/`remove_categories` on only one side.","solutions":["Unify categories on both sides: `cat2 = cat2.set_categories(cat1.categories)` (and match `ordered`).","Use `cat1.astype(cat2.dtype)` to align dtype before comparing.","Compare underlying values directly: `np.asarray(cat1) == np.asarray(cat2)` if semantic equality on values is intended.","Re-create both Categoricals from a shared, canonical category list."],"exampleFix":"# before\nc1 = pd.Categorical(['a', 'b'], categories=['a', 'b', 'c'], ordered=True)\nc2 = pd.Categorical(['a', 'b'], categories=['a', 'b', 'd'], ordered=True)\nc1 < c2  # TypeError\n\n# after\nc2 = c2.set_categories(c1.categories)\nc1 < c2","handlingStrategy":"validation","validationCode":"def align_categories(c1, c2):\n    if not c1._categories_match_up_to_permutation(c2):\n        c2 = c2.set_categories(c1.categories)\n        if c1.ordered:\n            c2 = c2.as_ordered()\n    return c1, c2","typeGuard":"def categories_compatible(c1, c2) -> bool:\n    return c1._categories_match_up_to_permutation(c2)","tryCatchPattern":"try:\n    result = c1 < c2\nexcept TypeError as e:\n    if \"categories\" in str(e):\n        c2 = c2.set_categories(c1.categories)\n        result = c1 < c2\n    else:\n        raise","preventionTips":["Standardize category dtype in one place and reuse the dtype object across columns/DataFrames.","When concatenating DataFrames, unify category dtypes via `.astype(shared_dtype)` first.","Document the canonical category list per categorical column in your schema."],"tags":["categorical","comparison","categories","typeerror"],"backgroundTag":null,"analyzedSha":"3b7651241d4da534b3559b60ef128e1c34f54116","analyzedAt":"2026-08-11T22:10:44.015Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}