Сохранить вывод apply как dict в pandas категориальном DataFrame - PullRequest
2 голосов
/ 24 февраля 2020

Давайте начнем с простого pandas.DataFrame. (Я на pandas 0.24.2, но я смог воспроизвести мою проблему и на версии 1.0.1)

import pandas as pd

df = pd.DataFrame({"a": [1, 2, 3], "b": [2, 4, 4]})    
print(df)
>>>    a  b
    0  1  2
    1  2  4
    2  3  4

Я хочу знать, каковы различные значения в каждом столбце моего фрейма данных и сколько там случаев, каждый столбец представлен в хорошем словаре. (Я знаю, что такое преобразование в словари не может быть лучшей практикой, но мне понадобится для иллюстрации)

df.apply(lambda x: x.value_counts().to_dict())
>>> a    {3: 1, 2: 1, 1: 1}
    b          {4: 2, 2: 1}
dtype: object

Пока все хорошо, верно? Что произойдет, если мой фрейм данных будет другого типа, скажем, категории? Я ожидал бы таких же результатов, верно?

Абсолютно нет:

df = df.astype('category') # Let's keep the same values, but now as type categorical
df.apply(lambda x: x.value_counts().to_dict())
>>>      a    b
     1  1.0  NaN
     2  1.0  1.0
     3  1.0  NaN
     4  NaN  2.0

Действительно странно, что сначала я получаю pd.Series, а затем pd.DataFrame. Любая идея о том, почему такое поведение существует, и что более важно, как предотвратить это?

РЕДАКТИРОВАТЬ: это работает, пока один столбец исходного кадра данных является категоричным. поэтому наличие df['a'] = df['a'].astype('category'] дает те же результаты, что и мой второй пример

РЕДАКТИРОВАТЬ 2: согласно комментарию @ jon-clements, я пробовал с разными аргументами для result_type, но безрезультатно

Ответы [ 3 ]

0 голосов
/ 24 февраля 2020

Я не уверен, почему это происходит. Но для решения этой проблемы достаточно просто понять список:

df = df.astype('category')
pd.Series({c:df[c].value_counts().to_dict() for c in df.columns})

Вывод:

a    {3: 1, 2: 1, 1: 1}
b          {4: 2, 2: 1}
dtype: object
0 голосов
/ 24 февраля 2020

Вы можете сделать:

df.stack().groupby(level=1).value_counts().groupby(level=0).agg(lambda x: dict(zip(x.index.get_level_values(1), x)))

Выходы (неважно, category или нет):

a    {1: 1, 2: 1, 3: 1}
b          {4: 2, 2: 1}
dtype: object
0 голосов
/ 24 февраля 2020

Конечно, я нашел идею быстрого исправления сразу после того, как закончил вводить мой вопрос: просто преобразовать в «объект» каждый столбец в кадре данных, прежде чем делать мои подсчеты

df = df.astype('object') # the df is originally categorical here
df.apply(lambda x: x.value_counts().to_dict())

Возвращает ожидаемые результаты .

Я оставлю вопрос открытым, если кто-то найдет менее хакерский ответ и, конечно, сможет объяснить, почему это поведение!

...