note.nkmk.me

NumPyの配列ndarrayの欠損値np.nanを他の値に置換

Date: 2018-01-30 / Modified: 2019-10-28 / tags: Python, NumPy

NumPy配列ndarrayの欠損値NaNnp.nanなど)の要素を他の値に置換する場合、np.nan_to_num()を用いる方法やnp.isnan()を利用したブールインデックス参照を用いる方法などがある。任意の値に置き換えたり、欠損値NaNを除外した要素の平均値に置き換えたりできる。

ここでは以下の内容について説明する。

  • 欠損値NaNの発生・生成・判定
  • np.genfromtxt()の引数filling_valuesを指定
  • np.nan_to_num()で欠損値NaNを置換
  • ブールインデックス参照で欠損値NaNを置換

欠損値の要素を他の値で置換するのではなく削除する場合は、以下の記事を参照。

また、pandasを使う場合は、欠損値を操作する方法が別途用意されている。

スポンサーリンク

欠損値NaNの発生・生成・判定

np.genfromtxt()でCSVファイルを読み取ると、デフォルトではデータが欠落した箇所が欠損値NaN(Not a Number: 非数)となる。print()での出力時はnanと表示される。

import numpy as np

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.nanfloat('nan')などを使う。そのほか、標準ライブラリのmathモジュールをインポートしてmath.nanとしてもよい。どれでも同じ。

a_nan = np.array([0, 1, np.nan, float('nan')])
print(a_nan)
# [ 0.  1. nan nan]

欠損値同士を==で比較してもFalseとなってしまうため、欠損値かどうかを判定するにはnp.isnan()math.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を置換

欠損値NaNを置換するにはnp.nan_to_num()を使う。

np.nan_to_num()の第一引数に配列ndarrayを指定すると、デフォルトでは欠損値が0に置換された新たなndarrayが生成される。元のndarrayは変更されない。

a = np.genfromtxt('data/src/sample_nan.csv', delimiter=',')
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.]]

第二引数copyFalseとすると元のndarrayが変更される。

print(np.nan_to_num(a, copy=False))
# [[11. 12.  0. 14.]
#  [21.  0.  0. 24.]
#  [31. 32. 33. 34.]]

print(a)
# [[11. 12.  0. 14.]
#  [21.  0.  0. 24.]
#  [31. 32. 33. 34.]]

NumPyバージョン1.17以降は第三引数nanで置換する値を指定できる。

a = np.genfromtxt('data/src/sample_nan.csv', delimiter=',')
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.        ]]

1.17より前のバージョンでは引数nanが実装されていないので、0以外の値に置換したい場合は次に説明する方法を使う。

ブールインデックス参照で欠損値np.nanを置換

欠損値NaNか否かを判定する関数np.isnan()を使って、欠損値の位置がTrueとなるndarrayを取得できる。

a = np.genfromtxt('data/src/sample_nan.csv', delimiter=',')
print(np.isnan(a))
# [[False False  True False]
#  [False  True  True False]
#  [False False False False]]

これを利用して、欠損値の位置に任意の値を代入することで、欠損値を置き換えることができる。

0に置換したい場合は以下の通り。

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.        ]]
スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事