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

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をコピーしました