LoginSignup
61

More than 5 years have passed since last update.

pandas DataFrame内にNaNありますか?

Last updated at Posted at 2016-12-01

ちょっと探して見つからず、何とかかんとかして出し方わかったのでメモ。

お題は「pandas DataFrame内にNaNありますか?」
データがちゃんと処理されているかの簡易的なチェックとして、データフレーム内にNaN値あるか、それがどこにあるか調べたい。
NaNを埋めたい/消したいならfillna()/dropna()使えばいいのだけど、今ここでやりたいのは「NaNがあるか調べて、その行(列)を表示すること」

例として、このデータフレームの2-4行目、または1-3列目だけを抜き出したい。

データ作成
df=pd.DataFrame(np.random.randn(5,5))
df.ix[2:, 1:3] = np.nan
df.columns=list('abcde')
df
#[Out]#           a         b         c         d         e
#[Out]# 0 -0.678873 -1.277486 -1.062232  0.097525 -2.386115
#[Out]# 1 -1.063709 -1.919997 -0.131733 -0.606348  0.101888
#[Out]# 2 -1.701473       NaN       NaN       NaN  0.201468
#[Out]# 3 -0.624932       NaN       NaN       NaN -0.654297
#[Out]# 4  0.345065       NaN       NaN       NaN -0.232199

NaNをbool値で出力

NaNがあるかどうかはisnull()/notnull()を使う。以下参考

pandas公式によるNaNの扱い方: pandas 0.19.1 documentation » Working with missing data

isnullメソッドを使う

isnull()
df.isnull()
#[Out]#        a      b      c      d      e
#[Out]# 0  False  False  False  False  False
#[Out]# 1  False  False  False  False  False
#[Out]# 2  False   True   True   True  False
#[Out]# 3  False   True   True   True  False
#[Out]# 4  False   True   True   True  False

返ってくるのはdfと同じ大きさでbool値の入ったデータフレーム。
NaNのところだけTrueになる。

notnull()はisnull()で返ってくるデータフレームのTrue/Falseが逆になったもの

ちょっとこれはやりたいことと違う

行(列)にNaNがあるかどうかまとめる

やりたいこと 「NaNがあるか調べて、その行(列)を表示すること」 を分解すると

  • NaNが一個以上ある行(列)を調べる
  • その行(列)をスライス/loc/ix/...で抜き出す

になるんじゃないかな。

ホニャララが一個以上ある、といえばnumpyのanyメソッド

np.any()
df.isnull().any()
#[Out]# a    False
#[Out]# b     True
#[Out]# c     True
#[Out]# d     True
#[Out]# e    False
#[Out]# dtype: bool

df.isnull().any(axis=1)
#[Out]# 0    False
#[Out]# 1    False
#[Out]# 2     True
#[Out]# 3     True
#[Out]# 4     True
#[Out]# dtype: bool

df.isnull().any(axis=0)  # df.isnull().any()と同じ
#[Out]# a    False
#[Out]# b     True
#[Out]# c     True
#[Out]# d     True
#[Out]# e    False
#[Out]# dtype: bool

any()のデフォルトの走査方向は行方向(axis=0)なのでdf.isnull().any()は列にTrue(isnull()による変換で、すなわちNaN)が一個以上含まれるならTrue / 含まれないならFalseを返す。
any(axis=1)としてやると走査方向を変えて列方向(axis=1)にTrue(すなわちNaN)が含まれるかどうかを探す。

axis=は省略可能なので、df.isnull().any(1)と書いてもdf.isnull().any(axis=1)と同じ。

行列に一個でもNaNがあるか

少しやりたいこととは話が逸れて、どこか一箇所にでもNaNがあればTrueを返すようにするにはanyを二つ重ねる。

NaNが一個でも含まれる?
df.isnull().any().any()  # NaNが含まれている
#[Out]# True
dff=pd.DataFrame(np.random.randn(5,5))  # NaNが含まれていない
dff.isnull().any().any()
#[Out]# False

stack overflowにも同じようなことやってました。
stack overflow - Python pandas: check if any value is NaN in DataFrame
df.any().any()以外にも

  • df.isnull().values.sum()
  • df.isnull().sum().sum()
  • df.isnull().values.any()

とか使っている。
%timeitで計測して時間が最も早かったのはdf.isnull().values.any()
一個でもNaNが含まれるか知りたいときは使ってみましょう。

NaNが含まれる行(列)を抜き出す

やりたいことがようやくできる。
df.isnull().any(1)行にNaNが含まれるかどうかのbool値作成して、スライスすると、NaNを含む列だけ抜き出せる。

NaN含む行抜き出し
df[df.isnull().any(1)]
#[Out]#           a   b   c   d         e
#[Out]# 2 -1.701473 NaN NaN NaN  0.201468
#[Out]# 3 -0.624932 NaN NaN NaN -0.654297
#[Out]# 4  0.345065 NaN NaN NaN -0.232199
NaN含む列抜き出し
df.ix[:,df.isnull().any()]
#[Out]#           b         c         d
#[Out]# 0 -1.277486 -1.062232  0.097525
#[Out]# 1 -1.919997 -0.131733 -0.606348
#[Out]# 2       NaN       NaN       NaN
#[Out]# 3       NaN       NaN       NaN
#[Out]# 4       NaN       NaN       NaN

以上!

より簡単な方法もありそうだけど、ないんですかね。誰か教えてください。
あと、pandasの行だけの抜き出しにloc, ilocとかあるのに対して、列の抜き出しはdf.<カラム名>とかdf.ix[:, <カラム名>]とかあるけど、美しくないので何か美しいやり方(行のloc, ilocと対になる列のloc, iloc的なの)ないんですか(*ω*)

更新2017/4/15
df.icol(3)で3列目抜き出し
df.icol([0,2])で0,2列目抜き出し
df.icol([0:2])で0,1,2列目は抜き出されずエラー


コメント欄に速度比較を載せました。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
61