チートシート(DataFrame の欠損値の扱い)
| 概要 | コード |
|---|---|
| 欠損値を表現する | np.nan |
| 欠損値部分を True、それ以外を False にする | df2 = df.isnull() |
| 欠損値以外の True、それ以外を True にする | df2 = df.notnull() |
| 欠損値を数える | df.isnull().sum()df.isnull().sum(axis=1) |
| 非欠損値を数える | df.notnull().sum()df.count()df.info() |
| 欠損値がある列/行を探す | df.isnull().any()df.isnull().any(axis=1) |
| 欠損値を含む「行」を削除する | df.dropna()df.dropna(axis=0)df.dropna(axis="index") |
| 欠損値を含む「列」を削除する | df.dropna(axis=1)df.dropna(axis="columns") |
| 欠損値を補完する | df["列"] = df["列"].fillna(値)df["列"].fillna(値, inplace=True) |
isnull()はisna()のエイリアスです。
Python コードでの欠損値 (NaN) の表現方法
pandas では、値が存在しないことを欠損値 (NaN: Not a Number) が存在すると表現します(プログラム的には何らかの値で「値がない」ことを表現しないといけないため)。
欠損値は、NumPy の np.nan で表現することができます。
import numpy as np
print(np.nan) # nan
print(type(np.nan)) # <class 'float'>
ちなみに、CSV ファイルを pd.read_csv() で読み込んだ場合、何も記述されていない部分に欠損値 (np.nan) が格納されます。
逆に値が存在することは、Non-null(非欠損値)と表現したりします。
欠損値部分とそれ以外の要素を True/False 値に変換する (isnull, notnull)
DataFrame の isnull() メソッドを使うと、各データが欠損値かどうかを True/False の形で取得できます。
import numpy as np
import pandas as pd
# テストデータ
df = pd.DataFrame({
"title": ["Title-1", "Title-2", np.nan, "Title-4", "Title-5"],
"price": [1000, np.nan, 3000, 4000, np.nan]
})
print(df.isnull())
title price
0 False False
1 False True
2 True False
3 False False
4 False Trueisnull() の代わりに notnull() を使うと、True/False が反転した結果を得られます。
print(df.notnull())
title price
0 True True
1 True False
2 False True
3 True True
4 True False欠損値・非欠損値を数える (isnull, notnull, sum, count, info)
欠損値 (NaN) を数える
df.isnull() を実行すると、欠損値部分だけが True になった DataFrame を生成できます。
その True の数を sum() で集計すれば、欠損値 (NaN) の数を数えることができます。
>>> df.isnull().sum()
title 1
price 2
dtype: int64
これで、title 列には欠損値が 1 つ、price 列には欠損値が 2 つ存在することが分かりました。
特定の列の欠損値 (NaN) の数をスカラー値(整数)で取得するには次のようにします。
>>> df["price"].isnull().sum()
2多くの場合、欠損値は列方向で集計しますが、sum(axis=1) とすることで、行ごとの欠損値数を取得することもできます。
>>> df.isnull().sum(axis=1)
0 0
1 1
2 1
3 0
4 1
dtype: int64
非欠損値 (Non-null) を数える
DataFrame の count() メソッドを使うと、各カラムの Non-null 値(非欠損値)の数を簡単に調べることができます。
>>> df.count() # あるいは df.notnull().sum()
title 4
price 3
dtype: int64
特定の列の非欠損値 (Non-null) の数をスカラー値(整数)で取得するには次のようにします。
>>> df["title"].count() # あるいは df["title"].nonnull().sum()
4非欠損値の数は、info() メソッドの出力の Non-Null Count 列でも確認できます。
>>> df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 5 entries, 0 to 4
Data columns (total 2 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 title 4 non-null object
1 price 3 non-null float64
dtypes: float64(1), object(1)
memory usage: 208.0+ bytes
欠損値がある列/行を探す
df.isnull() による欠損値の抽出結果に対して、any() メソッドを適用することで、欠損値の存在する列を調べることができます。
import numpy as np
import pandas as pd
# テストデータ
df = pd.DataFrame({
"title": ["Title-1", "Title-2", "Title-3"],
"price": [1000, np.nan, np.nan],
})
print(df.isnull().any())title False
price True
dtype: boolこの結果から、price 列に欠損値が存在することが分かります。
欠損値の有無を行ごとに調べたいときは、any() メソッドの軸オプションで行方向 axis=1 を指定します。
print(df.isnull().any(axis=1))
0 False
1 True
2 True
dtype: bool欠損値を含む「行」を削除する
欠損値を 1 つでも含む行を削除するには、df.dropna() を使用します(あるいは df.dropna(axis=0) や df.dropna(axis="index") でも同様)。
import numpy as np
import pandas as pd
# テストデータ
df = pd.DataFrame({
"title": ["Title-1", "Title-2", np.nan, "Title-4", "Title-5"],
"price": [1000, np.nan, 3000, 4000, np.nan]
})
df2 = df.dropna()
print(df2)
title price
0 Title-1 1000.0
3 Title-4 4000.0欠損値の有無を調べる列を絞るには、subset=["列1", "列2"] のようなオプションパラメーターで指定します。
指定する列が 1 つだけの場合は、リストではなく subset="列1" のように指定することもできます。
>>> df.dropna(subset=["title"])
title price
0 Title-1 1000.0
1 Title-2 NaN
3 Title-4 4000.0
4 Title-5 NaN欠損値を含む「列」を削除する
欠損値を 1 つでも含むカラム(列)を丸ごと削除するには、df.dropna(axis=1)(あるいは df.dropna(axis="columns"))を使います。
import numpy as np
import pandas as pd
# テストデータ
df = pd.DataFrame({
"col1": ["AAA", "BBB", "CCC", "DDD", "EEE"],
"col2": [100, np.nan, 300, 400, 500],
"col3": [1.0, 2.0, np.nan, 4.0, 5.0]
})
df2 = df.dropna(axis=1)
print(df2)
col2 列と col3 列には欠損値 (NaN) が含まれているので、それらの列が丸ごと削除されます。
col1
0 AAA
1 BBB
2 CCC
3 DDD
4 EEEcol1 列だけの DataFrame になってしまいました。。。
欠損値を補完する
Series#fillna(値) メソッドは、Series 内の欠損値 (NaN) 部分を指定した値に置き換えた Series を返します。
DataFrame#fillna(値) メソッドも使えますが、通常は特定列の Series データに対して使うことになると思います。
機械学習において、欠損値が含まれている行をすべて削除 (dropna()) してしまうと、学習に使用するデータ数が不足してしまうことがあります。
そのような場合は、欠損値を平均値や中央値で補完するというテクニックがあります。
df["age"].fillna(0, inplace=True)
df["age"] = df["age"].fillna(0) // 同上df["age"].fillna(df["age"].mean(), inplace=True)
df["age"] = df["age"].fillna(df["age"].mean()) // 同上df["age"].fillna(df["age"].mode(), inplace=True)
df["age"] = df["age"].fillna(df["age"].mode()) // 同上