note.nkmk.me

pandasで欠損値NaNを除外(削除)・置換(穴埋め)する

Date: 2017-11-16 / tags: Python, pandas
このエントリーをはてなブックマークに追加

欠損値NaN

例えばcsvファイルをpandasで読み込んだとき、要素が空白だったりすると欠損値NaN(Not a Number)だと見なされる。

例として以下のようなcsvファイルをread_csvで読み込んで使用する。

name,age,state,point, other
Alice,24,NY,,
,,,,
Charlie,,CA,,
Dave,68,TX,70,
Ellen,,CA,88,
Frank,30,,,

pandasにおいて、欠損値はすべてNumPyの浮動小数点のNaNとなる。列に一つでもNaNが含まれていると、ほかの値がすべて整数intでもその列のdtypeは浮動小数点として処理される。

import pandas as pd

df = pd.read_csv('data/src/sample_pandas_normal_nan.csv')
print(df)
#       name   age state  point   other
# 0    Alice  24.0    NY    NaN     NaN
# 1      NaN   NaN   NaN    NaN     NaN
# 2  Charlie   NaN    CA    NaN     NaN
# 3     Dave  68.0    TX   70.0     NaN
# 4    Ellen   NaN    CA   88.0     NaN
# 5    Frank  30.0   NaN    NaN     NaN

print(df.at[0, 'point'])
print(type(df.at[0, 'point']))
# nan
# <class 'numpy.float64'>

欠損値を除外(削除)する

メソッドdropna()を使う。

デフォルトでは新しいオブジェクトを返して元のオブジェクトは変更されないが、引数inplace=Trueを指定すると元のオブジェクト自体が変更される。

すべての値が欠損値である行・列を削除する

引数how='all'を指定すると、すべての値が欠損値である行が削除される。axis=1とすると列に適用。axis=[0, 1]とすると行と列の両方に適用。

print(df.dropna(how='all'))
#       name   age state  point   other
# 0    Alice  24.0    NY    NaN     NaN
# 2  Charlie   NaN    CA    NaN     NaN
# 3     Dave  68.0    TX   70.0     NaN
# 4    Ellen   NaN    CA   88.0     NaN
# 5    Frank  30.0   NaN    NaN     NaN

print(df.dropna(how='all', axis=1))
#       name   age state  point
# 0    Alice  24.0    NY    NaN
# 1      NaN   NaN   NaN    NaN
# 2  Charlie   NaN    CA    NaN
# 3     Dave  68.0    TX   70.0
# 4    Ellen   NaN    CA   88.0
# 5    Frank  30.0   NaN    NaN

print(df.dropna(how='all', axis=[0, 1]))
#       name   age state  point
# 0    Alice  24.0    NY    NaN
# 2  Charlie   NaN    CA    NaN
# 3     Dave  68.0    TX   70.0
# 4    Ellen   NaN    CA   88.0
# 5    Frank  30.0   NaN    NaN

欠損値が一つでも含まれる行・列を削除する

引数how='any'を指定すると、欠損値が一つでも含まれる行が削除される。axis=1とすると列に適用。なお、デフォルトがhow='any'なので、何も指定しないとこの動作になる。

すべての値が欠損値である行と列を削除したデータに対して処理してみる。

df2 = df.dropna(how='all', axis=[0, 1])
print(df2)
#       name   age state  point
# 0    Alice  24.0    NY    NaN
# 2  Charlie   NaN    CA    NaN
# 3     Dave  68.0    TX   70.0
# 4    Ellen   NaN    CA   88.0
# 5    Frank  30.0   NaN    NaN

print(df2.dropna(how='any'))
#    name   age state  point
# 3  Dave  68.0    TX   70.0

print(df2.dropna(how='any', axis=1))
#       name
# 0    Alice
# 2  Charlie
# 3     Dave
# 4    Ellen
# 5    Frank

欠損値の数に応じて行・列を削除する

引数threshに個数を指定する。例えばthresh=3とすると、欠損値が3個以上含まれている行が削除される。axis=1とすると列に適用。

print(df.dropna(thresh=3))
#     name   age state  point   other
# 0  Alice  24.0    NY    NaN     NaN
# 3   Dave  68.0    TX   70.0     NaN
# 4  Ellen   NaN    CA   88.0     NaN

print(df.dropna(thresh=3, axis=1))
#       name   age state
# 0    Alice  24.0    NY
# 1      NaN   NaN   NaN
# 2  Charlie   NaN    CA
# 3     Dave  68.0    TX
# 4    Ellen   NaN    CA
# 5    Frank  30.0   NaN

特定の行・列に欠損値がある行・列を削除する

引数subsetに対象としたい行ラベル・列ラベルをリストで指定する。リストである必要があるので、対象が一つでもsubset=['name']のように指定する。

デフォルトではsubsetで指定した列に欠損値がある行を削除する。axis=1とすると、subsetで指定した行に欠損値がある列を削除する。

print(df.dropna(subset=['age']))
#     name   age state  point   other
# 0  Alice  24.0    NY    NaN     NaN
# 3   Dave  68.0    TX   70.0     NaN
# 5  Frank  30.0   NaN    NaN     NaN

print(df.dropna(subset=[0, 4], axis=1))
#       name state
# 0    Alice    NY
# 1      NaN   NaN
# 2  Charlie    CA
# 3     Dave    TX
# 4    Ellen    CA
# 5    Frank   NaN

pandas.Seriesの場合

以上はデータが二次元のpandas.DataFrameの場合だったが、データが一次元のpandas.Seriesの場合は、シンプルにdropna()を呼ぶだけでいい。欠損値が削除される。

series = df['age']
print(series)
# 0    24.0
# 1     NaN
# 2     NaN
# 3    68.0
# 4     NaN
# 5    30.0
# Name: age, dtype: float64

print(series.dropna())
# 0    24.0
# 3    68.0
# 5    30.0
# Name: age, dtype: float64

欠損値を置換(穴埋め)する

メソッドfillna()を使うと欠損値に任意の値を代入して置き換えられる。

デフォルトでは新しいオブジェクトを返して元のオブジェクトは変更されないが、引数inplace=Trueを指定すると元のオブジェクト自体が変更される。

共通の値で一律に置換する

引数に置き換えたい値を指定する。0にしたり平均値にしたりしたい場合は多いだろう。

print(df.fillna(0))
#       name   age state  point   other
# 0    Alice  24.0    NY    0.0     0.0
# 1        0   0.0     0    0.0     0.0
# 2  Charlie   0.0    CA    0.0     0.0
# 3     Dave  68.0    TX   70.0     0.0
# 4    Ellen   0.0    CA   88.0     0.0
# 5    Frank  30.0     0    0.0     0.0

行・列によって異なる値で置換する

引数に辞書を指定すると、行ラベル毎に異なる値で置き換えられる。keyを行ラベル、valueを置き換えたい値とする。指定されていない行ラベルは欠損値NaNのまま。axis=1とすると列に適用。

print(df.fillna({'name': 'XXX', 'age': 20, 'point': 0}))
#       name   age state  point   other
# 0    Alice  24.0    NY    0.0     NaN
# 1      XXX  20.0   NaN    0.0     NaN
# 2  Charlie  20.0    CA    0.0     NaN
# 3     Dave  68.0    TX   70.0     NaN
# 4    Ellen  20.0    CA   88.0     NaN
# 5    Frank  30.0   NaN    0.0     NaN

前後の値で置換する

引数methodを指定する。method='ffill'とすると前の値で置き換えられ、method='bfill'とすると後ろの値で置き換えられる。時系列データのときに便利。

print(df.fillna(method='ffill'))
#       name   age state  point   other
# 0    Alice  24.0    NY    NaN     NaN
# 1    Alice  24.0    NY    NaN     NaN
# 2  Charlie  24.0    CA    NaN     NaN
# 3     Dave  68.0    TX   70.0     NaN
# 4    Ellen  68.0    CA   88.0     NaN
# 5    Frank  30.0    CA   88.0     NaN

print(df.fillna(method='bfill'))
#       name   age state  point   other
# 0    Alice  24.0    NY   70.0     NaN
# 1  Charlie  68.0    CA   70.0     NaN
# 2  Charlie  68.0    CA   70.0     NaN
# 3     Dave  68.0    TX   70.0     NaN
# 4    Ellen  30.0    CA   88.0     NaN
# 5    Frank  30.0   NaN    NaN     NaN

最大連続置換回数を指定

引数limitで、最大何回まで連続して置換するかを指定できる。以降は欠損値NaNのまま。

print(df.fillna(method='bfill', limit=1))
#       name   age state  point   other
# 0    Alice  24.0    NY    NaN     NaN
# 1  Charlie   NaN    CA    NaN     NaN
# 2  Charlie  68.0    CA   70.0     NaN
# 3     Dave  68.0    TX   70.0     NaN
# 4    Ellen  30.0    CA   88.0     NaN
# 5    Frank  30.0   NaN    NaN     NaN
スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事