Python | データ処理:欠損値 fillna

Python Python
スポンサーリンク
  1. 概要(fillnaは「欠損値を意図した値で埋めて分析を続行する」ための入口)
  2. 基本の使い方(SeriesとDataFrameで書き分ける)
    1. Seriesでの最小例(固定値で埋める)
    2. DataFrameで列ごとに埋める(辞書指定)
  3. よく使う補完方法(固定値・前後補完・統計量・グループ別)
    1. 固定値で埋める(ビジネスルールに基づく)
    2. 直前・直後の値で埋める(時系列の穴埋め)
    3. 平均・中央値などの統計量で埋める(分布に合わせる)
    4. グループ別統計で埋める(より精度の高い補完)
  4. 重要ポイントの深掘り(dtype・inplace・欠損の種類・時系列整形)
    1. dtype(型)が変わりうることを理解する
    2. inplaceは使いすぎない(明示的代入が安全)
    3. 欠損のバリエーション(NaN/None/pd.NA)
    4. 時系列の前処理とセットで考える
  5. 実践例(ユーザー情報・時系列・条件付き補完・複合ロジック)
    1. ユーザー情報の整備(文字列の欠損を安全に)
    2. 時系列センサーの穴埋め(前後補完+統計で仕上げ)
    3. 条件付きで埋める(文脈に応じた補完)
    4. 複合ロジック(数値・文字の同時整備)
  6. つまずき対策(ゼロと空文字の混同・全欠損・dropnaとの使い分け)
    1. ゼロと空文字は“意味が違う”
    2. 全欠損列は補完より削除を検討
    3. dropnaとの使い分けを決める
  7. まとめ(「何で埋めるか」「型を確定」「処理順」を決めれば怖くない)

概要(fillnaは「欠損値を意図した値で埋めて分析を続行する」ための入口)

pandasのfillnaは、DataFrameやSeriesに含まれる欠損値(NaN/None/pd.NA)を、固定値・前後の値・統計量などで置き換えるメソッドです。欠損のままだと集計や機械学習で落ちることがあり、早めに意味のある値へ補完して“計算可能な状態”に整えるのが定石です。初心者は「何で埋めるか(ルール)」「型がどう変わるか(dtype)」「いつ埋めるか(処理順)」を押さえると迷いません。


基本の使い方(SeriesとDataFrameで書き分ける)

Seriesでの最小例(固定値で埋める)

import pandas as pd
import numpy as np

s = pd.Series([1, np.nan, 3])
out = s.fillna(0)
print(out)
# 0    1.0
# 1    0.0
# 2    3.0
Python

各要素の欠損を指定値で置き換えます。数値なら0、文字列なら空文字や「不明」などが定番です。

DataFrameで列ごとに埋める(辞書指定)

df = pd.DataFrame({
    "age": [28, None, 35],
    "city": ["Tokyo", None, "Osaka"]
})

out = df.fillna({"age": 30, "city": "unknown"})
print(out)
#    age     city
# 0   28    Tokyo
# 1   30  unknown
# 2   35    Osaka
Python

列ごとに適切な置き換え値を指定できます。意味に合う“置き換えポリシー”を列ごとに決めるのが安全です。


よく使う補完方法(固定値・前後補完・統計量・グループ別)

固定値で埋める(ビジネスルールに基づく)

df["email"] = df["email"].fillna("unknown@example.com")
Python

「欠損=未登録」のように意味が明確なときは固定値が最もシンプルです。

直前・直後の値で埋める(時系列の穴埋め)

ts = pd.Series([1.2, None, None, 1.5])
ff = ts.fillna(method="ffill")  # 前方補完(直前値)
bf = ts.fillna(method="bfill")  # 後方補完(直後値)
Python

センサー値や連続的な指標は前後の値で滑らかに補完します。「トレンドを保つ」なら前方、「最初の穴埋め」なら後方が有効です。

平均・中央値などの統計量で埋める(分布に合わせる)

df["age"] = df["age"].fillna(df["age"].median())
Python

外れ値に強い中央値(median)が実務では扱いやすいことが多いです。平均(mean)は分布の偏りに注意します。

グループ別統計で埋める(より精度の高い補完)

df = pd.DataFrame({
    "sex": ["M","F","F","M","F"],
    "age": [28, None, 35, None, 32]
})

df["age"] = df.groupby("sex")["age"].transform(lambda s: s.fillna(s.median()))
print(df)
Python

全体の中央値より「グループ(例:性別や地域)ごとの中央値」で補完すると、文脈に合った値になり精度が上がります。


重要ポイントの深掘り(dtype・inplace・欠損の種類・時系列整形)

dtype(型)が変わりうることを理解する

数値列を0で埋めると浮動小数に落ちる、文字列を混ぜるとobject型になるなど、fillna後にdtypeが変化します。集計や学習前にastypeで明示的に型を確定させると安全です。

df["age"] = df["age"].fillna(0).astype("int64")
Python

inplaceは使いすぎない(明示的代入が安全)

# 悪い例: df.fillna(0, inplace=True)(読み手に副作用がわかりづらい)
# 良い例:
df = df.fillna(0)
Python

明示的に代入した方が可読性とテスト容易性が高まります。

欠損のバリエーション(NaN/None/pd.NA)

pandasは浮動小数の欠損をNaN、PythonのNone、拡張型のpd.NAを扱います。fillnaはまとめて処理できますが、文字列列のNoneはstripなどで扱う際に先にfillna(“”)で空文字へ正規化すると安全です。

時系列の前処理とセットで考える

欠損補完は「並び替え(sort_values)」「等間隔化(resample)」「前後補完(ffill/bfill)」の順で行うと安定します。日付列はto_datetimeで先に変換してから補完しましょう。

df["date"] = pd.to_datetime(df["date"])
df = df.sort_values("date").set_index("date").resample("D").asfreq()
df["sales"] = df["sales"].fillna(method="ffill")
Python

実践例(ユーザー情報・時系列・条件付き補完・複合ロジック)

ユーザー情報の整備(文字列の欠損を安全に)

df = pd.DataFrame({"name": [" Taro", None], "email": ["taro@example.com ", ""]})
df["name"]  = df["name"].fillna("").str.strip().str.title()
df["email"] = df["email"].fillna("").str.strip().str.lower()
df.loc[df["email"] == "", "email"] = "unknown@example.com"
print(df)
Python

文字列はまず空文字へ正規化→整形→最後にポリシーで置き換えると、欠損が混じっても壊れません。

時系列センサーの穴埋め(前後補完+統計で仕上げ)

ts = pd.Series([1.1, None, 1.3, None, None, 1.4])
ts = ts.fillna(method="ffill").fillna(method="bfill")
# まだ不自然なら、全体中央値で最終補完
ts = ts.fillna(ts.median())
print(ts)
Python

段階的に「前→後→統計量」で埋めると、過剰な歪みを避けつつ実務に耐える値へ落ち着きます。

条件付きで埋める(文脈に応じた補完)

df = pd.DataFrame({"category": ["A","B","A","B"], "score": [80, None, None, 70]})

for cat, med in df.groupby("category")["score"].median().items():
    df.loc[(df["category"] == cat) & (df["score"].isna()), "score"] = med

print(df)
Python

fillnaだけで表現しづらい「条件別置換」は、locとisnaを組み合わせると明確に書けます。

複合ロジック(数値・文字の同時整備)

df = pd.DataFrame({"qty": [10, None, 5], "status": [None, "ok", None]})
df["qty"]    = df["qty"].fillna(0).astype(int)
df["status"] = df["status"].fillna("unknown")
Python

列ごとに“意味のある”デフォルトへ寄せ、その後の集計・可視化で安定化させます.


つまずき対策(ゼロと空文字の混同・全欠損・dropnaとの使い分け)

ゼロと空文字は“意味が違う”

数値列の0は“存在する値”、文字列の””は“空の文字”。混同すると集計が歪みます。数値は0、文字列は”unknown”や空文字を使い分けて、意味を一貫させましょう。

全欠損列は補完より削除を検討

全部NaNの列は情報を持たないため、dropna(axis=1, how=”all”)で削除してシンプルにするのも選択肢です。残すなら、ビジネス上のデフォルトを明示してfillnaで埋めます。

dropnaとの使い分けを決める

行・列ごとに「欠損が多すぎて信頼できない」ならdropna、残したいが“計算可能”にしたいならfillna。分析の目的に合わせてポリシーを統一すると、後工程が安定します。


まとめ(「何で埋めるか」「型を確定」「処理順」を決めれば怖くない)

fillnaは、欠損値を固定値・前後補完・統計量・グループ別統計で埋めるための基本メソッドです。補完後のdtypeを必ず確認・必要に応じてastypeで確定し、時系列は並び替えと等間隔化の後にffill/bfillを適用する。文字列は空文字で正規化してから意味ある値へ置き換え、複雑な条件はloc+isnaで明示する。最初に「埋め方のポリシー」を決めて徹底すれば、初心者でも“正確で再現性のある”欠損処理を安定して実行できます。

タイトルとURLをコピーしました