Pythonにおけるnanの判定
Pythonの浮動小数点数float
型には非数(not a number)を表すnan
がある。nan
の仕様はIEEE 754の浮動小数点規格によって定められている。
ここでは、Pythonにおけるnan
の判定や比較について説明する。
本記事のサンプルコードではmathやpandas, NumPyを以下のようにインポートして使う。
import math
import numpy as np
import pandas as pd
なお、値が存在しないことを表すNone
はnan
とは別物。None
についての詳細は以下の記事を参照。
- 関連記事: PythonにおけるNoneの判定
NumPyやpandasでnan
を削除したり置換したりする方法について以下の記事を参照。
- 関連記事: NumPy配列ndarrayの欠損値np.nanを含む行や列を削除
- 関連記事: NumPy配列ndarrayの欠損値np.nanを他の値に置換
- 関連記事: pandasで欠損値NaNを削除(除外)するdropna
- 関連記事: pandasで欠損値NaNを置換(穴埋め)するfillna
浮動小数点数float型の非数nan
Pythonでは浮動小数点数float
型に非数を表すnan
がある。float('nan')
で生成できる。そのほかの生成方法については後述。
print(float('nan'))
# nan
print(type(float('nan')))
# <class 'float'>
例えば、NumPyやpandasにおいて値が欠損したCSVファイルを読み込むとnan
が発生する。pandasではNaN
と表記される。
a = np.genfromtxt('data/src/sample_nan.csv', delimiter=',')
print(a)
# [[11. 12. nan 14.]
# [21. nan nan 24.]
# [31. 32. 33. 34.]]
df = pd.read_csv('data/src/sample_pandas_normal_nan.csv')[:3]
print(df)
# name age state point other
# 0 Alice 24.0 NY NaN NaN
# 1 NaN NaN NaN NaN NaN
# 2 Charlie NaN CA NaN NaN
nanの生成: float('nan'), math.nan, numpy.nan
上述のようにfloat('nan')
でnan
を生成できる。大文字小文字を区別しないので'NaN'
や'NAN'
などでもよい。
print(float('nan'))
# nan
print(float('NaN'))
# nan
print(float('NAN'))
# nan
そのほか、math(標準ライブラリ)やNumPyでもnan
を生成できる。NumPyではNaN
もNAN
もエイリアスとして定義されている。
print(math.nan)
# nan
print(np.nan)
# nan
print(np.NaN)
# nan
print(np.NAN)
# nan
いずれも同等で、次に紹介する判定方法で同じように判定される。
nanの判定: math.isnan(), np.isnan()
math.isnan()
で値がnan
かどうかを判定できる。
print(math.isnan(float('nan')))
# True
print(math.isnan(math.nan))
# True
print(math.isnan(np.nan))
# True
numpy.isnan()
もある。
スカラー値のほか、リストやNumPy配列ndarray
といったarray-likeオブジェクトも引数に指定可能。要素ごとに判定され、ndarray
が返される。
print(np.isnan(float('nan')))
# True
print(np.isnan([float('nan'), math.nan, np.nan, 0]))
# [ True True True False]
なお、pandas.DataFrame
, Series
にはisna()
およびそのエイリアスのisnull()
メソッドがある。nan
だけでなくNone
に対してもTrue
と判定するという違いがある。詳細は以下の記事を参照。
math.isnan()
やnp.isnan()
にNone
を指定するとエラーになる。
比較演算子(<, >, ==, !=)に対する振る舞い
nan
と比較する場合、相手がどんな値でも<
, >
, ==
, <=
, >=
は常にFalse
、!=
は常にTrue
となる。
print(10 < float('nan'))
# False
print(10 > float('nan'))
# False
print(10 == float('nan'))
# False
print(10 != float('nan'))
# True
nan
同士の比較でも同様。==
, !=
は直感に反した結果となるので要注意。
直観に反する帰結として、非数値は自分自身と等価ではないことになります。 例えば x = float('NaN') ならば、 3 < x, x < 3, x == x は全て偽で、x != x は真です。 6. 式 (expression) - 値の比較 — Python 3.11.3 ドキュメント
print(float('nan') == float('nan'))
# False
print(float('nan') != float('nan'))
# True
ある値がnan
であるかを判定するには、==
ではなく上述のmath.isnan()
, numpy.isnan()
を使う。
if文でのnanの判定
Pythonではbool
型(True
, False
)以外のオブジェクトもif
文の条件式などでは真偽のいずれかに判定される。例えば、空文字列''
や数値0
はFalse
でそれ以外の文字列や数値はTrue
。
bool()
で確認できるように、nan
はTrue
と判定される。
print(bool(float('nan')))
# True
上述のように==
でも判定できないので、math.isnan()
, numpy.isnan()
を使う。
x = float('nan')
if math.isnan(x):
print('This is nan.')
else:
print('This is not nan.')
# This is nan.
x = 100
if math.isnan(x):
print('This is nan.')
else:
print('This is not nan.')
# This is not nan.
リスト中のnanの削除・置換
リスト中のnan
を削除・置換したい場合、リスト内包表記および三項演算子とmath.isnan()
, numpy.isnan()
による判定を組み合わせる。
l = [float('nan'), 0, 1, 2]
print(l)
# [nan, 0, 1, 2]
print([x for x in l if not math.isnan(x)])
# [0, 1, 2]
print([-100 if math.isnan(x) else x for x in l])
# [-100, 0, 1, 2]
判定にmath.isnan()
, numpy.isnan()
を使うだけで、考え方は他の値を削除・置換する場合と同じ。詳細は以下の記事を参照。
NumPyやpandasにおいてnan
を削除したり置換したりする方法について以下の記事を参照。
- 関連記事: NumPy配列ndarrayの欠損値np.nanを含む行や列を削除
- 関連記事: NumPy配列ndarrayの欠損値np.nanを他の値に置換
- 関連記事: pandasで欠損値NaNを削除(除外)するdropna
- 関連記事: pandasで欠損値NaNを置換(穴埋め)するfillna
nanを含む演算
nan
を含む+
, -
, *
, /
, **
などの演算結果はすべてnan
となる。
print(float('nan') + 100)
# nan
print(float('nan') - 100)
# nan
print(float('nan') - 100)
# nan
print(float('nan') / 100)
# nan
print(float('nan') ** 100)
# nan