データは常に完全ではなく、欠損値が混じっているなどすぐ分析に使える状態でないことは多々あります。データに欠損があると、分析における様々な処理に支障がでます。
欠損があるときは、そのデータ項目を削除したり、ルールを決めて欠損値を補完する場合が多いです。
今回は、Pandasのデータフレームで欠損値を補完する方法を紹介していきます。
データにブランクが含まれているの、あるあるなんですよね~~
そういったデータをどのように扱うか?もデータ分析において重要だな。
Pandasバージョン
本記事は、Pandas2.2.3の情報を基に執筆しています。
import pandas as pd
print(pd.__version__)
>>
2.2.3
使用するデータフレーム
今回は以下の欠損値(NAN及びNone)を含むデータフレームをサンプルに使用します。
import pandas as pd
df = pd.DataFrame(
data={"A":[1,3,None,None,None,11],
"B":["dog", "cat", "monkey", None, "rabbit", None],
"C":["a", None, "c", "d", "e", "f"],
"D":[None,None,None,None,None,None]})
>>
A B C D
0 1.0 dog a None
1 3.0 cat None None
2 NaN monkey c None
3 NaN None d None
4 NaN rabbit e None
5 11.0 None f None
データフレームの欠損を補完する手法
データフレームの欠損を補完するメソッドは、主にfillna()を用います。引数を操作することで、ルールに則った補完ができます。
以下に、様々な補完方法をまとめます。
全ての欠損を同じ値で補完
すべての欠損値を同じ値で補完する場合は、fillna()の引数に数値や文字列を渡します。
引数に0を渡すと、すべての欠損値が0に置換されます。
df1 = df.copy()
#すべての欠損値を0で置換
df1 = df1.fillna(0)
>>
A B C D
0 1.0 dog a 0
1 3.0 cat 0 0
2 0.0 monkey c 0
3 0.0 0 d 0
4 0.0 rabbit e 0
5 11.0 0 f 0
文字列で補完することもできます。
df1 = df1.fillna("elephant")
>>
A B C D
0 1.0 dog a elephant
1 3.0 cat elephant elephant
2 elephant monkey c elephant
3 elephant elephant d elephant
4 elephant rabbit e elephant
5 11.0 elephant f elephant
列ごとに値を指定して補完
辞書で値を指定して補完
fillna()に辞書 {列名 : 補完したい値}を渡すことで、列ごとに指定した値で欠損を置換することができます。
df2 = df.copy()
#列ごとに値を指定して置換(辞書)
df2 = df2.fillna({"A":"lion", "B":"lion", "C":"b", "D":"b"})
>>
A B C D
0 1.0 dog a b
1 3.0 cat b b
2 lion monkey c b
3 lion lion d b
4 lion rabbit e b
5 11.0 lion f b
列ごとに異なる型で補完することも可能ですが、今後使用できなくなるようです。
df2 = df.copy()
#列ごとに値を指定して置換(辞書)
df2 = df2.fillna({"A":10, "B":"lion", "C":"b", "D":5})
>>
A B C D
0 1.0 dog a 5
1 3.0 cat b 5
2 10.0 monkey c 5
3 10.0 lion d 5
4 10.0 rabbit e 5
5 11.0 lion f 5
FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version.
Seriesで値を指定して補完
Series形式で列ごとに置換したい値を指定することもできます。
Seriesはインデックスが列名、値には置換したい値が入ります。
fill_series = pd.Series(["lion", "lion", "z", "z"], index=["A", "B", "C", "D"])
>>
A lion
B lion
C z
D z
dtype: object
作成したSeriesを、fillna()の引数として渡します。
df2 = df.copy()
df2 = df2.fillna(fill_series)
>>
A B C D
0 1.0 dog a z
1 3.0 cat z z
2 lion monkey c z
3 lion lion d z
4 lion rabbit e z
5 11.0 lion f z
統計量で補完
データフレームの統計量をfillna()に渡すと、その統計量で欠損を置換することができます。ただし、置換できるのは数値型の列に限られます。
今回紹介する統計量以外(標準偏差等)でももちろん置換可能です。
平均値で補完
df3 = df.copy()
#各列の平均値で置換
df3 = df3.fillna(df.mean(numeric_only=True))
>>
A B C D
0 1.0 dog a None
1 3.0 cat None None
2 5.0 monkey c None
3 5.0 None d None
4 5.0 rabbit e None
5 11.0 None f None
最大値で補完
df3 = df.copy()
#各列の平均値で置換
df3 = df3.fillna(df.max(numeric_only=True))
>>
A B C D
0 1.0 dog a None
1 3.0 cat None None
2 11.0 monkey c None
3 11.0 None d None
4 11.0 rabbit e None
5 11.0 None f None
前後の値で補完
欠損の前後の値で補完することもできます。前後の値で補完する場合は、fillna()ではなく、ffill()やbfill()を使用します。
fillna()のmethodで"ffill"や"bfill"を指定する方法がありますが、今後サポートされなくなるため非推奨です。
前の値で補完
前の値で欠損を補完する場合は、ffill()を使用します。
D列のように先頭行から欠損が続く場合は補完できません。
df4 = df.copy()
#前の値で置換
df4 = df4.ffill()
>>
A B C D
0 1.0 dog a None
1 3.0 cat a None
2 3.0 monkey c None
3 3.0 monkey d None
4 3.0 rabbit e None
5 11.0 rabbit f None
後ろの値で補完
後ろの値で欠損を補完する場合はffill()を使用します。
ffill同様、D列のように最後行から欠損が続く場合は補完できません。
#後ろの値で置換
df4 = df4.fillna(method='bfill')
>>
A B C D
0 1.0 dog a None
1 3.0 cat c None
2 11.0 monkey c None
3 11.0 rabbit d None
4 11.0 rabbit e None
5 11.0 None f None
線形補完
これまでは同一列では全て同じ値で置換をしていましたが、欠損の前後の値を線形につなぐような補完もできます。
欠損の線形補完にはinterpolate()を用います。
df5 = df.copy()
#線形補完
df5 = df5.interpolate()
>>
A B C D
0 1.0 dog a None
1 3.0 cat None None
2 5.0 monkey c None
3 7.0 None d None
4 9.0 rabbit e None
5 11.0 None f None
C:\Users\dadad\AppData\Local\Temp\ipykernel_25504\1058585604.py:3: FutureWarning: DataFrame.interpolate with object dtype is deprecated and will raise in a future version. Call obj.infer_objects(copy=False) before interpolating instead.
df5 = df5.interpolate()
A列を見ると、欠損の前後の値を線形に補完するような値に置換されています。この方法は、数値型以外の列や全て欠損の列には適用できません。
線形補完にならない場合
また、数値型の列でも、欠損の前に数値がない場合や後ろに数値がない場合は線形補完されません(当たり前ですが)。欠損の前に値がない場合はffill、後ろに値がない場合はbfillでの置換と同様の結果が得られます。以下の例(A列)は欠損の後ろに値存在しないため、線形補完ではなくffillと同様の結果が得られます。
df = pd.DataFrame(
data={"A":[1,3,None,None,None,None],
"B":["dog", "cat", "monkey", None, "rabbit", None],
"C":["a", None, "c", "d", "e", "f"],
"D":[None,None,None,None,None,None]})
df = df.interpolate()
>>
A B C D
0 1.0 dog a None
1 3.0 cat None None
2 3.0 monkey c None
3 3.0 None d None
4 3.0 rabbit e None
5 3.0 None f None
Pythonでデータサイエンスするなら
Pythonでデータサイエンスをするなら、以下の書籍がおすすめです。Pandas、matplotlib、Numpy、scikit-learnといったデータサイエンスに必要なライブラリを、体系立てて一通り学ぶことができます。
ややお値段高めですが、これ1冊で十分という内容・ボリュームなので、損はしないと思います^^
まとめ
データフレームの欠損を補完する方法を紹介しました。様々な方法で欠損処理ができるので、その時々に応じてデータの前処理を行ってください。
どの方法で欠損値を埋めるかは、ケースバイケースになる。ルールとして前の値で埋める場合や、データの統計量を見ながら決定する場合もある。
ここは、経験がものを言うわけですね。。
今回はここまでにしよう。
ありがとうございました~~♪