pandas チートシート - DataFrame の欠損値 (NaN) の扱い方まとめ

チートシート(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)

DataFrameisnull() メソッドを使うと、各データが欠損値かどうかを 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   True

isnull() の代わりに 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) の数をスカラー値(整数)で取得するには次のようにします。

例: price 列の欠損値 (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) を数える

DataFramecount() メソッドを使うと、各カラムの Non-null 値(非欠損値)の数を簡単に調べることができます。

>>> df.count()  # あるいは df.notnull().sum()
title    4
price    3
dtype: int64

特定の列の非欠損値 (Non-null) の数をスカラー値(整数)で取得するには次のようにします。

例: price 列の非欠損値 (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" のように指定することもできます。

title 列に欠損値を含む行を削除
>>> 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  EEE

col1 列だけの DataFrame になってしまいました。。。

欠損値を補完する

Series#fillna(値) メソッドは、Series 内の欠損値 (NaN) 部分を指定した値に置き換えた Series を返します。 DataFrame#fillna(値) メソッドも使えますが、通常は特定列の Series データに対して使うことになると思います。

機械学習において、欠損値が含まれている行をすべて削除 (dropna()) してしまうと、学習に使用するデータ数が不足してしまうことがあります。 そのような場合は、欠損値を平均値や中央値で補完するというテクニックがあります。

age 列の欠損値部分に 0 を入れる
df["age"].fillna(0, inplace=True)
df["age"] = df["age"].fillna(0)  // 同上
age 列の欠損値を平均値 (mean) で補う
df["age"].fillna(df["age"].mean(), inplace=True)
df["age"] = df["age"].fillna(df["age"].mean())  // 同上
age 列の欠損値を中央値 (mode) で補う
df["age"].fillna(df["age"].mode(), inplace=True)
df["age"] = df["age"].fillna(df["age"].mode())  // 同上