ふくふくHukuhuku Inc.
EP.09Prep 8分公開: 2026-05-10

重複排除(Dedup)の戦略:どのレコードを「正」とするか

重複が見つかったとき、どのレコードを残すか。最新を残す / 最古を残す / 最も情報が豊富なものを残す── 3 つの戦略を使い分ける。

#重複排除#Dedup
CO📔 Google Colab で開く(上から順にセルを実行)
シェア

重複排除(Dedup)は名寄せの後工程。「同じエンティティ」と判定された複数レコードから、どれを正として残すかを決める作業です。

4 つの戦略

戦略ロジック向くケース
最新を残すupdated_at が最大の行顧客情報(住所変更等)
最古を残すcreated_at が最小の行「最初の登録」が信頼源
情報量で残すNULL が少ない / 必須フィールドが埋まってるアンケート回答
マージで残す重複行のフィールドを横方向に統合情報を捨てたくない場面

での実装

「最新を残す」Dedup
SQL
WITH ranked AS (  SELECT    *,    ROW_NUMBER() OVER (PARTITION BY normalized_name ORDER BY updated_at DESC) AS rn  FROM customers)SELECT * EXCEPT(rn) FROM ranked WHERE rn = 1;

Python(pandas)での実装

1. 戦略 A: 最新を残す
Python
import pandas as pd
# 重複検出print(f"全行: {len(df)}, 重複: {df.duplicated(subset='normalized_name').sum()}")
# 「最新を残す」(updated_at で並べ替え → drop_duplicates の keep='first')df_sorted = df.sort_values("updated_at", ascending=False)deduped_latest = df_sorted.drop_duplicates(subset="normalized_name", keep="first")print(f"Dedup 後: {len(deduped_latest)}")
2. 戦略 B: 情報量で残す(NULL が少ない行を選ぶ)
Python
def dedup_by_completeness(df: pd.DataFrame, key: str) -> pd.DataFrame:    """各グループで NULL の少ない行を残す"""    df = df.copy()    df["_completeness"] = df.notna().sum(axis=1)    deduped = (        df.sort_values("_completeness", ascending=False)        .drop_duplicates(subset=key, keep="first")        .drop(columns=["_completeness"])    )    return deduped
deduped = dedup_by_completeness(df, key="normalized_name")print(f"Dedup 後(情報量優先): {len(deduped)}")
3. 戦略 C: マージで残す(フィールドを横に統合)
Python
import numpy as np
def merge_duplicates(df: pd.DataFrame, key: str) -> pd.DataFrame:    """重複行のフィールドを「最新の non-null 値」で埋める"""    def take_first_valid(series):        valid = series.dropna()        return valid.iloc[0] if len(valid) > 0 else np.nan
    df_sorted = df.sort_values("updated_at", ascending=False)    merged = df_sorted.groupby(key, as_index=False).agg(take_first_valid)    return merged
merged = merge_duplicates(df, key="normalized_name")# 例: 行A は phone あり / email NULL, 行B は phone NULL / email あり# → マージ後の 1 行: phone も email も埋まる
4. 検証:Dedup 前後で件数とフィールド充足率を比較
Python
def validate_dedup(before: pd.DataFrame, after: pd.DataFrame) -> dict:    return {        "before_n": len(before),        "after_n": len(after),        "removed_n": len(before) - len(after),        "removed_pct": (len(before) - len(after)) / len(before),        "before_fillrate": before.notna().mean().mean(),        "after_fillrate": after.notna().mean().mean(),    }
print(validate_dedup(df, deduped))# 期待: after の fillrate が before より高い(マージ戦略時)

ふくふくの進め方

重複行が多くて困っている」のご相談には、重複パターンの分析 → 戦略選定 → SQL 実装 → 効果測定を 1〜2 週間で。

次回予告

EP.10 は結合の前処理:JOIN キー設計と「漏れ」の防止

シェア

この記事の感想を教えてください

あなたの 1 クリックで、本当にこの記事は更新されます。「もっと詳しく」「続編希望」が一定数集まった記事は、 ふくふくが 実際に内容を拡充したり続編記事を公開 します。 送信したリアクションはお使いのブラウザに記録され、再カウントされません。

シリーズの外も探す:

まずは、現状を聞かせてください。

要件が固まっていなくて大丈夫です。現状診断と方針提案までを無料でお手伝いします。

無料相談フォームへ hello [at] hukuhuku [dot] co [dot] jp