@@ -393,56 +393,6 @@ def __init__(
393393 self ._dtype = self ._dtype .update_dtype (dtype )
394394 self ._codes = coerce_indexer_dtype (codes , dtype .categories )
395395
396- @property
397- def categories (self ):
398- """
399- The categories of this categorical.
400-
401- Setting assigns new values to each category (effectively a rename of
402- each individual category).
403-
404- The assigned value has to be a list-like object. All items must be
405- unique and the number of items in the new categories must be the same
406- as the number of items in the old categories.
407-
408- Assigning to `categories` is a inplace operation!
409-
410- Raises
411- ------
412- ValueError
413- If the new categories do not validate as categories or if the
414- number of new categories is unequal the number of old categories
415-
416- See Also
417- --------
418- rename_categories : Rename categories.
419- reorder_categories : Reorder categories.
420- add_categories : Add new categories.
421- remove_categories : Remove the specified categories.
422- remove_unused_categories : Remove categories which are not used.
423- set_categories : Set the categories to the specified ones.
424- """
425- return self .dtype .categories
426-
427- @categories .setter
428- def categories (self , categories ):
429- new_dtype = CategoricalDtype (categories , ordered = self .ordered )
430- if self .dtype .categories is not None and len (self .dtype .categories ) != len (
431- new_dtype .categories
432- ):
433- raise ValueError (
434- "new categories need to have the same number of "
435- "items as the old categories!"
436- )
437- self ._dtype = new_dtype
438-
439- @property
440- def ordered (self ) -> Ordered :
441- """
442- Whether the categories have an ordered relationship.
443- """
444- return self .dtype .ordered
445-
446396 @property
447397 def dtype (self ) -> CategoricalDtype :
448398 """
@@ -458,10 +408,6 @@ def _constructor(self) -> Type["Categorical"]:
458408 def _from_sequence (cls , scalars , dtype = None , copy = False ):
459409 return Categorical (scalars , dtype = dtype )
460410
461- def _formatter (self , boxed = False ):
462- # Defer to CategoricalFormatter's formatter.
463- return None
464-
465411 def astype (self , dtype : Dtype , copy : bool = True ) -> ArrayLike :
466412 """
467413 Coerce this type to another dtype
@@ -640,6 +586,59 @@ def from_codes(cls, codes, categories=None, ordered=None, dtype=None):
640586
641587 return cls (codes , dtype = dtype , fastpath = True )
642588
589+ # ------------------------------------------------------------------
590+ # Categories/Codes/Ordered
591+
592+ @property
593+ def categories (self ):
594+ """
595+ The categories of this categorical.
596+
597+ Setting assigns new values to each category (effectively a rename of
598+ each individual category).
599+
600+ The assigned value has to be a list-like object. All items must be
601+ unique and the number of items in the new categories must be the same
602+ as the number of items in the old categories.
603+
604+ Assigning to `categories` is a inplace operation!
605+
606+ Raises
607+ ------
608+ ValueError
609+ If the new categories do not validate as categories or if the
610+ number of new categories is unequal the number of old categories
611+
612+ See Also
613+ --------
614+ rename_categories : Rename categories.
615+ reorder_categories : Reorder categories.
616+ add_categories : Add new categories.
617+ remove_categories : Remove the specified categories.
618+ remove_unused_categories : Remove categories which are not used.
619+ set_categories : Set the categories to the specified ones.
620+ """
621+ return self .dtype .categories
622+
623+ @categories .setter
624+ def categories (self , categories ):
625+ new_dtype = CategoricalDtype (categories , ordered = self .ordered )
626+ if self .dtype .categories is not None and len (self .dtype .categories ) != len (
627+ new_dtype .categories
628+ ):
629+ raise ValueError (
630+ "new categories need to have the same number of "
631+ "items as the old categories!"
632+ )
633+ self ._dtype = new_dtype
634+
635+ @property
636+ def ordered (self ) -> Ordered :
637+ """
638+ Whether the categories have an ordered relationship.
639+ """
640+ return self .dtype .ordered
641+
643642 @property
644643 def codes (self ) -> np .ndarray :
645644 """
@@ -1104,6 +1103,8 @@ def remove_unused_categories(self, inplace=False):
11041103 if not inplace :
11051104 return cat
11061105
1106+ # ------------------------------------------------------------------
1107+
11071108 def map (self , mapper ):
11081109 """
11091110 Map categories using input correspondence (dict, Series, or function).
@@ -1192,6 +1193,9 @@ def map(self, mapper):
11921193 __le__ = _cat_compare_op (operator .le )
11931194 __ge__ = _cat_compare_op (operator .ge )
11941195
1196+ # -------------------------------------------------------------
1197+ # Validators; ideally these can be de-duplicated
1198+
11951199 def _validate_insert_value (self , value ) -> int :
11961200 code = self .categories .get_indexer ([value ])
11971201 if (code == - 1 ) and not (is_scalar (value ) and isna (value )):
@@ -1241,6 +1245,8 @@ def _validate_fill_value(self, fill_value):
12411245 )
12421246 return fill_value
12431247
1248+ # -------------------------------------------------------------
1249+
12441250 def __array__ (self , dtype = None ) -> np .ndarray :
12451251 """
12461252 The numpy array interface.
@@ -1758,6 +1764,10 @@ def __contains__(self, key) -> bool:
17581764 # ------------------------------------------------------------------
17591765 # Rendering Methods
17601766
1767+ def _formatter (self , boxed = False ):
1768+ # Defer to CategoricalFormatter's formatter.
1769+ return None
1770+
17611771 def _tidy_repr (self , max_vals = 10 , footer = True ) -> str :
17621772 """
17631773 a short repr displaying only max_vals and an optional (but default
@@ -1987,7 +1997,9 @@ def _reverse_indexer(self) -> Dict[Hashable, np.ndarray]:
19871997 result = dict (zip (categories , _result ))
19881998 return result
19891999
1990- # reduction ops #
2000+ # ------------------------------------------------------------------
2001+ # Reductions
2002+
19912003 def _reduce (self , name : str , skipna : bool = True , ** kwargs ):
19922004 func = getattr (self , name , None )
19932005 if func is None :
@@ -2090,6 +2102,9 @@ def mode(self, dropna=True):
20902102 codes = sorted (htable .mode_int64 (ensure_int64 (codes ), dropna ))
20912103 return self ._constructor (values = codes , dtype = self .dtype , fastpath = True )
20922104
2105+ # ------------------------------------------------------------------
2106+ # ExtensionArray Interface
2107+
20932108 def unique (self ):
20942109 """
20952110 Return the ``Categorical`` which ``categories`` and ``codes`` are
@@ -2179,6 +2194,18 @@ def equals(self, other: object) -> bool:
21792194 return np .array_equal (self ._codes , other_codes )
21802195 return False
21812196
2197+ @property
2198+ def _can_hold_na (self ):
2199+ return True
2200+
2201+ @classmethod
2202+ def _concat_same_type (self , to_concat ):
2203+ from pandas .core .dtypes .concat import union_categoricals
2204+
2205+ return union_categoricals (to_concat )
2206+
2207+ # ------------------------------------------------------------------
2208+
21822209 def is_dtype_equal (self , other ):
21832210 """
21842211 Returns True if categoricals are the same dtype
@@ -2217,17 +2244,6 @@ def describe(self):
22172244
22182245 return result
22192246
2220- # Implement the ExtensionArray interface
2221- @property
2222- def _can_hold_na (self ):
2223- return True
2224-
2225- @classmethod
2226- def _concat_same_type (self , to_concat ):
2227- from pandas .core .dtypes .concat import union_categoricals
2228-
2229- return union_categoricals (to_concat )
2230-
22312247 def isin (self , values ) -> np .ndarray :
22322248 """
22332249 Check whether `values` are contained in Categorical.
0 commit comments