【Python】NotImplementedError: isna is not defined for MultiIndex が出た時の対処法

【Python】NotImplementedError: isna is not defined for MultiIndex が出た時の対処法

サーバーサイドエンジニアになって2年。今更ですが機械学習を一生懸命勉強している てるてるです。

Pandas.Seriesのデータを作成し、Seaborn.barplotを使って棒グラフ表示しようとしたところ、 NotImplementedError: isna is not defined for MultiIndex というエラーが出てしまい、かなり時間を使ってしまったので備忘録として残します。

お得なお知らせ
スキルアップAI社が公開している「機械学習のためのPython入門講座」が税込み55,000円のところ、なんと期間限定で無料で公開されています!
お申し込みは2022/12/25まで、講座動画は2022/12/31までとなっています。

実際に体験してみたのですが、Pythonの基本文法から始まり 機械学習の前処理, モデルの構築, 検証まで丁寧にわかりやすく説明してあり学びやすかったです!
Youtubeでの解説動画付きなので、分からないところは動画を見ながら一緒にできるのでPython初学者でも学びやすいかと思います!

興味がある方はお早めにお申し込みください!


用意したSeriesデータ

ランダムなSeries型データを用意し、インデックスは「(女性, 0), (女性, 1), (男性, 0), (男性, 1)」というように設定しました。
0と1の値は、スポーツ経験があるかどうかのフラグとして使用している想定です。

# 使用するデータを用意 (Pandas.Series型)
import pandas as pd
import numpy as np
import seaborn as sns

data = np.random.randint(0, 500, 4)
index = pd.MultiIndex.from_tuples([('女性', 0), ('女性', 1),
                                   ('男性', 0), ('男性', 1),]) # マルチインデックス作成
series = pd.Series(data, index=index, name='data')

------------------- 実行結果(サンプル) --------------------------
女性  0    127
     1    133
男性  0    315
     1    405
Name: data, dtype: int64


エラーになったコード

用意したデータをSeabornを使用して棒グラフ表示しようとして、sns.barplot(series.index, series.values) とコードを書いたところエラーが発生しました。

# 失敗した例
sns.barplot(series.index, series.values)
# sns.barplot(series.keys(), series.values) # 別方法でindexを取得する方法もあるが、こちらも失敗


------------------- 実際に表示されたエラー文章 --------------------------
Output exceeds the size limit. Open the full output data in a text editor
---------------------------------------------------------------------------
NotImplementedError                       Traceback (most recent call last)
<ipython-input-178-59d96087e767> in <module>
      4 series = pd.Series(data, index=index, name='data')
      5 
----> 6 sns.barplot(series.index, series.values)
      7 sns.barplot(series.keys(), series.values)
      8 

/opt/anaconda3/lib/python3.8/site-packages/seaborn/_decorators.py in inner_f(*args, **kwargs)
     44             )
     45         kwargs.update({k: arg for k, arg in zip(sig.parameters, args)})
---> 46         return f(**kwargs)
     47     return inner_f
     48 

/opt/anaconda3/lib/python3.8/site-packages/seaborn/categorical.py in barplot(x, y, hue, data, order, hue_order, estimator, ci, n_boot, units, seed, orient, color, palette, saturation, errcolor, errwidth, capsize, dodge, ax, **kwargs)
   3167 ):
   3168 
-> 3169     plotter = _BarPlotter(x, y, hue, data, order, hue_order,
   3170                           estimator, ci, n_boot, units, seed,
   3171                           orient, color, palette, saturation,

/opt/anaconda3/lib/python3.8/site-packages/seaborn/categorical.py in __init__(self, x, y, hue, data, order, hue_order, estimator, ci, n_boot, units, seed, orient, color, palette, saturation, errcolor, errwidth, capsize, dodge)
   1582                  errwidth, capsize, dodge):
...
--> 153         raise NotImplementedError("isna is not defined for MultiIndex")
    154     elif isinstance(obj, type):
    155         return False

NotImplementedError: isna is not defined for MultiIndex

別のところでは成功していた書き方だったんですが、この時だけエラーが発生しました。

エラーメッセージに isna と書いてあるので「欠損値関連かな?」と思い調べたのですが、有力な情報が中々見つからず苦労しました…



解決法:to_flat_index() を使いMultiIndex型を変換する


sns.barplotに渡している引数がMultiIndexになっているので、to_flat_index関数を使い、Index型に直してあげるだけで解決できました。

sns.barplot(series.index.to_flat_index(), series.values)
# または下の書き方でもOK
sns.barplot(series.keys().to_flat_index(), series.values)


余談ですが、Series.keys() はインデックスを取得するもので、辞書型というわけではないんですよね。
なので値を取得したい場合はSeries.values と使う必要があるそうです。(valuesは非推奨とのこと)
参考1:Series.keys() – https://pandas.pydata.org/docs/reference/api/pandas.Series.keys.html
参考2:Series.values – https://pandas.pydata.org/docs/reference/api/pandas.Series.values.html



さて、上のコードを実行すると棒グラフを表示することができました。



実際に to_flat_index() をした後のindexの型を見てみると、MultiIndex型からIndex型に変換されているのがわかりますね。これでもう失敗しないですね。

print("1. indexを取得 (MultiIndex型)")
print(series.index)

print("2. index.to_flat_index()を取得 (Index型)")
print(series.index.to_flat_index())

------------------- 実行結果 --------------------------
1. indexを取得 (MultiIndex型)
MultiIndex([('女性', 0),
            ('女性', 1),
            ('男性', 0),
            ('男性', 1)],
           )

2. index.to_flat_index()を取得 (Index型)
Index([('女性', 0), ('女性', 1), ('男性', 0), ('男性', 1)], dtype='object')


まとめ

エラー文章で検索しても引っかかるものがなく、リファレンス見てもよく分からなくて焦りました。
同じように悩んでいる人に、少しでもお役に立てれば幸いです。

データ分析カテゴリの最新記事

%d人のブロガーが「いいね」をつけました。