Pythonでデータ分析をしていると、必ずといっていいほど出会うのが「NaN(ナン)」という値です。「計算がうまくいかない」「グラフが変になった」という経験はありませんか?
この記事では、pandasでのNaN処理を基本から応用まで、実際のコード例とともにわかりやすく解説します。
NaNって何?データ分析での欠損値の意味

NaNの正体を理解しよう
「NaN」とは「Not a Number」の略で、「数値ではない」という意味です。簡
単にいうと、「データがない」「不明」「空っぽ」を表す特別な値なのです。
pandasでは、このような場面でNaNが登場します:
import pandas as pd
import numpy as np
# サンプルデータを作ってみよう
df = pd.DataFrame({
'名前': ['田中', '鈴木', None], # Noneは自動的にNaNになる
'年齢': [25, np.nan, 30], # np.nanも明示的にNaN
'身長': [170, 165, np.nan]
})
print(df)
このコードを実行すると、None
やnp.nan
が入力された部分はNaN
として表示されます。
なぜNaNが発生するの?
実際のデータ分析では、次のような理由でNaNが発生します:
よくある原因
- CSVファイルに空白セルがある
- アンケートで「未回答」や「無効回答」がある
- センサーの故障でデータが取得できない
- 計算で無効な結果が出る(例:0で割る計算)
具体例で見てみよう
# 実際のデータっぽい例
df_real = pd.DataFrame({
'ユーザーID': [1, 2, 3, 4],
'年収': [400, np.nan, 600, 350], # 年収未回答
'年齢': [25, 30, np.nan, 28], # 年齢未回答
'地域': ['東京', '大阪', '福岡', np.nan] # 地域未記入
})
このように、実際のデータには必ずといっていいほどNaNが含まれています。
NaNを見つける方法|欠損値の検出テクニック

データにNaNがあるかどうかを確認する方法を覚えましょう。
基本的な検出方法
全体の欠損状況を確認
# NaNがある場所をTrue/Falseで表示
print(df.isna())
# 各列の欠損数を数える
print(df.isna().sum())
より詳しい情報を取得
# データの基本情報を表示(欠損数も含む)
print(df.info())
# 欠損率を計算
missing_rate = (df.isna().sum() / len(df)) * 100
print(f"欠損率: {missing_rate}%")
欠損がある行を抽出する
# 年齢が欠損している行だけを表示
age_missing = df[df['年齢'].isna()]
print(age_missing)
# どこかの列に欠損がある行をすべて表示
any_missing = df[df.isna().any(axis=1)]
print(any_missing)
# すべての列に欠損がない行だけを表示
no_missing = df[df.notna().all(axis=1)]
print(no_missing)
これらの方法を使えば、データのどこに問題があるかを素早く把握できます。
NaNを処理する3つの方法

NaNが見つかったら、次は処理方法を選択します。主に3つのアプローチがあります。
方法1:削除する
メリット: シンプルで確実 デメリット: データが減ってしまう
# 欠損がある行をすべて削除
df_dropped = df.dropna()
# 特定の列だけを対象にして削除
df_age_dropped = df.dropna(subset=['年齢'])
# 欠損がある列を削除
df_col_dropped = df.dropna(axis=1)
方法2:補完する(埋める)
メリット: データ量を維持できる デメリット: 推測に基づくため、精度に影響する可能性
# 平均値で補完
df['年齢'].fillna(df['年齢'].mean(), inplace=True)
# 中央値で補完
df['年齢'].fillna(df['年齢'].median(), inplace=True)
# 固定値で補完
df['年齢'].fillna(0, inplace=True)
# 前の値で補完
df.fillna(method='ffill', inplace=True)
# 後の値で補完
df.fillna(method='bfill', inplace=True)
方法3:特別な値として扱う
メリット: 「データがない」という情報も活用できる デメリット: 後の処理で特別な配慮が必要
# NaNを特別な値(-1など)に変換
df['年齢'].fillna(-1, inplace=True)
# カテゴリ変数の場合は「不明」などに変換
df['地域'].fillna('不明', inplace=True)
NaNがあるときの計算の注意点

NaNがあると、計算結果が予想と違うことがあります。
基本的な計算の挙動
# サンプルデータ
ages = pd.Series([25, np.nan, 30, 35])
# 多くの関数はNaNを自動的に無視します
print(f"合計: {ages.sum()}") # 90 (NaNは無視)
print(f"平均: {ages.mean()}") # 30.0 (NaNは無視)
print(f"最大: {ages.max()}") # 35 (NaNは無視)
# ただし、データ数にはNaNも含まれます
print(f"データ数: {len(ages)}") # 4 (NaNも数える)
print(f"有効数: {ages.count()}") # 3 (NaNは数えない)
NaNとの比較は特殊
# NaN同士は「等しくない」と判定される
print(np.nan == np.nan) # False
# NaNかどうかを調べるときは isna() を使う
print(pd.isna(np.nan)) # True
# 間違った書き方
wrong_filter = df[df['年齢'] == np.nan] # 何も取得できない
# 正しい書き方
correct_filter = df[df['年齢'].isna()] # NaNの行を取得
よくあるミスと解決方法
ミス1:空文字とNaNを混同する
# 問題のあるデータ
df_messy = pd.DataFrame({
'名前': ['田中', '', '鈴木', np.nan]
})
# 空文字('')とNaNは別物
print(df_messy.isna().sum()) # 1つだけ(np.nanのみ)
# 空文字をNaNに統一
df_messy['名前'].replace('', np.nan, inplace=True)
print(df_messy.isna().sum()) # 2つ(空文字もNaNになった)
ミス2:fillnaが効かない
# 間違った書き方(元のDataFrameは変更されない)
df['年齢'].fillna(0)
print(df) # まだNaNが残っている
# 正しい書き方1: inplace=True を使う
df['年齢'].fillna(0, inplace=True)
# 正しい書き方2: 結果を代入する
df['年齢'] = df['年齢'].fillna(0)
ミス3:型の不整合
# 数値列に文字列で補完すると型が変わる
df['年齢'].fillna('不明', inplace=True)
print(df.dtypes) # 年齢がobject型(文字列型)になってしまう
# 解決策:事前に型を統一するか、適切な値で補完
df['年齢'].fillna(-1, inplace=True) # 数値で補完
まとめ
pandasでのNaN処理は、データ分析の基本中の基本です。
覚えておきたいポイント
- NaNの検出:
isna()
、sum()
、info()
を活用 - 処理方法の選択: 削除・補完・特別値のどれが適切か考える
- 計算時の注意: NaNは自動的に無視されることが多い
- 比較の注意:
== np.nan
ではなくisna()
を使う
コメント