pandasのdropna()の使い方|subset・how・thresh・axisで欠損値NaNの行・列を削除【pandas 3.0対応】

pandasのdropna()は、欠損値(NaN・None・pd.NAなど)を含む行や列を取り除くメソッドです。引数なしなら欠損が1つでもある行を削除し、特定の列だけを見るならsubset=["列名"]、全部欠けている行だけならhow="all"、「値が何個あれば残すか」ならthresh、列を消すならaxis=1を指定します。

この記事では、同じ表を使って各引数で何行残るのかを実際に動かして比べます。コードはPython 3.12・pandas 3.0.6で実行し、引数の説明は公式ドキュメント(pandas.DataFrame.dropna、pandas 3.0.6(2026年10月15日確認))に合わせています。

dropna()の引数一覧

引数 既定値 意味
axis 0 0または"index"で行を、1または"columns"で列を削除する
how "any" "any"は欠損が1つでもあれば削除、"all"は全部欠損のときだけ削除
thresh なし 欠損でない値がこの個数以上ある行(列)だけ残す。howとは同時に指定できない
subset なし 欠損を調べる列(axis=1のときは行)を限定する
inplace False Trueなら元のDataFrameを書き換え、戻り値はNone
ignore_index False Trueなら結果の行番号を0から振り直す(pandas 2.0.0で追加)

基本:欠損が1つでもある行を削除する

以下の5行の表を例にします。name・age・scoreのあちこちに欠損があります。

import numpy as np
import pandas as pd

df = pd.DataFrame({
    "name": ["佐藤", "鈴木", "高橋", "田中", None],
    "age": [25, np.nan, 31, np.nan, np.nan],
    "score": [80, 72, np.nan, np.nan, np.nan],
})
print(df)
print()
print(df.dropna())

実行結果:

  name   age  score
0   佐藤  25.0   80.0
1   鈴木   NaN   72.0
2   高橋  31.0    NaN
3   田中   NaN    NaN
4  NaN   NaN    NaN

  name   age  score
0   佐藤  25.0   80.0

引数なしのdropna()はhow="any"と同じで、どこか1つでも欠損がある行をすべて削除します。この表では、すべての値がそろっている0行目しか残りません。実際のデータでは、引数なしで実行すると思った以上に行が減ることがよくあります。まずdf.isna().sum()で列ごとの欠損数を確認してから、次のsubsetやthreshで条件を絞るのがおすすめです。

subset:特定の列に欠損がある行だけ削除する

「年齢が分からない行だけ除きたい」のように、判断に使う列を決めたいときはsubsetを使います。指定した列だけを見て、そこに欠損がある行を削除します。他の列に欠損があっても行は残ります。

import numpy as np
import pandas as pd

df = pd.DataFrame({
    "name": ["佐藤", "鈴木", "高橋", "田中", None],
    "age": [25, np.nan, 31, np.nan, np.nan],
    "score": [80, 72, np.nan, np.nan, np.nan],
})
print(df.dropna(subset=["age"]))
print()
print(df.dropna(subset=["age", "score"], how="all"))
print()
print(df.dropna(subset="score"))

実行結果:

  name   age  score
0   佐藤  25.0   80.0
2   高橋  31.0    NaN

  name   age  score
0   佐藤  25.0   80.0
1   鈴木   NaN   72.0
2   高橋  31.0    NaN

  name   age  score
0   佐藤  25.0   80.0
1   鈴木   NaN   72.0

結果を順に見ます。

  • subset=["age"]:ageが欠けている1・3・4行目が消え、scoreが欠けている2行目は残る
  • subset=["age", "score"], how="all":2列の両方が欠けている3・4行目だけが消える
  • subset="score":列が1つなら、リストにせず文字列で渡しても動く

subsetに複数の列を渡したとき、howを省略すると"any"(どれか1つでも欠けていれば削除)になります。「どちらか一方でも値があれば残したい」なら、上の2つ目の例のようにhow="all"を組み合わせます。存在しない列名を渡すとKeyErrorになる点にも注意してください(後述)。

how=”all”:全部欠けている行だけ削除する

CSVの末尾に空行がある、Excelから読み込んだら空の行が混ざった、というときはhow="all"が便利です。すべての値が欠損している行だけを削除し、一部でも値がある行は残します。

import numpy as np
import pandas as pd

df = pd.DataFrame({
    "name": ["佐藤", "鈴木", "高橋", "田中", None],
    "age": [25, np.nan, 31, np.nan, np.nan],
    "score": [80, 72, np.nan, np.nan, np.nan],
})
print(df.dropna(how="all"))
print()
print(df.dropna(thresh=2))

実行結果:

  name   age  score
0   佐藤  25.0   80.0
1   鈴木   NaN   72.0
2   高橋  31.0    NaN
3   田中   NaN    NaN

  name   age  score
0   佐藤  25.0   80.0
1   鈴木   NaN   72.0
2   高橋  31.0    NaN

1つ目の結果では、全項目が欠けている4行目だけが消えました。2つ目は次のthreshの例です。

thresh:値がいくつあれば残すかを決める

thresh=2は「欠損でない値が2個以上ある行を残す」という意味です。「欠損が2個以上なら削除」ではない点を取り違えやすいので注意してください。上の表は3列なので、thresh=2なら欠損が1個までの行(0・1・2行目)が残り、値がnameの1個だけの3行目と、値が1つもない4行目が消えます。

列数が多い表で「半分以上の項目が埋まっている行だけ使う」ときは、thresh=len(df.columns) // 2のように列数から計算すると意図が伝わりやすくなります。なお、threshとhowを同時に指定するとTypeErrorになります。

axis=1:欠損を含む列を削除する

axis=1(またはaxis="columns")にすると、行ではなく列を削除します。howやthreshは列単位で働きます。

import numpy as np
import pandas as pd

df = pd.DataFrame({
    "name": ["佐藤", "鈴木", "高橋"],
    "age": [25, np.nan, 31],
    "memo": [np.nan, np.nan, np.nan],
})
print(df.dropna(axis=1))
print()
print(df.dropna(axis="columns", how="all"))
print()
print(df.dropna(axis=1, thresh=3))

実行結果:

  name
0   佐藤
1   鈴木
2   高橋

  name   age
0   佐藤  25.0
1   鈴木   NaN
2   高橋  31.0

  name
0   佐藤
1   鈴木
2   高橋
  • axis=1:欠損を1つでも含むageとmemoの両方が消える
  • axis="columns", how="all":全部欠けているmemoだけが消える
  • axis=1, thresh=3:値が3個そろっている列(name)だけが残る

アンケートの未使用の設問など、まったく使われていない列を落とすときはhow="all"を付けておくと、必要な列まで消してしまう事故を防げます。

削除した後の行番号を振り直す:ignore_index

dropna()は元の行番号(インデックス)をそのまま残すので、削除後は0, 2のように番号が飛びます。0から振り直したいときは、pandas 2.0以降ならignore_index=True、それより前のバージョンでも使える書き方ならreset_index(drop=True)です。

import numpy as np
import pandas as pd

df = pd.DataFrame({"a": [1, np.nan, 3], "b": [4, 5, 6]})
print(df.dropna())
print()
print(df.dropna(ignore_index=True))
print()
print(df.dropna().reset_index(drop=True))

実行結果:

     a  b
0  1.0  4
2  3.0  6

     a  b
0  1.0  4
1  3.0  6

     a  b
0  1.0  4
1  3.0  6

番号が飛んだままだと、df.loc[1]のように番号で行を取り出したときにKeyErrorになることがあります。後で番号を使う処理があるなら振り直しておきましょう。

inplace=Trueは使うべきか

inplace=Trueを付けると元のDataFrameが書き換わり、戻り値はNoneになります。

import numpy as np
import pandas as pd

df = pd.DataFrame({"a": [1, np.nan, 3]})
result = df.dropna(inplace=True)
print(result)
print(df)

実行結果:

None
     a
0  1.0
2  3.0

df = df.dropna(inplace=True)と書くとdfがNoneになってしまう、というのがよくある間違いです。df = df.dropna()と代入する書き方なら、メソッドをつなげて書くこともでき、元のデータを残したまま比較することもできます。特別な理由がなければ、代入する書き方をおすすめします。

dropnaで消えない「見た目の欠損」に注意

dropna()が欠損として扱うのはNaN・None・pd.NA・NaTなどで、空文字""や空白だけの文字列、"N/A"という文字は対象外です(read_csvは既定で空欄や"N/A"、"NULL"などを読み込み時にNaNへ変換しますが、空白だけの値や、手で作ったデータ・別の経路で入った値はそのまま残ります)。

import numpy as np
import pandas as pd

df = pd.DataFrame({"city": ["東京", "", " ", "N/A", np.nan]})
print(df.dropna())
print()
cleaned = df.replace(r"^\s*$", np.nan, regex=True).replace("N/A", np.nan).dropna()
print(cleaned)

実行結果:

  city
0   東京
1     
2     
3  N/A

  city
0   東京

1つ目の結果では、空文字・空白・"N/A"の行が残っています。replace()で先にNaNへ置き換えてからdropna()すると、2つ目のようにまとめて消せます。値の置き換えはpandas replace()の使い方で詳しく解説しています。

よくあるエラーと確認のしかた

import numpy as np
import pandas as pd

df = pd.DataFrame({"a": [1, np.nan, 3]})
try:
    df.dropna(how="all", thresh=1)
except TypeError as e:
    print("TypeError:", e)
try:
    df.dropna(subset=["x"])
except KeyError as e:
    print("KeyError:", e)

実行結果:

TypeError: You cannot set both the how and thresh arguments at the same time.
KeyError: ['x']
  • TypeError: You cannot set both the how and thresh arguments at the same time.:howとthreshを同時に指定している。どちらか一方にする
  • KeyError: ['x']:subsetに存在しない列名を渡している。df.columns.tolist()で列名を確認する(CSVの列名に空白が付いていることもある)

削除の前後で件数を確かめる習慣をつけると、消しすぎに気づけます。Seriesにも同じ名前のdropna()があり、欠損の要素だけを取り除きます。

import numpy as np
import pandas as pd

s = pd.Series([1.5, np.nan, 3.0, None])
print(s.dropna())
print()
df = pd.DataFrame({"a": [1, np.nan, 3], "b": [np.nan, np.nan, 6]})
print(df.isna().sum())
print(len(df), "->", len(df.dropna()))

実行結果:

0    1.5
2    3.0
dtype: float64

a    1
b    2
dtype: int64
3 -> 1

削除する前に考えたいこと

欠損のある行を消すと、残ったデータが偏ることがあります。たとえば「高齢の回答者ほど年収欄が空欄」なら、空欄の行を消すと平均年齢が下がった集計になります。削除してよいかは、欠損の数と、欠け方に偏りがないかを見て決めます。

よくある質問

Q. dropna()で特定の列にNaNがある行だけ削除するには?

subsetに列名を渡します。df.dropna(subset=[“age”])ならage列が欠けている行だけが削除され、他の列の欠損は無視されます。列が1つなら文字列のままsubset=”age”と書くこともできます。

Q. subsetに複数の列を指定したときの動きは?

既定のhow=”any”では、指定した列のどれか1つでも欠けていれば削除します。指定した列がすべて欠けている行だけを削除したいときはhow=”all”を一緒に指定します。

Q. threshの数字は何を表していますか?

欠損でない値がいくつ以上あればその行(列)を残すか、という個数です。thresh=2なら値が2個以上ある行が残ります。欠損の個数ではない点に注意してください。また、howと同時には指定できません。

Q. dropna()したのにDataFrameが変わりません。

dropna()は既定では新しいDataFrameを返すだけで、元のデータは変わりません。df = df.dropna()のように代入してください。inplace=Trueを使う場合は戻り値がNoneになるので、df = df.dropna(inplace=True)とは書かないでください。

Q. 空文字や”N/A”の行がdropna()で消えないのはなぜですか?

dropna()が欠損として扱うのはNaN・None・pd.NAなどで、空文字や”N/A”という文字列は通常の値だからです。replace()で先にNaNに置き換えてからdropna()してください。

pandas|欠損値の扱いの関連記事

NaNの判定・削除・補完など、欠損値処理に関する記事です。

pandas全体の使い方は「pandasの使い方を初心者向けに解説」でまとめています。

プログラミング学習に興味がある方は、まずは無料体験会へ

無料体験会・お申し込みはこちら