Python | データ処理:重複 drop_duplicates

Python
スポンサーリンク

概要(drop_duplicatesは「重複行を安全に取り除いて、件数や集計を正しくする」)

pandasのdrop_duplicatesは、DataFrameやSeriesから“重複したデータ”を削除するメソッドです。アンケートの二重回答や取り込みの重複行をそのまま集計すると、件数・平均・割合が歪みます。分析前に「どの列で重複判定するか」「どちらの行を残すか」を決めて、確実に重複を掃除するのが定石です。


基本の使い方(全列での重複判定と特定列での判定)

全列が同じ行をまとめて削除(最小例)

import pandas as pd

df = pd.DataFrame({
    "id": [1, 1, 2, 2, 2],
    "name": ["Taro", "Taro", "Hanako", "Hanako", "Hanako"]
})

out = df.drop_duplicates()  # 全列が完全一致する行を削除
print(out)
#    id    name
# 0   1    Taro
# 2   2  Hanako
Python

「行全体が完全一致するもの」だけを重複とみなします。最初の出現を残して、後の重複を落とすのがデフォルトです。

特定の列だけで重複判定(subset)

df = pd.DataFrame({
    "id": [1, 1, 2, 2],
    "name": ["Taro", "Taro", "Hanako", "Hanako"],
    "age": [20, 21, 25, 25]
})

# nameだけで重複判定(年齢が違っても「同じ名前を1人」とみなす)
out = df.drop_duplicates(subset=["name"])
print(out)
#    id    name  age
# 0   1    Taro   20
# 2   2  Hanako   25
Python

「何を重複とみなすか」は列の選び方で決まります。業務ルールに合わせてsubsetを設計しましょう。


重要オプションの深掘り(keep・ignore_index・inplace)

keep(どちらの重複を残すか)

df = pd.DataFrame({"name": ["Taro", "Taro", "Taro"], "age": [20, 21, 22]})

df_first = df.drop_duplicates(subset=["name"], keep="first")  # 最初を残す(デフォルト)
df_last  = df.drop_duplicates(subset=["name"], keep="last")   # 最後を残す
df_none  = df.drop_duplicates(subset=["name"], keep=False)    # すべて削除(完全排除)

print(df_first)
#   name  age
# 0  Taro   20

print(df_last)
#   name  age
# 2  Taro   22

print(df_none)
# 空(全て重複扱いで削除)
Python

ポイント: 「最新を残したいか、最初を残したいか、そもそも重複は全部消したいか」を明確に決めてkeepで表現します。

ignore_index(削除後に連番インデックスへ)

df = pd.DataFrame({"x": [1, 1, 2, 2, 3]})
out = df.drop_duplicates(ignore_index=True)
print(out)
#    x
# 0  1
# 1  2
# 2  3
Python

重複削除後はインデックスが飛び飛びになります。連番に振り直したい時はignore_index=Trueが便利です。

inplace(直接更新するか)

df.drop_duplicates(subset=["name"], keep="first", inplace=True)  # dfを直接書き換え
Python

注意: inplaceは副作用が見えにくく、テストやデバッグで混乱しがちです。基本は「代入で受ける」書き方(df = df.drop_duplicates(…))を推奨します。


重複の確認と前処理(duplicatedと併用、キー正規化)

どの行が重複かを確認(duplicated)

df = pd.DataFrame({"name": ["Taro", "Taro", "Hanako", "Hanako"], "age": [20, 20, 25, 26]})

mask = df.duplicated(subset=["name", "age"], keep="first")
dups = df[mask]
print(dups)
# 「同じname×ageで2回目以降」の行が抽出される
Python

重複の可視化→削除の順で進めると、意図しない消しすぎを防げます。

キーの前処理(空白・大小・型の揃え)

df = pd.DataFrame({"email": [" Taro@Example.com ", "taro@example.com", None]})
df["email"] = df["email"].fillna("").str.strip().str.lower()
unique_emails = df.drop_duplicates(subset=["email"], keep="first")
Python

重複判定の列は、空白除去・小文字化・型統一を先にやるのが鉄則です。揃えずに判定すると、同じものを別物として残してしまいます。


実践例(マスタ付与前の重複掃除・最新レコードの選別・複合キー)

マスタ付与前に重複ユーザーを一意化

users = pd.DataFrame({
    "user_id": ["001", "001", "002"],
    "name": ["Taro", "Taro", "Hanako"]
})

users = users.drop_duplicates(subset=["user_id"], keep="first")
Python

外部データ結合(merge)前にキーの一意性を確保しておくと、意図しない多対多結合で行が爆発するのを防げます。

最新レコードだけを残す(keep=”last”)

history = pd.DataFrame({
    "user_id": ["001", "001", "001"],
    "status": ["new", "active", "suspended"],
    "ts": ["2025-01-01", "2025-02-01", "2025-03-01"]
})

# 時系列で並べ、user_idごとに最後を残す
history = history.sort_values("ts")
latest = history.drop_duplicates(subset=["user_id"], keep="last")
print(latest)
Python

「時系列で最後の状態だけ欲しい」場面は、sort→drop_duplicates(keep=”last”)の型がシンプルです。

複合キーで誤結合を防ぐ(store×dateなど)

sales = pd.DataFrame({
    "store": ["A", "A", "A", "B"],
    "date":  ["2025-01-01", "2025-01-01", "2025-01-02", "2025-01-01"],
    "qty":   [10, 10, 12, 8]
})

clean = sales.drop_duplicates(subset=["store", "date"], keep="first")
Python

単一列より「複合キー」を使うと、文脈に即した重複判定ができます。


つまずき対策(“行全体”と“列 subset”の違い・NaN扱い・順序)

誤解しやすいポイント

  • 列を指定しないと、行全体が一致したものだけが重複扱い。 列の一部だけで重複判定したいならsubsetを必ず使います。
  • NaNはNaN同士でも“同値”として重複判定される(DataFrameでは) ため、NaNを含む行の重複削除に注意が必要です。必要なら先にfillnaで正規化します。
  • 残したい行の基準は順序に依存。 keep=”first”/”last”は現在の並び順で決まるため、意図がある順序(sort)に整えてからdrop_duplicatesします。

安全な進め方

  • 確認→削除: duplicatedで重複行を確認してからdrop_duplicates。
  • 正規化→判定: キー列はstrip/lower/astypeで揃えてからsubset判定。
  • 連番化: ignore_index=Trueでインデックスをリセットし、後工程の参照を安定化。

まとめ(subsetで“何を重複とみなすか”を決め、keepと順序で“どれを残すか”を制御)

drop_duplicatesは、重複行を削除して分析を正しく進めるための基本メソッドです。まずsubsetで「重複判定の軸」を決め、keepで「残す基準(最初・最後・完全排除)」を選ぶ。順序が意味を持つならsortしてから実行し、ignore_indexで連番化する。duplicatedで可視化してから削除に進み、キー列は正規化して誤判定を防ぐ。これらを型として徹底すれば、初心者でも“過不足なく、意図どおりに”重複を掃除できます。

タイトルとURLをコピーしました