こんにちは、かつコーチです。
実務のデータには、必ずと言っていいほど欠損値が含まれています。
「削除すればいいのか、埋めればいいのか」で迷う方も多いと思うので、この記事ではdropnaとfillnaの使い分けを、判断基準とあわせて解説します。
欠損値とは?
欠損値(NaN)の定義
欠損値とは、本来あるはずのデータが記録されていない状態のことです。
pandasでは欠損値をNaN(Not a Number)という特別な値で表現します。
import pandas as pd
import numpy as np
df = pd.DataFrame({
"名前": ["田中", "佐藤", "鈴木"],
"年齢": [25, np.nan, 28]
})
print(df)
名前 年齢
0 田中 25.0
1 佐藤 NaN
2 鈴木 28.0
アンケートの未回答、システム連携時の取得漏れ、Excelでの入力漏れなど、欠損値が生まれる原因はさまざまです。
なぜ欠損値の処理が必要なのか
欠損値をそのままにして集計や機械学習に使うと、計算結果が意図せずNaNになったり、正確な平均値・合計値が計算できなくなったりします。
「欠損値をどう扱うか」は、分析結果の信頼性に直結する重要な工程です。
基本の書き方:dropnaとfillnaの使い方
手順1:欠損値の有無を確認する
処理を始める前に、まず欠損値がどこにどれだけあるかを確認します。
print(df.isnull().sum())
名前 0
年齢 1
dtype: int64
isnull()はNaNならTrueを返すDataFrameを作り、.sum()で列ごとの欠損数を合計しています。
手順2:dropnaで欠損値のある行を削除する
dropnaは、欠損値が含まれる行(または列)をまるごと削除するメソッドです。
df_dropped = df.dropna()
print(df_dropped)
名前 年齢
0 田中 25.0
2 鈴木 28.0
列単位で削除したい場合はaxis=1を指定します。
df_dropped_col = df.dropna(axis=1)
手順3:fillnaで欠損値を埋める
fillnaは、欠損値を指定した値で埋めるメソッドです。
df_filled = df.fillna({"年齢": df["年齢"].mean()})
print(df_filled)
名前 年齢
0 田中 25.0
1 佐藤 26.5
2 鈴木 28.0
列ごとに異なる値で埋めたい場合は、辞書形式で指定するのが便利です。
つまずきやすい設定・注意点
dropna()はデフォルトで元のDataFrameを変更せず、新しいDataFrameを返します。上書きしたい場合はdf = df.dropna()のように再代入するか、inplace=Trueを使いますfillnaで平均値を使う場合、平均を計算する前に他の欠損値処理を済ませておかないと、平均値自体がずれてしまうことがあります
dropnaとfillna、どちらを選ぶべきか
判断軸の比較表
| 観点 | dropna(削除) | fillna(埋める) |
|---|---|---|
| データ量への影響 | 行が減る=データ量が減少する | データ量を維持できる |
| 向いているケース | 欠損が少数で、削除しても分析に支障がない場合 | 欠損が多く、削除するとデータが不足する場合 |
| リスク | 重要なデータまで失う可能性がある | 埋めた値が分析結果を歪める可能性がある |
| 代表的な使い所 | ID列など必須項目が欠けている行の除外 | アンケートの未回答を平均値・中央値で補完 |
どう選べばいいか
迷ったときの判断基準はシンプルです。
- その行・列が分析に不可欠な項目で、欠損が全体の数%程度なら
dropna(多少データが減っても影響が小さいため) - 欠損の割合が大きく、削除するとデータが偏ってしまうなら
fillna(平均値・中央値・0など、業務的に妥当な値で補完する)
私が実際の案件でアンケートデータを扱った際、「未回答」を安易に0で埋めてしまい、平均点が実態より大幅に低く算出されてしまったことがあります。fillna(0)は便利ですが、「0という値が業務的に何を意味するか」を考えずに使うと、分析結果を歪める原因になります。
このときは0埋めをやめ、未回答の行をdropna()で除外する方針に切り替えて、正しい平均点を算出し直しました。
よくあるつまずきポイント・エラー対処
fillnaの値が数値じゃない列にも影響してしまう
❌Before:DataFrame全体に一律の値でfillnaをかけてしまう
df_filled = df.fillna(0)
数値列だけでなく、本来空欄のままにしておきたい文字列列まで0で埋まってしまうことがあります。
✅After:列を指定して、列ごとに適切な値で埋める
df_filled = df.fillna({
"年齢": df["年齢"].mean(),
"備考": "未入力"
})
「全部まとめて処理」ではなく「列ごとの意味を考えて処理」することが、欠損値処理の基本姿勢です。
応用・一歩先の使い方
前後の値で埋める(時系列データ向け)
センサーデータや株価のような時系列データでは、前の値や後ろの値で埋める方法もよく使われます。
df_filled = df.ffill() # 前の値で埋める(forward fill)
df_filled = df.bfill() # 後ろの値で埋める(backward fill)
なお、fillna(method="ffill")という書き方は古い記事でよく見かけますが、pandas 2.x系では非推奨(FutureWarning)になっています。
2.x系ではdf.ffill()・df.bfill()のように専用メソッドを直接使う書き方が推奨されているので、新しくコードを書くときはこちらを使いましょう。
特定の列にだけdropnaを適用する
subset引数を使うと、特定の列に欠損値がある行だけを削除対象にできます。
df_dropped = df.dropna(subset=["年齢"])
「名前」列は欠損していても構わないが「年齢」列は必須、といった業務要件に対応できます。
まとめ
この記事のポイント
- 欠損値はpandasではNaNとして表現される
dropnaは欠損のある行・列を削除、fillnaは指定した値で埋める- 判断基準は「欠損の割合」と「削除して困る項目かどうか」
- 一律の値で埋めると、意味のない値が分析結果を歪めるリスクがある
- 列ごとの意味を考えて、
dropnaとfillnaを使い分ける
次に読むべき記事
欠損値の処理ができるようになったら、次はデータをグループごとに集計する「groupbyでデータをグループ化・集計する」に進みましょう。
きれいになったデータを使って、実際の集計作業に入っていきます。
タグ: Pandas, 中級者向け, データ加工