mygems

Doppelte Zeilen aus einer CSV-Datei entfernen

Die meisten Duplikate sind zwei Datensätze für eine Person, einer davon neuer. So findest du sie und behältst den richtigen.

Von uos ·

Für exakt doppelte Zeilen, mit erhaltener Kopfzeile und unveränderter Reihenfolge:

awk 'NR==1 || !seen[$0]++' input.csv > deduped.csv

Das deckt den einfachen Fall ab, und der einfache Fall ist seltener, als man denkt. Die meisten „Duplikate“ in einer Arbeitsdatei sind keine identischen Zeilen, sondern zwei Datensätze für dieselbe Person mit anderer Groß- und Kleinschreibung, einem Leerzeichen am Ende oder einer aktualisierten Telefonnummer. Löschst du dabei den falschen, gehen Daten verloren. Auf die Reihenfolge kommt es also an: Lege fest, was zwei Zeilen zu denselben macht, sieh dir an, worin sie sich unterscheiden, und lösche erst dann.

Schritt eins: den Schlüssel festlegen

Ein Duplikat sind zwei Zeilen, die dieselbe Sache beschreiben. Welche Spalten das belegen, ist eine Entscheidung über deine Daten, keine Eigenschaft der Datei.

  • Ein Duplikat der ganzen Zeile, jedes Feld identisch, ist fast immer ein Fehler: ein doppelter Import, ein erneut gelaufener Job, ein Anhängen, das zweimal lief. Das kannst du bedenkenlos entfernen.
  • Ein Schlüssel-Duplikat, gleiche email oder gleiche order_id, aber sonst alles verschieden, ist eine Datenfrage. Eine der Zeilen ist wahrscheinlich neuer oder vollständiger, und du musst dich entscheiden.

Wer das verwechselt, verliert auf die klassische Weise Datensätze. Wer in einer Kundenliste nach name dedupliziert, löscht fröhlich zwei verschiedene Menschen namens James Smith.

Schritt zwei: zählen, bevor du löschst

Führe nie blind eine Deduplizierung aus. Sieh dir an, was du entfernen willst:

duckdb -c "SELECT email, count(*) n FROM read_csv('input.csv') GROUP BY email HAVING n > 1 ORDER BY n DESC LIMIT 20"

Zwei Zahlen verraten dir, ob dein Schlüssel stimmt. Sind es eine Handvoll Duplikate, hast du wahrscheinlich echte Doppeleinträge. Ist ein Drittel der Datei „doppelt“, ist der Schlüssel falsch: Du vergleichst etwas, das nie eindeutig war.

Schau dir dann einen konkreten Fall vollständig an. Genau diesen Schritt überspringen die meisten:

duckdb -c "SELECT * FROM read_csv('input.csv') WHERE email = '[email protected]'"

Hier findest du heraus, dass sich die beiden Zeilen in genau der Spalte unterscheiden, auf die es dir ankam.

Schritt drei: entscheiden, welche Zeile bleibt

Sobald du weißt, dass sich die Zeilen unterscheiden, wird aus „Duplikate entfernen“ die Aufgabe „die richtige behalten“. Drei Regeln, grob danach sortiert, wie oft sie richtig sind:

Die neueste behalten. Gibt es einen Zeitstempel, ist das meistens die Antwort.

duckdb -c "COPY (SELECT * FROM (SELECT *, row_number() OVER (PARTITION BY email ORDER BY updated_at DESC) rn FROM read_csv('input.csv')) WHERE rn = 1) TO 'deduped.csv' (HEADER)"

Die vollständigste behalten. Ohne Zeitstempel ist die Zahl der nicht leeren Felder ein brauchbarer Ersatz, denn der vollere Datensatz ist meistens der spätere. Sortiere nach (col_a IS NOT NULL)::INT + (col_b IS NOT NULL)::INT + … und nimm die oberste.

Beide zusammenführen. Manchmal hat jede Zeile etwas, das der anderen fehlt. Das kommt oft vor, und eine Abkürzung gibt es nicht: Es ist ein Coalesce pro Spalte. Bei einer kleinen Menge machst du das besser von Hand, als es bei einer großen schlecht zu automatisieren.

Wofür du dich auch entscheidest: Schreibe die verworfenen Zeilen in eine zweite Datei, bevor du sie löschst. Eine Deduplizierung, die du nicht rückgängig machen kannst, wirst du in den nächsten zwei Wochen irgendwann bereuen.

Beinahe-Duplikate, also die meisten

Exakter Abgleich verfehlt den Großteil der echten Duplikate. Normalisiere zuerst, vergleiche danach und behalte die Originalwerte.

duckdb -c "SELECT lower(trim(email)) k, count(*) n FROM read_csv('input.csv') GROUP BY k HAVING n > 1"

Diese Normalisierungen helfen, grob nach Trefferquote geordnet:

  • Groß- und Kleinschreibung. [email protected] und [email protected] sind dasselbe Postfach.
  • Leerzeichen. Leerzeichen am Ende, die beim Kopieren entstehen, sind unsichtbar und extrem häufig. trim() erwischt führende und folgende; ein replace erledigt die geschützten Leerzeichen, die aus Webformularen kommen.
  • Satzzeichen in Kennungen. Telefonnummern wie +44 20 7946 0958, 02079460958 und (020) 7946 0958 sind eine Nummer. Entferne vor dem Vergleich alles, was keine Ziffer ist.
  • Gmail-Punkte und Plus-Adressen. [email protected] landet im selben Posteingang wie [email protected]. Ob das als Duplikat zählt, hängt davon ab, ob du Personen oder Konten dedupliziert.

Was du nicht automatisch tun solltest: unscharfer Namensabgleich. „Jon Smith“ und „John Smith“ können dieselbe Person oder zwei Kollegen sein, und ein Ähnlichkeitsschwellwert, der für eine Datei passt, ist für die nächste falsch. Erzeuge die Kandidatenpaare, prüfe sie und handle erst dann.

CSV File Viewer - Smart CSViPhone & iPad · Android

Der SQL-Editor und der visuelle Filter-Editor sind die zwei Hälften dieser Aufgabe: ein GROUP BY, um die doppelten Schlüssel zu finden, dann ein Filter, um jede Zeile mit einem gemeinsamen Schlüssel zu lesen, ohne vorher etwas in eine Datenbank zu laden.

Was es kann

In einer Tabellenkalkulation

Excel und Google Sheets haben beide einen Befehl „Duplikate entfernen“ (Remove Duplicates), und eine Eigenschaft davon solltest du kennen, bevor du ihn benutzt: Er behält das erste Vorkommen und löscht den Rest, und du kannst nicht bestimmen, welches das erste ist. Die zufällige Reihenfolge im Blatt entscheidet, welcher Datensatz überlebt.

Sortiere also bewusst, bevor du ihn ausführst. Sortiere absteigend nach deinem Zeitstempel, und aus „das erste behalten“ wird „das neueste behalten“, was du meistens meintest.

Der andere Weg in der Tabelle, eine Hilfsspalte mit COUNTIF, ist langsamer, aber zerstörungsfrei, und er zeigt dir die Duplikate, statt sie zu entfernen. Bei einer großen Datei bringt er außerdem Excel zum Hängen, denn COUNTIF über eine halbe Million Zeilen wächst quadratisch.

Auf dem Smartphone

Auf dem Smartphone ist das realistisch kein vollständiger Deduplizierungsdurchlauf. Du sortierst nach der verdächtigen Spalte, scrollst und siehst die Wiederholungen nebeneinander. So findest du am schnellsten heraus, ob eine Datei überhaupt ein Duplikatproblem hat.

Wenn du sie siehst, beantwortet das Filtern auf einen Schlüssel und das Lesen der paar Zeilen, die ihn teilen, die einzige Frage, die zählt: Ist das derselbe Datensatz, oder sind es zwei Datensätze, die zufällig ein Feld gemeinsam haben?

CSV Editor - Smart CSViPhone & iPad

Sortiere nach jeder Spalte wie in Excel und lösche dann Zeilen bei aktivem Filter, ohne etwas zu riskieren: Ausgeblendete Zeilen sind geschützt, ein Löschen berührt also nie Daten außerhalb des Filters. Rückgängig macht alles wieder gut, und genau das macht diese Arbeit auf dem Smartphone vertretbar.

Was es kann

Überprüfen

Drei Zahlen, und sie sollten zusammenpassen:

wc -l input.csv deduped.csv
duckdb -c "SELECT count(*) rows, count(DISTINCT email) keys FROM read_csv('deduped.csv')"

rows und keys müssen jetzt gleich sein. Sind sie es nicht, hat die Deduplizierung nicht jede Gruppe erfasst. Und input − deduped muss der Zahl der Zeilen entsprechen, die du entfernen wolltest und in Schritt zwei gezählt hast. Wurden mehr entfernt, war der Schlüssel weiter oder enger gefasst, als du dachtest, und die Datei mit den verworfenen Zeilen, die du gesichert hast, rettet dir jetzt den Nachmittag.

Fragen

Wie entferne ich doppelte Zeilen aus einer CSV-Datei?
Für exakt doppelte Zeilen behält `awk 'NR==1 || !seen[$0]++' input.csv > deduped.csv` die Kopfzeile und die ursprüngliche Reihenfolge. Wenn Duplikate über eine Schlüsselspalte statt über die ganze Zeile definiert sind, gruppiere zuerst nach diesem Schlüssel, um zu sehen, was du löschen würdest. Wähle dann selbst, welche Zeile bleibt, meist die neueste laut Zeitstempel, statt es dem Tool zu überlassen.
Wie finde ich Duplikate in einer CSV, bevor ich sie lösche?
Zähle sie nach Schlüssel: `SELECT email, count(*) n FROM read_csv('input.csv') GROUP BY email HAVING n > 1`. Kommt ein großer Teil der Datei zurück, ist der Schlüssel falsch: Du vergleichst eine Spalte, die nie eindeutig war. Wähle dann alle Zeilen zu einem doppelten Schlüssel aus und lies sie nebeneinander; dabei merkst du, dass sich die Zeilen in einer Spalte unterscheiden, die dir wichtig ist.
Welche doppelte Zeile soll ich behalten?
Die neueste, wenn es einen Zeitstempel gibt. Ein row_number()-Fenster, nach dem Schlüssel partitioniert und absteigend nach Datum sortiert, behält genau eine Zeile pro Schlüssel. Ohne Zeitstempel ist die vollständigste Zeile ein brauchbarer Ersatz. Hat jede Zeile etwas, das der anderen fehlt, ist die ehrliche Antwort, sie spaltenweise zusammenzuführen, statt eine zu verwerfen.
Warum löscht „Duplikate entfernen“ in Excel die falsche Zeile?
Weil es das erste Vorkommen in der aktuellen Reihenfolge des Blatts behält und du nicht beeinflussen kannst, welches das ist. Sortiere vor dem Ausführen absteigend nach deinem Zeitstempel, dann bedeutet „das erste behalten“ so viel wie „das neueste behalten“.
Wie erkenne ich Duplikate, die nicht exakt identisch sind?
Normalisiere für den Vergleich und behalte die Originalwerte: alles klein schreiben, Leerzeichen entfernen und bei Telefonnummern alles außer Ziffern streichen, bevor du gruppierst. Diese drei erwischen die meisten echten Duplikate. Unscharfen Namensabgleich solltest du nicht automatisieren: „Jon Smith“ und „John Smith“ können eine Person oder zwei sein, und ein Schwellwert, der für eine Datei passt, ist für die nächste falsch.
Wie prüfe ich, ob die Deduplizierung funktioniert hat?
Die Zeilenzahl der Ausgabe und die Zahl ihrer unterschiedlichen Schlüssel müssen jetzt gleich sein, und die Zahl der entfernten Zeilen muss zu der passen, die du vor dem Löschen gezählt hast. Schreibe die verworfenen Zeilen vorher in eine separate Datei, denn eine Deduplizierung, die du nicht rückgängig machen kannst, willst du irgendwann rückgängig machen.

uos — Baut CSV Editor und Smart CSV Viewer und hat oft genug die falsche Zeile eines Duplikatpaars gelöscht, um die Prüfungen aufzuschreiben.