概要(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")
Pythoninplaceは使いすぎない(明示的代入が安全)
# 悪い例: 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)
Pythonfillnaだけで表現しづらい「条件別置換」は、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で明示する。最初に「埋め方のポリシー」を決めて徹底すれば、初心者でも“正確で再現性のある”欠損処理を安定して実行できます。
