3秒でわかる
データの中で値が入っていない箇所のこと。放置すると集計や機械学習が壊れるため、数える・埋める・落とすの判断が必要になります。
もう少し詳しく
どういうものか
欠損値は、本来値があるはずの場所に値が入っていない状態を指します。pandas では NaN(Not a Number)、None、日時型なら NaT として表現されます。アンケートの未回答、センサーの通信断、結合で相手が見つからなかった行など、発生源はさまざまです。
NaN は浮動小数点の特殊な値で、自分自身とも等しくなりません。そのため x == np.nan は常に False になり、判定には専用の関数を使います。
なぜ必要か
欠損を意識せずに処理を進めると、結果が静かに歪みます。平均を取れば欠損行は分母から外れ、対象者数が変わったことに気づけません。列同士の割り算をすれば NaN が伝播し、最終的な集計だけが空になります。機械学習の学習器の多くは欠損があると実行時に失敗します。
そして欠損そのものが情報を持つ場合があります。「年収の未回答」が特定の層に偏っていれば、0 で埋めた瞬間にその偏りを消してしまいます。
具体例
import pandas as pd
import numpy as np
df = pd.DataFrame({
"name": ["佐藤", "鈴木", "高橋", "田中"],
"age": [28, np.nan, 41, 35],
"score": [80, 92, np.nan, np.nan],
})
print(df.isna().sum()) # 列ごとの欠損数
print(df["score"].mean()) # 86.0 (欠損の 2 行は分母に入らない)
df_dropped = df.dropna(subset=["score"]) # score が欠損の行を落とす
df_filled = df.fillna({"age": df["age"].median(), "score": 0})
df["score_missing"] = df["score"].isna() # 欠損だったことを列に残すisna().sum() で場所と量を把握してから、埋めるか落とすかを決めます。埋めた場合は、埋めた事実をフラグ列として残しておくと後の分析で効きます。
つまずきやすいところ
df["age"] == np.nan で欠損を探すと、1 件も引っかからないのにエラーも出ません。判定は isna() を使います。
fillna(0) を全列に一括で当てるのも危険です。気温の欠損を 0 で埋めると、氷点下の観測として平均を引き下げます。数量なら 0、連続値なら中央値、カテゴリなら「不明」という値、というように列ごとに決めます。
CSV の読み込み時には、空欄以外に -、NA、不明 といった文字列が欠損を表している場合があります。そのままでは文字列として読まれ、列全体が object 型になって数値計算ができません。pd.read_csv(path, na_values=["-", "不明"]) のように指定します。
似た用語との違い
| 用語 | 内容 |
|---|---|
| 欠損値 | 値が存在しない |
| 外れ値 | 値はあるが分布から極端に離れている |
| 空文字 | 長さ 0 の文字列。pandas では欠損として数えられない |
覚え方
欠損は「消す前に数える」。件数と偏りを見てから、埋めるか落とすかを決めます。