[pandas] 欠損値 (NA) の処理

[pandas] 欠損値 (NA) の処理

欠損値 (NA)

 一般に pandas ではデータの 欠損値 (NA : Not Available)NaN (Not a Number ) とよばれる特殊な浮動小数点数を割り当てます。たとえば、互いに異なるラベルをもつ Series 同士で演算を実行すると NaN が現れます。

# リストPD20-1

import numpy as np
import pandas as pd

# Seriseオブジェクトを作成
a = pd.Series([10, 20, 30], index=list("ABC"))
b = pd.Series([ 5, 10, 15], index=list("BCD"))

# aをbで除算
print(a / b)
A    NaN
B    4.0
C    3.0
D    NaN
dtype: float64

 NaN は numpy.nan とよばれる 64bit浮動小数点数です。
 Python の欠損値オブジェクト None を含むリストから Series を生成した場合も、None は numpy.nan に変換されます。

# リストPD20-2

# Seriseオブジェクトを作成
d = pd.Series([None, 0, 1], index=list("ABC"))

print(d)
A    NaN
B    0.0
C    1.0
dtype: float64

dropna() 欠損値の削除

 以下のコードを実行すると、このサイトから CSV形式のテストデータ (10人の年齢、身長、体重のデータ) を読み込んで、DataFrame に変換します。このテストデータはいくつかの空白データがあるので、pandas で読み込んだときには、空白部分に NaN が割り当てられます。

# リストPD21-1

import numpy as np
import pandas as pd

# テストデータのURL
u = "https://python.atelierkobato.com/wp-content/uploads/2019/07/pandas_test_04.csv"

# テストデータを読み込んでDataFrameを作成
df = pd.read_csv(u, index_col=0)

print(df)
         age  height  weight
Allan     27  184.18   77.11
Jeff      15     NaN   58.74
Conrad    40  160.50   70.04
Rowland   35  162.70     NaN
William   14  164.98   56.72
Thomas    27     NaN     NaN
Stewart   19  174.01   82.58
Roy       31  167.49   77.04
Brendan   23     NaN   61.18
Scott     10  142.37   35.56

 DataFrame の dropna()メソッド は欠損値 (NA) の存在する行をすべて取り除きます。

# リストPD21-2

# 欠損値を含む行をすべて削除
df_2 = df.dropna()

print(df_2)
# 欠損値を含む行を除去
df_2 = df.dropna()

print(df_2)

 欠損値を含む列をすべて消去したい場合は dropna() に axis=1 または axis="columns" を渡します。

# リストPD21-3

# 欠損値を含む列をすべて削除
df_3 = df.dropna(axis=1)

print(df_3)
         age
Allan     27
Jeff      15
Conrad    40
Rowland   35
William   14
Thomas    27
Stewart   19
Roy       31
Brendan   23
Scott     10

 次のデータ操作を解説するために、df の "Scott" の行をすべて NAN に置き換えておきます。

# リストPD21-4

# Scottの行をすべて NAN に置き換える
df.loc["Scott"] = np.nan

print(df)
          age  height  weight
Allan    27.0  184.18   77.11
Jeff     15.0     NaN   58.74
Conrad   40.0  160.50   70.04
Rowland  35.0  162.70     NaN
William  14.0  164.98   56.72
Thomas   27.0     NaN     NaN
Stewart  19.0  174.01   82.58
Roy      31.0  167.49   77.04
Brendan  23.0     NaN   61.18
Scott     NaN     NaN     NaN

 dropna() はデフォルトで how="any" が設定されていて、対象とする行や列に1つでも欠損値が含まれていると除去するようになっています。how="all" に設定すると、すべての要素が欠損値となっている行や列のみを取り除きます。

# リストPD21-5

# すべての要素が欠損値となっている行を除去
df_4 = df.dropna(how="all")

print(df_4)
          age  height  weight
Allan    27.0  184.18   77.11
Jeff     15.0     NaN   58.74
Conrad   40.0  160.50   70.04
Rowland  35.0  162.70     NaN
William  14.0  164.98   56.72
Thomas   27.0     NaN     NaN
Stewart  19.0  174.01   82.58
Roy      31.0  167.49   77.04
Brendan  23.0     NaN   61.18

 引数 thresh は欠損値以外の要素の最小個数を指定します。
 たとえば、df.drpopna(thresh=2) を実行すると、欠損値以外の要素が 2 個未満である Thomas と Scott の行を取り除きます。

# リストPD21-6

# 欠損値以外の要素が2個未満の行を削除
df_5 = df.dropna(thresh=2)

print(df_5)
          age  height  weight
Allan    27.0  184.18   77.11
Jeff     15.0     NaN   58.74
Conrad   40.0  160.50   70.04
Rowland  35.0  162.70     NaN
William  14.0  164.98   56.72
Stewart  19.0  174.01   82.58
Roy      31.0  167.49   77.04
Brendan  23.0     NaN   61.18

 

fillna() 欠損値への埋め込み処理

 状況によっては、欠損値を削除せずに特定の数値や文字列を割り当てたほうがよいこともあるでしょう。fillna()メソッド は、Series と DataFrame に対して欠損値の埋め込み処理を実行します。fillna() の使用例を解説するために、最初に DataFrame を作成しておきます。

# リストPD22-1

import numpy as np
import pandas as pd

# 2次元配列を生成
arr = np.array([[1, np.nan, 2, 3],
                [np.nan, 4, np.nan, 5],
                [6, 7, np.nan, 8]])

# DataFrameを生成
df = pd.DataFrame(arr, columns=list("abcd"))

print(df)
     a    b    c    d
0  1.0  NaN  2.0  3.0
1  NaN  4.0  NaN  5.0
2  6.0  7.0  NaN  8.0

 fillna() を使って、すべての欠損値に同じ値を割り当てることができます。

# リストPD22-2

# すべての欠損値に0を割り当てる
df_10 = df.fillna(0)

print(df_10)
     a    b    c    d
0  1.0  0.0  2.0  3.0
1  0.0  4.0  0.0  5.0
2  6.0  7.0  0.0  8.0

 method="ffill" を渡すと、行または列に沿って1つ先の値を欠損値に割り当てます。

# リストPD22-3

# 行に沿って1つ先の値を割り当てる
df_11 = df.fillna(method="ffill", axis=1)

print(df_11)
     a    b    c    d
0  1.0  1.0  2.0  3.0
1  NaN  4.0  4.0  5.0
2  6.0  7.0  7.0  8.0

 method="bfill" を渡すと、行または列に沿って1つ後ろの値を欠損値に割り当てます。

# リストPD22-4

# 行に沿って1つ後ろの値を割り当てる
df_12 = df.fillna(method="bfill", axis=0)

print(df_12)
     a    b    c    d
0  1.0  4.0  2.0  3.0
1  6.0  4.0  NaN  5.0
2  6.0  7.0  NaN  8.0

 

isnull(), notnull() 欠損値の検出

 欠損値を含む DataFrame を生成します。

# リストPD23-1

import numpy as np
import pandas as pd

# 2次元配列を生成
arr = np.array([[1, np.nan],
                [None, "a"]])

# DataFrameを生成
df = pd.DataFrame(arr, columns=list("AB"))

print(df)
      A    B
0     1  NaN
1  None    a

 isnull()メソッドは欠損値を True, それ以外の値を False とするブール配列を返します。

# リストPD23-2

# 欠損値をTrueとするブール値配列を生成
b1 = df.isnull()

print(b1)
       A      B
0  False   True
1   True  False

 notnull()メソッドは欠損値を False, それ以外の値を True とするブール配列を返します。

# リストPD23-3

# 欠損値をFalseとするブール値配列を生成
b2 = df.notnull()

print(b2)
       A      B
0   True  False
1  False   True