pandasで欠損値を見つける・カウントする・置き換える

CSVファイルを読み込むと欠損値となっているセルがあって困ることありますよね。
この記事を読んで欠損値対策をしましょう。

isnaisnullは同じもの

pd.isna()pd.isnull() は同じものです。
Gitのコード上でもそうなっています。
isnull = isna

pandas.DataFrame.isna()pandas.DataFrame.isnull() も同じものです。
こちらもGitのコードで同じものになっています。
DataFrame.isnull is an alias for DataFrame.isna.

pandas.Series.isna()pandas.Series.isnull() も同じものです。
Git上に書かれています。
Series.isnull is an alias for Series.isna.

それぞれの仕様書を載せておきます。

isnaで引っかかるもの

isna() で何を見つけられるか、見てみます。
0、空文字、スペース などは引っかかりません。

import pandas as pd
import numpy as np
import math

print(pd.NA)
print(type(pd.NA))
print(pd.isna(pd.NA))
# <NA>
# <class 'pandas._libs.missing.NAType'>
# True

print(np.nan)
print(type(np.nan))
print(pd.isna(np.nan))
# nan
# <class 'float'>
# True

print(math.nan)
print(type(math.nan))
print(pd.isna(math.nan))
# nan
# <class 'float'>
# True

print(None)
print(type(None))
print(pd.isna(None))
# None
# <class 'NoneType'>
# True

print(pd.isna(0))
# False
# 0は引っかからない。

print(pd.isna(''))
# False
# 空文字は引っかからない。

print(pd.isna(' '))
# False
# 半角スペースは引っかからない。

print(pd.isna(' '))
# False
# 全角スペースは引っかからない。

isnaとisnullは同じものですが、確認しましょう。

print(pd.isnull(pd.NA))
print(pd.isnull(np.nan))
print(pd.isnull(math.nan))
print(pd.isnull(None))

# True
# True
# True
# True
# isnullはisnaの結果と同じ。

欠損値をカウントする

DataFrameの欠損値をカウントしてみます。
全体、横方向、縦方向のそれぞれでカウントできます。

# DataFrameの例
df = pd.DataFrame(dict(
    name=['John', 'Nana', 'Ken'],
    age=[10, np.nan, 3],
    country=['us', np.nan, np.nan],))

print(df)
#    name   age country
# 0  John  10.0      us
# 1  Nana   NaN     NaN
# 2   Ken   3.0     NaN

print(df.isna())
#     name    age  country
# 0  False  False    False
# 1  False   True     True
# 2  False  False     True

# 各列の欠損値カウント
print(df.isna().sum())
# name       0
# age        1
# country    2
# dtype: int64

# 各行の欠損値カウント
print(df.isna().sum(axis='columns'))
# 0    0
# 1    2
# 2    1
# dtype: int64

# DataFrame全体の欠損値カウント
print(df.isna().sum().sum())
# 3

Seriesの欠損値をカウントしてみます。

# Seriesの例
s = pd.Series(
    data=[5, None, 2],
    index=['orange', 'apple', 'lemon'],
    name='num')

print(s)
# orange    5.0
# apple     NaN
# lemon     2.0
# Name: num, dtype: float64

print(s.isna())
# orange    False
# apple      True
# lemon     False
# Name: num, dtype: bool

# Seriesの欠損値をカウントする。
print(s.isna().sum())
# 1

欠損値を見つけて、置換する

欠損値を補間してみましょう。

下の例では、DataFrameを使い、age列の欠損値はゼロに、country列の欠損値は”unknown”に置換し欠損値を無くしています。

# DataFrameの例
df = pd.DataFrame(dict(
    name=['John', 'Nana', 'Ken'],
    age=[np.nan, np.nan, 3],
    country=['us', np.nan, np.nan],))

print(df)
#    name  age country
# 0  John  NaN      us
# 1  Nana  NaN     NaN
# 2   Ken  3.0     NaN
    
print(df['age'])
# 0    NaN
# 1    NaN
# 2    3.0
# Name: age, dtype: float64

print(df['age'].isna())
# 0     True
# 1     True
# 2    False
# Name: age, dtype: bool

# ageが欠損値の行のみ、表示する。
print(df[df['age'].isna()])
#    name  age country
# 0  John  NaN      us
# 1  Nana  NaN     NaN

# ageが欠損値のIndexを指定して、0に置き換える。
df.loc[df['age'].isna(), 'age'] = 0
print(df)
#    name  age country
# 0  John  0.0      us
# 1  Nana  0.0     NaN
# 2   Ken  3.0     NaN

# countryが欠損値になっている行を、unknownに置き換える。
df.loc[df['country'].isna(), 'country'] = 'unknown'
print(df)
#    name  age  country
# 0  John  0.0       us
# 1  Nana  0.0  unknown
# 2   Ken  3.0  unknown
    
# 欠損値をカウントする。
print(df.isna().sum().sum())
# 0

Seriesで欠損値を置換してみます。

# Seriesの例
s = pd.Series(
    data=[5, None, 2],
    index=['orange', 'apple', 'lemon'],
    name='num')

print(s)
# orange    5.0
# apple     NaN
# lemon     2.0
# Name: num, dtype: float64

# 欠損値をゼロに置き換える。
s[s.isna()] = 0
print(s)
# orange    5.0
# apple     0.0
# lemon     2.0
# Name: num, dtype: float64

# 置換後の欠損値のカウント。
print(s.isna().sum())
# 0