Маркировка гистограммы, созданной из сгруппированного фрейма данных Pandas, где есть категория NaN - PullRequest
0 голосов
/ 25 сентября 2018

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

ValueError: невозможно преобразовать плавающий NaN в целое число

Я знаю, что это потому, что тамтолько одно значение (вместо двух) для одной из сгруппированных категорий.Как мне заставить его пометить его как «0»?

Я спустился по кроличьей норе на это целый день и ничего не нашел.Вот что я пробовал (разными способами):

  • Вставка строки в сгруппированный фрейм данных.
  • Использование pd.fillna().
  • Создание функции для применения в предложении маркировки.

Я работаю с большим количеством данных, которые часто сталкиваются с такой проблемойтак что я был бы очень признателен за помощь в решении этой проблемы.Кажется, все так просто.Что мне не хватает?Спасибо!

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# my initial data set 
d = {'year' : [2014,2014,2014,2015,2015,],
     'status' : ["n","y","n","n","n"],
     'num' : [1,1,1,1,1]}
df = pd.DataFrame(d)

# groupby to create another dataframe
df2 = (df["status"]
    .groupby(df["year"])
    .value_counts(normalize=True)
    .rename("Percent")
    .apply(lambda x: x*100)
    .reset_index())

# create my bar plot
f = plt.figure(figsize = (11,8.5))

ax1 = plt.subplot(2,2,1)
sns.barplot(x="year",
           y="Percent",
           hue="status",
           hue_order = ["n","y"],
           data=df2,
           ci = None)

# label the bars
for p in ax1.patches:
    ax1.text(p.get_x() + p.get_width()/2., p.get_height(), '%d%%' % round(p.get_height()), 
        fontsize=10, color='red', ha='center', va='bottom')

plt.show()

Ответы [ 2 ]

0 голосов
/ 25 сентября 2018

При работе с данными, где у вас отсутствуют категории, распространенным приемом, который можно использовать, является укладка и разбор данных.Общую идею можно посмотреть в этом ответе .Как только данные отформатированы, вы можете fillna со своим значением заполнения (в данном случае 0) и оставить свой код как есть.

Все, что вам нужно сделать, это заменить текущее создание df2 приведенным ниже кодом.


df2 = (df.groupby('year').status.value_counts(normalize=True).mul(100)
          .unstack().stack(dropna=False).fillna(0)
          .rename('Percent').reset_index())

Что дает нам:

   year status     Percent
0  2014      n   66.666667
1  2014      y   33.333333
2  2015      n  100.000000
3  2015      y    0.000000

Теперь, без каких-либо изменений в вашем коде печати, я получаю этот вывод:

enter image description here

0 голосов
/ 25 сентября 2018

Вы можете обработать случай пустого бара, установив высоту в ноль, если p.get_height() возвращает NaN:

for p in ax1.patches:
    height = p.get_height()
    if np.isnan(height):
        height = 0
    ax1.text(p.get_x() + p.get_width()/2., height, '%d%%' % round(height), 
        fontsize=10, color='red', ha='center', va='bottom')

дает мне

example showing 0%

Кроме того, вы можете расширить свой фрейм, чтобы убедиться, что там есть ноль:

non_data_cols = df2.columns.drop("Percent")
full_index = pd.MultiIndex.from_product([df[col].unique() for col in non_data_cols], names=non_data_cols)
df2 = df2.set_index(non_data_cols.tolist()).reindex(full_index).fillna(0).reset_index()

, который расширяется, чтобы дать мне

In [74]: df2
Out[74]: 
   year status     Percent
0  2014      n   66.666667
1  2014      y   33.333333
2  2015      n  100.000000
3  2015      y    0.000000
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...