ちょっと探して見つからず、何とかかんとかして出し方わかったのでメモ。
お題は「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メソッドを使う
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
メソッド
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を二つ重ねる。
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を含む列だけ抜き出せる。
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
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列目は抜き出されずエラー
コメント欄に速度比較を載せました。