Объект
pandas.CategoricalIndex()
представляет собой тип индекса, который полезен для поддержки индексации дубликатов. Это контейнер вокруг элементовpandas.Categorical()
, который позволяет эффективно индексировать и хранить индекс с большим количеством повторяющихся элементов.
pandas.Categorical
- представляет собой категориальную переменную;pandas.CategoricalIndex
- контейнер вокруг элементов Categorical
;pandas.Categorical(values, categories=None, ordered=None)
:Объект pandas.Categorical()
представляет собой категориальную переменную.
Categorical
могут принимать только ограниченное и обычно фиксированное количество возможных значений (категорий). Категориальные переменные могут иметь порядок, но числовые операции (сложение, деление и т. д.) невозможны.
Все значения values
, соответствуют либо категориям categories
, либо имеют значение numpy.nan
. Присвоение значений вне категорий приведет к возникновению ошибки ValueError
. Порядок определяется порядком появления категорий, а не лексическим порядком значений.
Принимаемые значения:
values
- список/массив значений категорий. Если указан аргумент categories
, то значения values
, не входящие в последовательность categories
, будут заменены на NaN
.categories=None
- список/массив самих категорий, должны быть уникальными. Если не указан, то предполагается, что категории представляют собой уникальные значения values
(по возможности отсортированные, в противном случае в порядке их появления). ordered=None
- если True
, то результирующая Categorical
будет упорядоченный. Упорядоченная категория при сортировке учитывает порядок своего атрибута .categories
(который, в свою очередь, является аргументом categories
, если он указан).dtype=None
- экземпляр CategoricalDtype
, то его нельзя использовать вместе с аргументами categories
и ordered
.Категориальные значения могут принимать только ограниченное и обычно фиксированное количество возможных categories
. Объект Categorical
может иметь порядок, но числовые операции (сложения, деления, ...) невозможны.
Все значения values
будут соответствовать категориям categories
, либо будут иметь numpy.nan
. Присвоение значений вне категорий вызовет ValueError
. Порядок определяется порядком категорий, а не лексическим порядком значений.
pandas.Categorical()
:>>> pd.Categorical([1, 2, 3, 1, 2, 3]) # [1, 2, 3, 1, 2, 3] # Categories (3, int64): [1, 2, 3] >>> pd.Categorical(['a', 'b', 'c', 'a', 'b', 'c']) # ['a', 'b', 'c', 'a', 'b', 'c'] # Categories (3, object): ['a', 'b', 'c']
Отсутствующие значения не включаются в категорию.
>>> c = pd.Categorical([1, 2, 3, 1, 2, 3, np.nan]) >>> c # [1, 2, 3, 1, 2, 3, NaN] # Categories (3, int64): [1, 2, 3] # их наличие указано в атрибуте `codes` кодом -1. >>> c.codes # array([ 0, 1, 2, 0, 1, 2, -1], dtype=int8)
Упорядоченные объекты Categorical
могут быть отсортированы в соответствии с пользовательским порядком и могут иметь минимальное и максимальное значение.
>>> c = pd.Categorical(['a', 'b', 'c', 'a', 'b', 'c'], ordered=True, categories=['c', 'b', 'a']) >>> c # ['a', 'b', 'c', 'a', 'b', 'c'] # Categories (3, object): ['c' < 'b' < 'a'] >>> c.min() # 'c'
pandas.CategoricalIndex(data=None, categories=None, ordered=None, dtype=None, name=None)
:Объект pandas.CategoricalIndex()
представляет собой тип индекса, который полезен для поддержки индексации дубликатов. Это контейнер вокруг элементов pandas.Categorical()
, который позволяет эффективно индексировать и хранить индекс с большим количеством повторяющихся элементов.
Принимаемые значения:
data=None
- список/массив значений категорий. Если аргумент categories
указан, то значения data
, не входящие в categories
, будут заменены на NaN
.categories=None
- список/массив самих категорий, должны быть уникальными. Если не указан (а также не указан dtype
), то они будут выведены как уникальные значения data
.ordered=None
- если True
, то результирующая Categorical
будет упорядоченный. Упорядоченная категория при сортировке учитывает порядок своего атрибута .categories
(который, в свою очередь, является аргументом categories
, если он указан).dtype=None
- экземпляр CategoricalDtype
, то его нельзя использовать вместе с аргументами categories
и ordered
.name=None
- строка с именем, которое будет храниться в индексе.Объект pandas.CategoricalIndex
, как и pandas.Categorical()
, может принимать только ограниченное и обычно фиксированное количество возможных значений (категорий). Также, как и Categorical
, он может иметь порядок, но числовые операции (сложения, деления, ...) невозможны
>>> import pandas as pd >>> pd.CategoricalIndex(["a", "b", "c", "a", "b", "c"]) # CategoricalIndex(['a', 'b', 'c', 'a', 'b', 'c'], categories=['a', 'b', 'c'], # ordered=False, dtype='category') # `CategoricalIndex` может быть создан из `Categorical` >>> c = pd.Categorical(["a", "b", "c", "a", "b", "c"]) >>> pd.CategoricalIndex(c) # CategoricalIndex(['a', 'b', 'c', 'a', 'b', 'c'], categories=['a', 'b', 'c'], # ordered=False, dtype='category')
Порядок определяется порядком категорий, а не лексическим порядком значений. Упорядоченный CategoricalIndex
может иметь минимальное и максимальное значение.
ci = pd.CategoricalIndex( ["a", "b", "c", "a", "b", "c"], ordered=True, categories=["c", "b", "a"] ) >>> ci # CategoricalIndex(['a', 'b', 'c', 'a', 'b', 'c'], categories=['c', 'b', 'a'], # ordered=True, dtype='category') >>> ci.min() # 'c'
Возможные исключения:
ValueError
- Если категории не подтверждаются.TypeError
- Если задано явное значение ordered=True
, но нет категорий и значения не сортируются.pandas.CategoricalIndex
>>> import numpy as np >>> from pandas.api.types import CategoricalDtype >>> df = pd.DataFrame({"A": np.arange(6), "B": list("aabbca")}) # установим тип столбца `CategoricalDtype` >>> df["B"] = df["B"].astype(CategoricalDtype(list("cab"))) # или проще так >>> df["B"] = df["B"].astype('category') >>> df # A B # 0 0 a # 1 1 a # 2 2 b # 3 3 b # 4 4 c # 5 5 a
Установка индекса столбца с типом Categorical
создаст CategoricalIndex
.
>>> df2 = df.set_index("B") >>> df2.index # CategoricalIndex(['a', 'a', 'b', 'b', 'c', 'a'], categories=['c', 'a', 'b'], # ordered=False, dtype='category', name='B')
Индексирование с помощью .iloc
/.loc
работает аналогично Index
с дубликатами. Индексаторы должны находиться в категории, иначе операция вызовет ошибку KeyError
.
df2.loc["a"] # A # B # a 0 # a 1 # a 5
CategoricalIndex
сохраняется после индексации:
>>> df2.loc["a"].index # CategoricalIndex(['a', 'a', 'a'], categories=['c', 'a', 'b'], # ordered=False, dtype='category', name='B')
При сортировке индекс будет сортироваться по порядку следования категорий (напомним, что индекс создавался с помощью CategoricalDtype(list('cab'))
, поэтому порядок сортировки - cab
).
>>> df2.sort_index() # A # B # c 4 # a 0 # a 1 # a 5 # b 2 # b 3
Операции группировки с CategoricalIndex
также сохранят природу индекса.
>>> df2.groupby(level=0, observed=True).sum() # A # B # c 4 # a 6 # b 5 >>> df2.groupby(level=0, observed=True).sum().index # CategoricalIndex(['c', 'a', 'b'], categories=['c', 'a', 'b'], # ordered=False, dtype='category', name='B')
Операции переиндексации вернут результирующий индекс на основе типа переданного индексатора. Передача списка вернет старый добрый Index
. Индексация с помощью Categorical
вернет CategoricalIndex
, индексированный в соответствии с категориями переданного dtype: Categorical
. Это позволяет индексировать их произвольно даже со значениями, не входящими в категории, аналогично тому, как можно переиндексировать любой индекс pandas
.
df3 = pd.DataFrame( {"A": np.arange(3), "B": pd.Series(list("abc")).astype("category")} ) >>> df3 = df3.set_index("B") >>> df3 # A # B # a 0 # b 1 # c 2 # переиндексируем `df3` списком >>> df3.reindex(["a", "e"]) # A # B # a 0.0 # e NaN # смотрим тип индекса >>> df3.reindex(["a", "e"]).index # Index(['a', 'e'], dtype='object', name='B') # переиндексируем `df3` типом `Categorical` >>> df3.reindex(pd.Categorical(["a", "e"], categories=list("abe"))) # A # B # a 0.0 # e NaN # смотрим тип индекса >>> df3.reindex(pd.Categorical(["a", "e"], categories=list("abe"))).index # CategoricalIndex(['a', 'e'], categories=['a', 'b', 'e'], # ordered=False, dtype='category', name='B')
Предупреждение. Операции по изменения формы и сравнения с
CategoricalIndex
должны иметь одинаковые категории, иначе будет выданоTypeError
.>>> df4 = pd.DataFrame({"A": np.arange(2), "B": list("ba")}) >>> df4["B"] = df4["B"].astype(CategoricalDtype(list("ab"))) >>> df4 = df4.set_index("B") >>> df4.index # CategoricalIndex(['b', 'a'], categories=['a', 'b'], ordered=False, dtype='category', name='B') >>> df5 = pd.DataFrame({"A": np.arange(2), "B": list("bc")}) >>> df5["B"] = df5["B"].astype(CategoricalDtype(list("bc"))) >>> df5 = df5.set_index("B") >>> df5.index # CategoricalIndex(['b', 'c'], categories=['b', 'c'], ordered=False, dtype='category', name='B') >>> pd.concat([df4, df5]) # A # B # b 0 # a 1 # b 0 # c 1