pandasを使って読み込んだデータを処理する時に、
必ずと言っても良いほど向き合わなければいけないのが欠損値(NaN
)の処理。
今回は備忘録としてよく利用する機能を簡易的にまとめてみた。
今回扱うデータ
今回読み込むデータはこちら。
id | name | color | price | country |
1 | apple | red | 200 | |
2 | strawberry | red | 300 | |
3 | banana | yellow | 214 | |
4 | meron | green | 3000 | |
5 | orange | 1280 | ||
6 | grape | purple |
$ cat sample.csv
id,name,color,price,country
1,apple,red,200,
2,strawberry,red,300,
3,banana,yellow,214,
4,meron,green,3000,
5,orange,,1280,
6,grape,purple,,
欠損値がいくつか入っている状態のcsvファイルを用意した。
準備
まずはデータの読み込み。
>>> import pandas as pd
>>> df = pd.read_csv('sample.csv')
>>> df
id name color price country
0 1 apple red 200.0 NaN
1 2 strawberry red 300.0 NaN
2 3 banana yellow 214.0 NaN
3 4 meron green 3000.0 NaN
4 5 orange NaN 1280.0 NaN
5 6 grape purple NaN NaN
>>>
欠損値の状態確認
実務では上記のような少ないデータ数を扱うことはない。
全部目視で確認するのが大変なほど大量なデータを扱うはずである。
そのため、データの中身を確認し、どこにどれくらい欠損値が入っているのかを確認する必要がある。
欠損値をTrue/Falseで確認する
欠損値をTrue/False表記で確認したい場合、isnull()
メソッドを利用する。
>>> df.isnull()
id name color price country
0 False False False False True
1 False False False False True
2 False False False False True
3 False False False False True
4 False False True False True
5 False False False True True
>>>
- 欠損値:True
- 欠損値ではない:False
で表現されていることが分かる。
欠損値の数を数える
上記のisnull()
メソッドを利用すると、集計も可能である。
>>> df.isnull().sum()
id 0
name 0
color 1
price 1
country 6
dtype: int64
>>> df.shape
(6, 5)
>>>
isnull()
でTrue/False形式に変換sum()
で集計
という順序で欠損値の数を確認できる。
この場合、「shape()
メソッドの結果と一致している=全て欠損値の列」となる。
countryに関して、shapeの結果とisnull().sum()
の結果が一致していることが確認できる。
欠損値ではない数を数える
欠損値ではない数を数える場合は、count()
メソッドを利用する。
>>> df.count()
id 6
name 6
color 5
price 5
country 0
dtype: int64
>>> df.shape
(6, 5)
>>>
この場合、「0
と表示されている=全て欠損値の列」となる。
countryが0となっていて、全てが欠損値であることが確認できる。
特定列にある欠損値の出現頻度を一覧で見る
ユニークな要素の出現頻度を数えるvalue_counts()
メソッドを使うと
特定列のNaNを含めた出現頻度を見ることができる。
欠損値を含めて数えるためには、引数に「dropna=False
」を指定する必要がある。
>>> df
id name color price country
0 1 apple red 200.0 NaN
1 2 strawberry red 300.0 NaN
2 3 banana yellow 214.0 NaN
3 4 meron green 3000.0 NaN
4 5 orange NaN 1280.0 NaN
5 6 grape purple NaN NaN
>>> df['color'].value_counts()
red 2
yellow 1
green 1
purple 1
Name: color, dtype: int64
>>> df['color'].value_counts(dropna=False)
red 2
NaN 1
yellow 1
green 1
purple 1
Name: color, dtype: int64
>>>
このメソッドはDataFrameのような2次元の状態では利用できない点に注意する。
データの基本情報から判断する
データの詳しい情報を見るためのinfo()
メソッドを利用すると、
データの概要とともに欠損値についても確認ができる。
>>> df
id name color price country
0 1 apple red 200.0 NaN
1 2 strawberry red 300.0 NaN
2 3 banana yellow 214.0 NaN
3 4 meron green 3000.0 NaN
4 5 orange NaN 1280.0 NaN
5 6 grape purple NaN NaN
>>> df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 6 entries, 0 to 5
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 id 6 non-null int64
1 name 6 non-null object
2 color 5 non-null object
3 price 5 non-null float64
4 country 0 non-null float64
dtypes: float64(2), int64(1), object(2)
memory usage: 368.0+ bytes
>>>
RangeIndex
でデータサイズが分かるので、non-nullの数と見比べて、
どれくらい欠損値があるのかを確認できる。
欠損値への操作
欠損値の状態が確認できたところで、欠損値への操作を行う。
大抵の場合、以下のどちらかの対応になる。
- 欠損値を除外する
- 欠損値を何か別の値で埋める
全てが欠損値である列を削除する
今回のデータはcountry
の列が全て欠損値となっている。
この列は何の意味も持たない列なので、削除したい。
欠損値の削除を行う場合はdropna()
メソッドを利用する。
このメソッドに下記の引数を組み合わせて実現する。
- 列方向に削除したい:
axis=1
を指定 - 全ての値が欠損値であるものを削除したい:
how='all'
を指定
>>> df
id name color price country
0 1 apple red 200.0 NaN
1 2 strawberry red 300.0 NaN
2 3 banana yellow 214.0 NaN
3 4 meron green 3000.0 NaN
4 5 orange NaN 1280.0 NaN
5 6 grape purple NaN NaN
>>> df.dropna(axis=1, how='all')
id name color price
0 1 apple red 200.0
1 2 strawberry red 300.0
2 3 banana yellow 214.0
3 4 meron green 3000.0
4 5 orange NaN 1280.0
5 6 grape purple NaN
>>>
ところどころにNaNが含まれているcolorやpriceは削除されなかったが、
全てNaNで埋め尽くされているcountryは削除されたことが分かる。
特定の列の欠損値を補完する
今回の場合、全てのcountry=Japanとしたい場合、下記のようにfillna()
メソッドを使って補完することができる。
>>> df
id name color price country
0 1 apple red 200.0 NaN
1 2 strawberry red 300.0 NaN
2 3 banana yellow 214.0 NaN
3 4 meron green 3000.0 NaN
4 5 orange NaN 1280.0 NaN
5 6 grape purple NaN NaN
# countryの列だけ抽出して、fillna()メソッドを適用する
>>> df['country'].fillna('Japan')
0 Japan
1 Japan
2 Japan
3 Japan
4 Japan
5 Japan
Name: country, dtype: object
# 適用した結果で再代入する
>>> df['country'] = df['country'].fillna('Japan')
>>> df
id name color price country
0 1 apple red 200.0 Japan
1 2 strawberry red 300.0 Japan
2 3 banana yellow 214.0 Japan
3 4 meron green 3000.0 Japan
4 5 orange NaN 1280.0 Japan
5 6 grape purple NaN Japan
>>>
2次元のDataFrameそのものに対して適用してしまうと、
特定の行だけではなく全ての欠損値が補完されてしまうため注意。
>>> df
id name color price country
0 1 apple red 200.0 NaN
1 2 strawberry red 300.0 NaN
2 3 banana yellow 214.0 NaN
3 4 meron green 3000.0 NaN
4 5 orange NaN 1280.0 NaN
5 6 grape purple NaN NaN
>>> df.fillna('HOGE')
id name color price country
0 1 apple red 200.0 HOGE
1 2 strawberry red 300.0 HOGE
2 3 banana yellow 214.0 HOGE
3 4 meron green 3000.0 HOGE
4 5 orange HOGE 1280.0 HOGE
5 6 grape purple HOGE HOGE
>>>
まとめ
- 欠損値の数を数える:
isnull().sum()
,count()
,value_counts()
など - 欠損値を削除する:
dropna()
- 欠損値を補完する:
fillna()