Pythonのif文でNaN判定する方法
Pythonのif文でfloat型の値をNaN判定
NaNを普段から「ナン」と私は呼んでますが、あってるんでしょうか?
調べたところ…NaNは読み方「ナン」で合ってます。本格カレーについてくるナンと同じ読み方!
※本場の読み方は「ネァン)」だそうですが、まあ日本国内ではナンで良さそうです。
NaN(Not a number)は、一般的に、ありえない計算しようとした場合に発生します。例えば、0を0で除算、0に無限大を乗算、負数の対数や平方根などの場合です。ただ、Pythonの場合は、計算を行おうとした場合にエラーになってしまいます。
if文でNaNの判定をするのに便利な「math.isnan()」という関数が用意されています。試してみましょう。
#!/usr/bin/python3 import math a=0 b=0 if( math.isnan(a/b) ) : print( "NaN Error" ) exit() c=a/b print( c )
変数a,bにそれぞれ0を代入し、ゼロ除算の結果NaNになるようならNaN Errorと表示する、というスクリプト。しかし、結果はこうなります。
File "./nan.py", line 7, in <module> if( math.isnan(a/b) ) : ZeroDivisionError: division by zero
エェェ!生エラー出た!
どうやら、isnanより先にa/bを計算したときにdivision by zeroエラーになってしまう模様。まあ、処理上はisnanを使わなくても、b=0かどうかをif文で判定すればいいんですけど…
どうやら、計算処理でNaNを生成すること自体が難しい模様。float(“nan”)で人為的にNaNを発生させることができるので、試してみました。
#!/usr/bin/python3 import math c=float("nan") if( math.isnan(c) ) : print( "NaN Error" ) exit() print( c )
実行するとこう。
c=NaNなので、print文でNaN Errorを表示しています。
関連 Pythonのprint
% ./nan.py NaN Error
これだと、isnan()の存在意義がイマイチ感じられませんね。他のケースを調べてみましょう。
Pythonのリスト(list)のNaN判定
list中に含まれるNaNを判定するサンプルコード。
$ cat nanlist.py #!/usr/bin/python3 import math # list1 を作成 list1=[1,2,3,float('nan'),5,6,float('nan'),7] print( list1 ) # isnan()=Falseのみ対象にlist1からlist2を作成 list2 = [x for x in list1 if math.isnan(x) == False] print( list2 )
forとif文を組み合わせて、listからNaN判定がFalse(=NaNではない)値のみを抽出しています。forのこの書き方は「内包表記」という記述方法で、listの処理を高速化するための常套手段。
関連 Pythonのfor文
関連 Pythonのlist
上記のコードにnanlist.pyという名前をつけて保存し、実行するとこう。
$ ./nanlist.py [1, 2, 3, nan, 5, 6, nan, 7] [1, 2, 3, 5, 6, 7]
PythonのPandasデータフレーム(dataframe)のNaN判定
Pythonのライブラリ、Pandasで扱うデータフレームは、行と列で成り立つ表のようなデータ。二次元配列と考えれば良いかも知れません。
2次元配列に加えて、行番号とカラム名がセットになっています。
name age 0 Taro 13.0 1 Hanako NaN 2 Jiro 12.0
以下は、データフレームの第二カラムがNaNではないものだけを抽出するサンプルコードです。リストの要素に対してforループでmath.isnan()を使ってNaN判定しています。
$ cat nandf.py #!/usr/bin/python3 import pandas as pd import math # dataframesを作成 data = [['Taro',13],['Hanako',float('nan')],['Jiro',12]] df = pd.DataFrame(data,columns =['name','age']) print(df) # ageがNaNでないものだけを表示 print( "### without NaN Value ###" ) for col_name, item in df.iterrows(): if( math.isnan(item[1]) == False ): print( item[0], item[1] )
実行するとこうなります。
$ ./nandf.py name age 0 Taro 13.0 1 Hanako NaN 2 Jiro 12.0 ### without NaN Value ### Taro 13.0 Jiro 12.0
データフレームの第二カラムageの値がNaNのものだけを除外してprint文で表示しています。
PythonのNumpyのNaN判定
Numpyは高速で多次元配列の計算を行うためのライブラリ。
2×3の2次元配列に対して、第一要素、第二要素がともにNaNではないときに新規の2次元配列に追加するサンプルコードです。
$ cat ./nannumpy.py #!/usr/bin/python3 import numpy as np import math # numpy arrayを生成 list=np.array([[1,2],[3,float('nan')],[5,6]]) # numpy array表示 print ( list ) # 配列の第一要素、第二要素がともにNaNではないときだけlist2に追加 list2 = [(x,y) for x,y in list if math.isnan(x) == False and math.isnan(y) == False ] # 新規に生成した numpy arrayを生成 print( list2 )
numpy行列の各要素にmath.isnan()でNaN判定。
np.array()で、numpy行列の初期化をおこなって、forの内包表記でnan判定を行いながらnumpy行列list2を作成、表示しています。
実行するとこうなります。
$ ./nannumpy.py [[ 1. 2.] [ 3. nan] [ 5. 6.]] [(1.0, 2.0), (5.0, 6.0)]
PythonのNaN判定のまとめ
- PythonのNaNは、math.isnan()で判定が可能
- Pythonで0除算などを行うと、NaNとはならずにDivision by zeroのエラーになる
- listやデータフレームなどでNaN判定を行う場合は、forループ等で複数判定をおこなう