pandasの欠損値NaN・None・pd.NAの違い|isna・dropna・fillnaの使い方
pandasの欠損値は、数値の列ではNaN(np.nan)、object型の列ではNone、Int64・boolean・stringなどの「nullable型」ではpd.NAで表されます。どれもisna()で欠損として判定でき、dropna()で削除、fillna()・ffill()・bfill()で補完できます。
見た目は似ていても、3つは型も比較のふるまいも違います。この記事では、公式ドキュメント「Working with missing data」に沿って違いを整理し、検出・削除・補完のやり方を実際に動かした結果つきで説明します。コードはすべて Python 3.13・pandas 3.0.6・NumPy 2.5.4 で実行しました(2026年10月15日確認)。pandas 3.0 では文字列の列とfillnaの書き方が変わったので、古い記事のコードがそのまま動かない場合の直し方も載せています。
NaN・None・pd.NAの違い(早見表)
| 値 | どこで使われるか | 型 | 同じ値どうしの == |
|---|---|---|---|
np.nan(NaN) |
float64などNumPyの数値型。pandas 3.0では既定の文字列型(str)でも欠損はNaN | float |
False |
None |
object型の列。数値の列に入れるとNaNに置き換わる | NoneType |
True |
pd.NA |
Int64・Float64・boolean・stringなどのnullable型、ArrowDtype | NAType |
<NA>(判定不能) |
pd.NaT |
datetime64・timedelta64・Period | NaTType |
False |
公式ドキュメントでは、どの値が使われるかはデータ型(dtype)で決まると説明されています。つまり「どれを使うか」を自分で選ぶというより、列の型によって自動的に決まると考えるのが実態に近いです。判定は値そのものではなく isna() で行う、というのが3つに共通する一番大事なルールです。
NaN:数値の列の欠損値
NaN(Not a Number)は浮動小数点数の特別な値で、NumPyの np.nan として使います。整数のリストに1つでもNaNが混ざると、列全体が float64 になります。
import pandas as pd
import numpy as np
print(pd.__version__)
s = pd.Series([1, 2, np.nan, 4])
print(s)
print(type(np.nan))
実行結果:
3.0.6
0 1.0
1 2.0
2 NaN
3 4.0
dtype: float64
<class 'float'>
1・2・4 が 1.0・2.0・4.0 に変わっているのがポイントです。整数のまま欠損を持ちたい場合は、後で説明する Int64 型を使います。
None:Pythonの「値なし」
None はPython標準の「値がない」ことを表すオブジェクトです。pandasでは、どの型の列に入れたかで扱いが変わります。
import pandas as pd
s_obj = pd.Series([1, "a", None])
print(s_obj)
s_str = pd.Series(["A", "B", None, "D"])
print(s_str)
print(repr(s_str[2]))
実行結果:
0 1
1 a
2 None
dtype: object
0 A
1 B
2 NaN
3 D
dtype: str
nan
いろいろな型が混ざったobject型の列では None がそのまま残ります。一方、文字列だけの列はpandas 3.0から専用の文字列型(str)になり、None は NaN に置き換わります。公式の移行ガイド「Migration guide for the new string data type」にも、新しい文字列型では欠損値は常にNaNになると書かれています。
同じコードをpandas 2.3.3で動かすと、文字列の列も dtype: object のままで、欠損は None と表示されました。x is None で欠損を探しているコードは、pandas 3.0では見落としが出るので pd.isna(x) に書き換えてください。数値の列に None を入れた場合は、バージョンに関係なくNaNになります(次の例の最後の行)。
pd.NA:型を崩さない欠損値
pd.NA はpandas 1.0で加わった欠損値で、Int64(Iは大文字)・boolean・string などのnullable型で使われます。整数や真偽値の列に欠損があっても、型が float や object に変わりません。
import pandas as pd
s_int = pd.Series([1, 2, None, 4], dtype="Int64")
print(s_int)
print(s_int[2] is pd.NA)
s_bool = pd.Series([True, False, None], dtype="boolean")
print(s_bool)
s_plain = pd.Series([1, 2, None, 4])
print(s_plain.dtype)
実行結果:
0 1
1 2
2 <NA>
3 4
dtype: Int64
True
0 True
1 False
2 <NA>
dtype: boolean
float64
最後の行のように、dtypeを指定しないと従来どおり float64 になります。公式ドキュメントにも、nullable型は既定では使われないので dtype を明示する必要があると書かれています。なお pd.NA のふるまいは公式ドキュメント上「Experimental(実験的)」と明記されており、将来変わる可能性があります。
比較と論理演算での違い
3つの違いが一番はっきり出るのが、== での比較です。
import pandas as pd
import numpy as np
print(None == None)
print(np.nan == np.nan)
print(pd.NA == pd.NA)
print(pd.NA + 1)
print(True | pd.NA, False & pd.NA)
print(pd.isna(np.nan), pd.isna(None), pd.isna(pd.NA))
try:
if pd.NA:
pass
except TypeError as e:
print("TypeError:", e)
実行結果:
True
False
<NA>
<NA>
True False
True True True
TypeError: boolean value of NA is ambiguous
None == NoneはTrue、np.nan == np.nanはFalseになるpd.NAとの比較や計算は、結果も<NA>(わからない)になるTrue | pd.NAは、もう一方が何でも結果が決まるのでTrue(三値論理)if pd.NA:のように真偽を直接問うとTypeErrorになる
このため、Seriesを == np.nan と比べても欠損は1つも見つかりません。欠損を探すときは必ず isna() を使います。また、sum() や mean() などの集計は既定で欠損を飛ばして計算します。
import pandas as pd
import numpy as np
s = pd.Series([1.0, np.nan, 3.0])
print(s == np.nan) # 比較では見つからない
print(s.isna()) # isna() なら見つかる
print(s.sum(), s.mean()) # 集計では欠損を飛ばす
print(s.sum(skipna=False))
実行結果:
0 False
1 False
2 False
dtype: bool
0 False
1 True
2 False
dtype: bool
4.0 2.0
nan
欠損値を見つける:isna()・notna()
isna() は欠損ならTrue、notna() は欠損でなければTrueを返します。isnull()・notnull() は同じ動きをする別名です。NaN・None・pd.NAのどれが入っていても同じように判定できます。
import pandas as pd
import numpy as np
df = pd.DataFrame({
"点数": [80, np.nan, 65, np.nan],
"名前": ["佐藤", None, "鈴木", "高橋"],
"合格": pd.array([True, None, False, True], dtype="boolean"),
})
print(df)
print(df.dtypes)
print(df.isna())
print(df.isna().sum())
print(df.notna().all(axis=1))
実行結果:
点数 名前 合格
0 80.0 佐藤 True
1 NaN NaN <NA>
2 65.0 鈴木 False
3 NaN 高橋 True
点数 float64
名前 str
合格 boolean
dtype: object
点数 名前 合格
0 False False False
1 True True True
2 False False False
3 True False False
点数 2
名前 1
合格 1
dtype: int64
0 True
1 False
2 True
3 False
dtype: bool
よく使うのは次の3つです。
df.isna():セルごとの欠損の有無df.isna().sum():列ごとの欠損の個数df.notna().all(axis=1):欠損が1つもない行かどうか
列ごとの欠損以外の件数をざっと見たいときは df.info() の Non-Null Count も便利です。
欠損値を削除する:dropna()
dropna() は欠損を含む行(または列)を取り除いた新しいDataFrameを返します。元のDataFrameは変わりません。
import pandas as pd
import numpy as np
df = pd.DataFrame({
"ID": [1, 2, 3, 4],
"点数": [80, np.nan, 65, np.nan],
"名前": ["佐藤", None, "鈴木", "高橋"],
})
print(df.dropna()) # 欠損が1つでもある行を削除
print(df.dropna(subset=["名前"])) # 名前が欠けている行だけ削除
print(df.dropna(axis=1)) # 欠損を含む列を削除
print(df.dropna(thresh=3)) # 欠損でない値が3つ以上ある行を残す
実行結果:
ID 点数 名前
0 1 80.0 佐藤
2 3 65.0 鈴木
ID 点数 名前
0 1 80.0 佐藤
2 3 65.0 鈴木
3 4 NaN 高橋
ID
0 1
1 2
2 3
3 4
ID 点数 名前
0 1 80.0 佐藤
2 3 65.0 鈴木
| 書き方 | 意味 |
|---|---|
dropna() |
欠損が1つでもある行を削除 |
dropna(subset=["名前"]) |
指定した列に欠損がある行だけ削除 |
dropna(axis=1) |
欠損を含む列を削除 |
dropna(how="all") |
すべての値が欠損の行だけ削除 |
dropna(thresh=3) |
欠損でない値が3つ以上ある行を残す |
引数の一覧は公式リファレンスの DataFrame.dropna にあります。行を消すとデータ数が減るので、件数が少ないデータでは次の「補完」も検討してください。
欠損値を埋める:fillna()
fillna() は欠損を指定した値で置き換えます。列ごとに違う値で埋めたいときは辞書で渡すのが安全です。
import pandas as pd
import numpy as np
df = pd.DataFrame({
"点数": [80, np.nan, 65, np.nan],
"名前": ["佐藤", None, "鈴木", "高橋"],
})
print(df.fillna({"点数": 0, "名前": "不明"}))
print(df["点数"].fillna(df["点数"].mean()))
実行結果:
点数 名前
0 80.0 佐藤
1 0.0 不明
2 65.0 鈴木
3 0.0 高橋
0 80.0
1 72.5
2 65.0
3 72.5
Name: 点数, dtype: float64
平均値で埋める場合は、まず df["点数"].mean() で平均を求め(欠損は自動で除外されます)、その値を fillna() に渡します。中央値なら median() に置き換えます。
前後の値で埋める:ffill()・bfill()
時系列データなどで「直前の値で埋めたい」ときは ffill()、「直後の値で埋めたい」ときは bfill() を使います。
import pandas as pd
import numpy as np
s = pd.Series([10, np.nan, np.nan, 40])
print(s.ffill())
print(s.bfill())
print(s.ffill(limit=1))
try:
s.fillna(method="ffill")
except TypeError as e:
print("TypeError:", e)
実行結果:
0 10.0
1 10.0
2 10.0
3 40.0
dtype: float64
0 10.0
1 40.0
2 40.0
3 40.0
dtype: float64
0 10.0
1 10.0
2 NaN
3 40.0
dtype: float64
TypeError: NDFrame.fillna() got an unexpected keyword argument 'method'
以前の記事でよく見かける fillna(method="ffill") は、pandas 2.1で非推奨になり(What’s new in 2.1.0)、pandas 3.0では引数そのものがなくなったため TypeError になります(DataFrame.fillna の引数一覧にも method はありません)。手元のコードに残っていたら、df.ffill()・df.bfill() に置き換えてください。limit=1 を付けると、連続する欠損のうち最初の1つだけを埋められます。
まとめてnullable型にそろえる:convert_dtypes()
列ごとにdtypeを指定するのが面倒なときは convert_dtypes() が便利です。公式リファレンスの説明どおり、pd.NAを扱える型に一括で変換します。
import pandas as pd
import numpy as np
df = pd.DataFrame({
"点数": [80, np.nan, 65],
"人数": [3, 5, 2],
"名前": ["佐藤", None, "鈴木"],
})
print(df.dtypes)
df2 = df.convert_dtypes()
print(df2.dtypes)
print(df2)
実行結果:
点数 float64
人数 int64
名前 str
dtype: object
点数 Int64
人数 Int64
名前 string
dtype: object
点数 人数 名前
0 80 3 佐藤
1 <NA> 5 <NA>
2 65 2 鈴木
小数点以下がない 点数 列は Int64 に、文字列は string になり、欠損はすべて <NA> 表示にそろいます。型がそろうと、整数がいつの間にか小数になる、といった事故を防げます。
pandas 3.0で変わった点のまとめ
pandas 3.0.0は2026年1月21日に公開されました(What’s new in 3.0.0)。欠損値まわりで影響が大きいのは次の3つです。
- 文字列の列が既定で専用の
str型になり、欠損はNoneではなくNaNで入る fillna()のmethod引数がなくなり、ffill()・bfill()を使うfillna()にvalue=Noneを渡せるようになり、object以外の型ではその型の欠損値が使われる
公式の更新情報では、まずpandas 2.3に上げて警告が出ないことを確認してから3.0へ移るよう勧めています。どちらのバージョンでも動くコードにするには、欠損の判定を pd.isna() に統一するのが確実です。
よくある質問
Q. pandasでNaNとNoneの違いは何ですか?
NaNは浮動小数点数の特別な値で、数値の列の欠損に使われます。NoneはPython標準の「値なし」で、object型の列ではそのまま残りますが、数値の列に入れるとNaNに置き換わります。pandas 3.0では文字列の列でもNoneはNaNになります。
Q. pd.NAはいつ使えばいいですか?
整数や真偽値の列に欠損があっても型を変えたくないときです。dtype=”Int64″ や “boolean” を指定するか、convert_dtypes() で変換すると、欠損はpd.NAで表されます。
Q. 欠損値かどうかを == で判定してはいけないのはなぜですか?
np.nan == np.nan は False、pd.NA との比較は <NA> になるため、== では欠損を見つけられないからです。pd.isna()、Series.isna() を使えばNaN・None・pd.NAのどれでも判定できます。
Q. fillna(method=”ffill”) がエラーになります。
pandas 3.0で fillna() の method 引数が削除されたためです。df.ffill() または df.bfill() に書き換えてください。pandas 2.1〜2.3でも非推奨の警告が出ます。
Q. notna() と notnull() は違いますか?
同じ動きをする別名です。isna() と isnull() も同様です。公式ドキュメントは isna()・notna() を使って説明しています。
まとめ
- 欠損値の表し方は列の型で決まる:数値はNaN、object型はNone、nullable型はpd.NA
- 判定は == ではなく isna()・notna() で行う
- 削除は dropna()、補完は fillna()・ffill()・bfill()
- 整数や真偽値の型を保ちたいなら Int64・boolean か convert_dtypes()
- pandas 3.0では文字列列の欠損がNaNになり、fillna(method=…) は使えない
欠損値の処理は、小さなDataFrameを作って結果を print しながら確かめるのが一番の近道です。一人で詰まりやすい人は、自分のペースで進めながらわからないところをトレーナーに質問できる通学型スクールのテックジム(東京本校は永田町)や、無料講座も活用してみてください。
pandas|欠損値の扱いの関連記事
NaNの判定・削除・補完など、欠損値処理に関する記事です。
- 欠損値NaNの判定と個数カウントをマスターしてデータを見える化しよう
- 欠損値NaNを含む行・列をきれいに削除!dropna徹底解説
- 欠損値NaNを賢く埋める!fillnaでデータクレンジング
- 欠損値NaNを含む行・列を特定・抽出する方法
- 欠損値NaNを前後の値で賢く埋めるinterpolateメソッド徹底解説
- NaNの除外・置換・抽出をマスターしてデータ分析の質を向上
pandas全体の使い方は「pandasの使い方を初心者向けに解説」でまとめています。



