AIでCSVの重複行を整理するときは、「どの列が同じなら候補にするか」を先に決めます。作業用の行IDが違う2行を、そのIDまで含めて全列一致と呼ぶことはできません。反対に、顧客IDだけが同じという理由で別の日の記録を消すと、有効な履歴を失う場合があります。
この記事では、架空CSV6行で、比較対象列の一致、業務キーの一致、値の競合を分けます。元CSVを残し、一部の一致行だけをまとめた作業コピーと、確認待ちの候補表を作ります。実台帳やAI出力を処理した結果ではありません。
目次
一行の意味と、比較する列を決める
今回は「一顧客・一日につき一つの売上集計」という架空のデータです。customer_idとsales_dateを業務キーとし、同じ顧客でも別の日なら別の有効記録になり得るとします。実際の売上や会計処理の定義ではありません。
source_row_idは元CSVのどの行かを追う作業用IDです。業務値の比較では除きますが、候補表や除外記録には残します。
source_row_id,customer_id,sales_date,amount_yen
S01,C001,2026-10-01,1000
S02,C001,2026-10-01,1000
S03,C001,2026-10-03,1200
S04,C002,2026-10-01,800
S05,C002,2026-10-01,900
S06,C003,2026-10-01,500
日付と金額の表記は、この例では統一済みです。実データで文字列の日付、時差、数値の桁区切りなどが混在する場合は、比較前にその意味と処理規則を確認します。AIに都合のよい型や欠損値を推測させてから、一致したと判断しないようにします。
同じという判定を三つに分ける
表は横にスクロールできます
| 比較方法 | この例で一致する行 | 判断 |
|---|---|---|
| source_row_idを含む全列 | 一致なし | 全行で作業用IDが違う |
| customer_id、sales_date、amount_yen | S01、S02 | 指定した業務値の列が一致 |
| customer_id、sales_date | S01、S02と、S04、S05 | 同じ業務キーの候補。値の一致は別に確認 |
| customer_idだけ | S01、S02、S03と、S04、S05 | 別日の履歴もまとまるため、そのまま削除条件にしない |
S01とS02は、作業用IDを除いた3列で一致します。S03は同じ顧客でも日付と金額が異なります。S04とS05は業務キーが同じでも金額が違い、どちらを採用すべきかはこのCSVから確定できません。
比較方法ごとのグループは重なり合います。S01とS02を複数の表で見つけても、それだけで削除件数を二重に加算しません。
残す規則を、候補を見る段階で固定する
今回の説明用ルールは、指定した3列が一致する場合に限り、元CSVで先に出た行を一つ残すことです。元の順序を変えず、S01を残してS02を作業コピーから除きます。先の行が常に正しいという一般ルールではありません。
業務キーだけが一致し金額が違うS04とS05は、両方残して確認待ちにします。更新日時や正本の区別がないため、「最後だから900円」「大きい方を採用」などの規則を追加しません。
表は横にスクロールできます
| 対象 | この例の処理 | 残す根拠 |
|---|---|---|
| S01、S02 | S01を残しS02を除外候補へ | 指定3列一致・元の先頭を保持 |
| S03 | 保持 | C001の別日の記録 |
| S04、S05 | 両方保持、確認待ち | 金額の競合が未解決 |
| S06 | 保持 | 今回の比較で一致候補なし |
実際に一行を除いてよいかは、データの粒度と採用ルール次第です。同額の決済が複数ある取引明細なら、同じ顧客・日付・金額でも別取引かもしれません。この例の一日集計の条件を、取引明細へ流用しないでください。
pandasで候補と作業コピーを別に作る
pandasのduplicatedは、subsetで比較列を指定できます。keep=Falseは一致するグループの全行を示し、drop_duplicatesのkeep="first"は最初の行を残す処理です。これは列と順序に基づく機能で、業務上の正しさを選ぶ機能ではありません。pandas公式:duplicated(新しいタブで開く)、drop_duplicates(新しいタブで開く)
上のCSVをsales_sample.csvとして置く説明用コードです。元ファイルを書き換えず、DataFrameも別の作業コピーへ分けます。
import pandas as pd
df = pd.read_csv("sales_sample.csv", dtype=str)
required = ["source_row_id", "customer_id", "sales_date", "amount_yen"]
if set(required) - set(df.columns):
raise ValueError("必要な列がありません")
if df[required].isna().any().any():
raise ValueError("この例では欠損を処理せず確認へ戻します")
if df["source_row_id"].duplicated().any():
raise ValueError("元行IDが重複しています")
payload = ["customer_id", "sales_date", "amount_yen"]
business_key = ["customer_id", "sales_date"]
exact_candidates = df.loc[df.duplicated(subset=payload, keep=False)].copy()
working_copy = df.drop_duplicates(subset=payload, keep="first").copy()
conflicts = working_copy.loc[
working_copy.duplicated(subset=business_key, keep=False)
].copy()
removed = df.loc[~df["source_row_id"].isin(working_copy["source_row_id"])].copy()
print("一致候補:", exact_candidates["source_row_id"].tolist())
print("除外候補:", removed["source_row_id"].tolist())
print("未解決:", conflicts["source_row_id"].tolist())
この6行では、一致候補はS01・S02、除外候補はS02、作業コピーに残る競合はS04・S05になります。掲載コードをローカルのpandasで実行し、元のIDと件数を照合しました。実ファイルの規模、入力のあらゆる不正値、AIの分類性能を検証したものではありません。
コードは全列を文字列として読み、この例の統一された表記を比較します。「1000」と「1,000」を同じ数として解釈する処理や、表記ゆれの推定は含めていません。空白だけの値、無効な日付なども、実データの規則で別に点検してください。
件数と、未解決の状態を両方残す
今回の作業コピーは、6行からS02の1行を除いた5行です。元行数6−除外行数1=作業コピー5行で照合できます。
ただし、業務キーの競合はS04・S05の1グループ・2行が残っています。「重複が全部なくなった」「台帳が確定した」とは報告しません。指定列一致の処理だけを行い、金額の競合は未解決と記録します。
除外表には、除く元IDのS02、残す元IDのS01、比較列、採用規則、入力ファイルの版を残します。判断を直す場合は、S02を推測で作り直すのではなく、保存した原CSVとそのIDへ戻ります。今回は元の値を変更するフィールド統合は行っていません。
同じ業務キーで一行を残す必要がある場合も、更新日時の有効性や正本のルールを確認してから別の処理にします。金額や状態が競合するグループを、指定列一致と同じ規則で片付けないようにします。
AIへは、候補表と処理記録を依頼する
このCSVの重複候補を整理してください。原CSVは変更しません。
一行の意味:この例では一顧客・一日につき一つの売上集計です。
source_row_idは追跡用で、業務値の比較列から除きます。
比較列:customer_id、sales_date、amount_yen。
業務キー:customer_id、sales_date。
まず比較方法ごとに元行ID、グループ、相違列を示してください。
指定3列が一致した場合だけ、元CSVの先頭行を残す候補にします。
業務キーが同じで金額が違う場合は、両方保持して確認待ちにしてください。
顧客IDだけが同じ別日の記録を削除しないでください。
出力:候補表、作業コピー、除外元IDと保持元IDの対応、未解決表、件数照合。
未指定の型変換、表記正規化、最新行優先、値の統合を追加しないでください。
入力:[利用が認められたCSV]
正規化してから比較する必要があるなら、変換前と後の列を分け、その変換で新しく一致したグループも確認します。似た名称が同じ人物・会社かを判断する作業は、顧客台帳の表記ゆれ・重複整理で扱います。
処理の完了は、消した行数だけでは判断できません。比較列、保持規則、元IDへの対応、件数、未解決グループを残し、どこまで整理したコピーなのかを説明できる状態にします。
参考資料
公式仕様の確認日:2026年10月20日。CSV6行と保持規則は架空例です。掲載コードをローカルで実行し、候補ID、作業コピー、除外と未解決の件数を検算しました。実台帳、AI出力、正しい売上額の決定、大量データの負荷、画面表示は検証していません。
