Python

pandasにおける欠損値の扱い

By 2022年3月5日No Comments

この記事ではデータの欠落において、pandasがそれを表現する方法についてや処理の方法についてを解説します。

プログラミング初心者対象!Python入門セミナー

プログラミング初心者がPythonの初歩部分を突破するためのセミナーです。

pandasでデータ分析を行うときにデータが欠落していると、分析結果に影響を与える可能性があります。この記事を読んで、データの欠損に対処する方法について学びましょう。

pandasについて

pandasを使うと、データの統計量を表示したり、グラフ化するなど、データ分析(データサイエンス)や機械学習で必要となる作業を簡単に行うことができるようになります。

pandasは外部ライブラリなので、使用するにはインストールが必要になります。Numpyの記事でも取り上げましたが、インストールにはAnacondaやminicondaがおすすめです。

Anacondaのインストール

Minicondaのインストール

pandasの欠損値の検出

csvファイルをpandasで読み込んだとき、要素が空白だったりすると欠損値NaN(Not a Number)だとみなされます。その際におけるNaNの扱いについて説明します。

今回のデータセットは以下のものを使います。5人の生徒の5教科のテスト結果をDataFrameにしています。欠損値はnp.nanによって生成しています。pandasではnp.nanはnoneを使っても同じように処理することができます。

data = pd.DataFrame(np.array([[80, 70, 80, 90, np.nan], [60, 60, 60, 60, 60], [np.nan, 80, 70, 60, np.nan], [40, np.nan, 40, 80, 80], [50, 80, np.nan, 50, 80]]), columns=["Math", "English", "Physics", "Chemistry", "History"], index=["Tanaka", "Suzuki", "Sato", "Yamada", "Ogawa"])#         Math  English  Physics  Chemistry  History# Tanaka  80.0     70.0     80.0       90.0      NaN# Suzuki  60.0     60.0     60.0       60.0     60.0# Sato     NaN     80.0     70.0       60.0      NaN# Yamada  40.0      NaN     40.0       80.0     80.0# Ogawa   50.0     80.0      NaN       50.0     80.0

pandasのデータ構造には、NaNを検出するための2つのメソッドisnull()とnotnull()が用意されています。いずれも、データに対するブール値(TrueもしくはFalse)が返されます。例を見てみましょう。NaNの要素にはTrueが、それ以外にはFalseが返されていることが確認できます。

print(data.isnull())
#          Math  English  Physics  Chemistry  History
# Tanaka  False    False    False      False     True
# Suzuki  False    False    False      False    False
# Sato     True    False    False      False     True
# Yamada  False     True    False      False    False
# Ogawa   False    False     True      False    False

notnull()はisnull()の逆です。NaNの要素にはFalseが、それ以外にはTrueが返されていることが確認できます。以下のように

print(data.notnull())
#          Math  English  Physics  Chemistry  History
# Tanaka   True     True     True       True    False
# Suzuki   True     True     True       True     True
# Sato    False     True     True       True    False
# Yamada   True    False     True       True     True
# Ogawa    True     True    False       True     True

pandasの欠損値の除外

pandasにおける欠損値を除外するにはdropna()を使います。Seriesに対する結果は単純です。

series = pd.Series([1, np.nan, 'hello', np.nan])
print(series)
# 0        1
# 1      NaN
# 2    hello
# 3      NaN
# dtype: object

次にDataFrameについて考えてみましょう。DataFrameは先程のものを使います。

print(data)
#         Math  English  Physics  Chemistry  History
# Tanaka  80.0     70.0     80.0       90.0      NaN
# Suzuki  60.0     60.0     60.0       60.0     60.0
# Sato     NaN     80.0     70.0       60.0      NaN
# Yamada  40.0      NaN     40.0       80.0     80.0
# Ogawa   50.0     80.0      NaN       50.0     80.0

DataFrameは行と列からなるので1つの要素を削除することはできません。まずデフォルトでは、dropna()はNaNが存在する全ての行を削除します。今回の例ではテスト結果に欠損値のないSuzukiの結果が返されます。

print(data.dropna())
#         Math  English  Physics  Chemistry  History
# Suzuki  60.0     60.0     60.0       60.0     60.0

または別の軸に沿ったNaNの除外も可能です。引数axisを指定することで、NaNを含む全ての列を削除します。今回の例では欠損値のないChemistyの結果が返されます。

print(data.dropna(axis='1'))
#         Chemistry
# Tanaka       90.0
# Suzuki       60.0
# Sato         60.0
# Yamada       80.0
# Ogawa        50.0

除外対象にする行や列を要素がすべてNaNのときに限定したいかもしれません。そのときは、引数how=’all’を指定すると全ての値が欠損値の行が削除されます。

また、引数threshに個数を指定すると欠損値ではない要素の数に応じて行や列を削除することができます。今回の例だとthresh=4とすると欠損値ではない要素の数がが4つ以上含まれている行が残ります。

print(data.dropna(thresh=4))
#         Math  English  Physics  Chemistry  History
# Tanaka  80.0     70.0     80.0       90.0      NaN
# Suzuki  60.0     60.0     60.0       60.0     60.0
# Yamada  40.0      NaN     40.0       80.0     80.0
# Ogawa   50.0     80.0      NaN       50.0     80.0

さらに特定の行や列にしぼって削除したい場合は、引数subsetに対象としたい行列のラベルを指定します。今回はHistoryに欠損値がある場合その行を削除します。

print(data.dropna(subset=['History']))
#         Math  English  Physics  Chemistry  History
# Suzuki  60.0     60.0     60.0       60.0     60.0
# Yamada  40.0      NaN     40.0       80.0     80.0
# Ogawa   50.0     80.0      NaN       50.0     80.0

pandasの欠損値の置換

NaNを有効な値で置き換えることがいい場合もあります。NaNを全て0で置き換えるように単一の数値を使ったり、他の適当な値から補完をすることができます。

そんなときはfillna()を使うことで欠損値を任意の値で置き換えることができます。

先程のdataを例とします。

print(data)
#         Math  English  Physics  Chemistry  History
# Tanaka  80.0     70.0     80.0       90.0      NaN
# Suzuki  60.0     60.0     60.0       60.0     60.0
# Sato     NaN     80.0     70.0       60.0      NaN
# Yamada  40.0      NaN     40.0       80.0     80.0
# Ogawa   50.0     80.0      NaN       50.0     80.0

dataの欠損値をすべて0で置き換えてみます。

print(data.fillna(0))
#         Math  English  Physics  Chemistry  History
# Tanaka  80.0     70.0     80.0       90.0      0.0
# Suzuki  60.0     60.0     60.0       60.0     60.0
# Sato     0.0     80.0     70.0       60.0      0.0
# Yamada  40.0      0.0     40.0       80.0     80.0
# Ogawa   50.0     80.0      0.0       50.0     80.0

引数method=’ffill’ (forward fill)を指定することで、NaNの要素に対して1つ前の値を埋めることができます。forward fillを行うとき前の値を利用できない場合はNaNが残ります。

print(data.fillna(method='ffill'))
#        Math  English  Physics  Chemistry  History
# Tanaka  80.0     70.0     80.0       90.0      NaN
# Suzuki  60.0     60.0     60.0       60.0     60.0
# Sato    60.0     80.0     70.0       60.0     60.0
# Yamada  40.0     80.0     40.0       80.0     80.0
# Ogawa   50.0     80.0     40.0       50.0     80.0

軸の指定をすることもできます。今回の例の場合は、1列目がNaNの場合残ってしまいます。

print(data.fillna(method='ffill', axis=1))
#         Math  English  Physics  Chemistry  History
# Tanaka  80.0     70.0     80.0       90.0     90.0
# Suzuki  60.0     60.0     60.0       60.0     60.0
# Sato     NaN     80.0     70.0       60.0     60.0
# Yamada  40.0     40.0     40.0       80.0     80.0
# Ogawa   50.0     80.0     80.0       50.0     80.0

同じように引数method=’bfill’ (back fill)を指定することでNaNの要素に対して1通白の値を埋めることができます。この場合は最後の行のNaNは残ってしまいます。

print(data.fillna(method='bfill'))
#         Math  English  Physics  Chemistry  History
# Tanaka  80.0     70.0     80.0       90.0     60.0
# Suzuki  60.0     60.0     60.0       60.0     60.0
# Sato    40.0     80.0     70.0       60.0     80.0
# Yamada  40.0     80.0     40.0       80.0     80.0
# Ogawa   50.0     80.0      NaN       50.0     80.0

まとめ

今回はpandasにおける欠損値の扱いについて解説しました。欠損値をうまく処理することでよりpandasを使いこなすことができるようになると思うのでぜひマスターしましょう。

Udemyの動画学習でもPythonを勉強しよう!

「平日の夜の勉強会には時間が間に合わなくて参加できない」「通勤時間のわずかな隙間時間を勉強時間にあてたい」「本ではよく分からないところを動画で理解を深めたい」そんなあなたはUdemyの動画学習がお勧めです!

UdemyのPythonおすすめ33講座レビューリスト
HOSL

Author HOSL

More posts by HOSL