NumPy配列ndarrayの欠損値np.nanを他の値に置換
NumPy配列ndarray
の欠損値NaN
(np.nan
)を置換するには、np.nan_to_num()
やnp.isnan()
を利用する。任意の値に置き換えたり、欠損値NaN
を除外した要素の平均値に置き換えたりできる。
欠損値を置換するのではなく削除する方法については以下の記事を参照。
pandasでの欠損値の処理については以下の記事を参照。
本記事のサンプルコードのNumPyのバージョンは以下の通り。バージョンによって仕様が異なる可能性があるので注意。
import numpy as np
print(np.__version__)
# 1.26.1
欠損値NaNの発生・生成・判定
np.genfromtxt()
でCSVファイルを読み取ると、デフォルトではデータが欠落した箇所が欠損値NaN
(Not a Number: 非数)となる。print()
での出力時はnan
と表示される。
a = np.genfromtxt('data/src/sample_nan.csv', delimiter=',')
print(a)
# [[11. 12. nan 14.]
# [21. nan nan 24.]
# [31. 32. 33. 34.]]
明示的に欠損値NaN
を生成したいときはnp.nan
やfloat('nan')
などを使う。
- 関連記事: Pythonにおけるnanの判定
a_nan = np.array([0, 1, np.nan, float('nan')])
print(a_nan)
# [ 0. 1. nan nan]
欠損値同士を==
で比較してもFalse
となってしまうため、欠損値かどうかを判定するにはnp.isnan()
を使う。
print(np.nan == np.nan)
# False
print(np.isnan(np.nan))
# True
np.isnan()
ではndarray
の各要素に対して欠損値NaN
かどうかを判定できる。
print(a_nan == np.nan)
# [False False False False]
print(np.isnan(a_nan))
# [False False True True]
np.genfromtxt()の引数filling_valuesを指定
元となるCSVファイルのデータが欠落している場合、np.genfromtxt()
で読み込むときに引数filling_values
を指定すると、欠落箇所を任意の値で埋めることができる。
例えば、0
で埋めたい場合は以下の通り。
a_fill = np.genfromtxt('data/src/sample_nan.csv', delimiter=',',
filling_values=0)
print(a_fill)
# [[11. 12. 0. 14.]
# [21. 0. 0. 24.]
# [31. 32. 33. 34.]]
欠損値ではない要素の平均値などで埋めたい場合はnp.genfromtxt()
での読み込み時には指定できない。以降に説明する方法を使う。
np.nan_to_num()で欠損値NaNを置換
配列ndarray
の欠損値NaN
を置換するにはnp.nan_to_num()
を使う。
なお、np.nan_to_num()
は欠損値NaN
だけでなく無限大inf
も置換する。以下の記事を参照。
np.nan_to_num()
の第一引数に配列ndarray
を指定すると、デフォルトでは欠損値が0
に置換された新たなndarray
が生成される。元のndarray
は変更されない。
a = np.genfromtxt('data/src/sample_nan.csv', delimiter=',')
print(a)
# [[11. 12. nan 14.]
# [21. nan nan 24.]
# [31. 32. 33. 34.]]
print(np.nan_to_num(a))
# [[11. 12. 0. 14.]
# [21. 0. 0. 24.]
# [31. 32. 33. 34.]]
print(a)
# [[11. 12. nan 14.]
# [21. nan nan 24.]
# [31. 32. 33. 34.]]
第二引数copy
をFalse
とすると元のndarray
が変更される。
np.nan_to_num(a, copy=False)
print(a)
# [[11. 12. 0. 14.]
# [21. 0. 0. 24.]
# [31. 32. 33. 34.]]
NumPy1.17
以降は第三引数nan
で置換する値を指定できる。
a = np.genfromtxt('data/src/sample_nan.csv', delimiter=',')
print(a)
# [[11. 12. nan 14.]
# [21. nan nan 24.]
# [31. 32. 33. 34.]]
print(np.nan_to_num(a, nan=-1))
# [[11. 12. -1. 14.]
# [21. -1. -1. 24.]
# [31. 32. 33. 34.]]
欠損値ではない要素の平均を算出する関数np.nanmean()
を利用すると、平均値に置換可能。列・行ごとの平均値で置換することもできる。
print(np.nanmean(a))
# 23.555555555555557
print(np.nan_to_num(a, nan=np.nanmean(a)))
# [[11. 12. 23.55555556 14. ]
# [21. 23.55555556 23.55555556 24. ]
# [31. 32. 33. 34. ]]
print(np.nanmean(a, axis=0, keepdims=True))
# [[21. 22. 33. 24.]]
print(np.nan_to_num(a, nan=np.nanmean(a, axis=0, keepdims=True)))
# [[11. 12. 33. 14.]
# [21. 22. 33. 24.]
# [31. 32. 33. 34.]]
print(np.nanmean(a, axis=1, keepdims=True))
# [[12.33333333]
# [22.5 ]
# [32.5 ]]
print(np.nan_to_num(a, nan=np.nanmean(a, axis=1, keepdims=True)))
# [[11. 12. 12.33333333 14. ]
# [21. 22.5 22.5 24. ]
# [31. 32. 33. 34. ]]
np.nan_to_num()
の第三引数nan
にndarray
を指定すると、第一引数のndarray
と同じ形状にブロードキャストされる。
- 関連記事: NumPyのブロードキャスト(形状の自動変換)
np.nanmean()
でkeepdims=True
とすると正しくブロードキャストされて置換される。axis=0
ではkeepdims=False
(デフォルト)でも問題ないが、axis
に関わらずkeepdims=True
としておいたほうが間違いは少ない。
1.17
より前のバージョンでは引数nan
が実装されていないので、0
以外の値に置換したい場合は次に説明する方法を使う。
np.isnan()を利用して欠損値NaNを置換
欠損値NaN
かを判定する関数np.isnan()
を使って、欠損値の要素がTrue
となるndarray
を取得できる。
a = np.genfromtxt('data/src/sample_nan.csv', delimiter=',')
print(a)
# [[11. 12. nan 14.]
# [21. nan nan 24.]
# [31. 32. 33. 34.]]
print(np.isnan(a))
# [[False False True False]
# [False True True False]
# [False False False False]]
これをマスクとして利用すると、欠損値の要素に任意の値を代入できる。
a[np.isnan(a)] = 0
print(a)
# [[11. 12. 0. 14.]
# [21. 0. 0. 24.]
# [31. 32. 33. 34.]]
np.nanmean()
を使って平均値に置き換えることも可能。
a = np.genfromtxt('data/src/sample_nan.csv', delimiter=',')
a[np.isnan(a)] = np.nanmean(a)
print(a)
# [[11. 12. 23.55555556 14. ]
# [21. 23.55555556 23.55555556 24. ]
# [31. 32. 33. 34. ]]
列・行ごとの平均値に置き換えたい場合はnp.where()
を使う。
a = np.genfromtxt('data/src/sample_nan.csv', delimiter=',')
print(np.where(np.isnan(a), np.nanmean(a, axis=0, keepdims=True), a))
# [[11. 12. 33. 14.]
# [21. 22. 33. 24.]
# [31. 32. 33. 34.]]
print(np.where(np.isnan(a), np.nanmean(a, axis=1, keepdims=True), a))
# [[11. 12. 12.33333333 14. ]
# [21. 22.5 22.5 24. ]
# [31. 32. 33. 34. ]]