SAS9

Alle Duplikate löschen (ohne eine Kopie zu behalten)

Simon 9 vistas

In der Datenverwaltung ist die Deduplizierung eine klassische Aufgabe. Wenn man von "Duplikate entfernen" spricht, möchte man normalerweise eine einzige Zeile für jeden Schlüssel beibehalten und die Wiederholungen eliminieren. Das macht ein PROC SORT mit der Option NODUPKEY sehr gut.

Es gibt jedoch einen strengeren Fall: vollständig jede Datengruppe zu löschen, die Duplikate aufweist. Wenn eine Kennung mehrmals vorkommt, wird davon ausgegangen, dass die Daten "kontaminiert" oder mehrdeutig sind, und man möchte keine Spur dieser Datensätze behalten. Nur die wirklich eindeutigen Kennungen (die nur einmal in der Originaltabelle vorkommen) sollen überleben.

Alle Duplikate löschen (ohne eine Kopie zu behalten) -

Das Problem

Nehmen wir das Beispiel einer Tabelle, die eine Kundenkennung (ID) und ein Jahr (Year) enthält. Eine Beobachtung wird durch die Kombination ID + Year definiert.

Eingabedaten:

ObsIDYearVar1Status
1119995Eindeutig (zu behalten)
22200010Duplikat
3220008Duplikat
4220006Duplikat
5320017Eindeutig (zu behalten)
64200212Duplikat
74200215Duplikat

Das Ziel ist es, eine Tabelle zu erhalten, die nur die Beobachtungen 1 und 5 enthält. Die ID-Gruppen 2 und 4 müssen vollständig verschwinden.

Wenn Sie PROC SORT NODUPKEY verwenden, behält SAS© die erste Zeile jeder Gruppe (Zeile 2 und Zeile 6 würden bleiben), was hier nicht das gewünschte Ergebnis ist.

Die SQL-Lösung: GROUP BY und HAVING

Die eleganteste und prägnanteste Methode, um diesen Vorgang durchzuführen, verwendet PROC SQL. Die Idee ist, die Daten nach dem Identifikationsschlüssel zu gruppieren, die Anzahl der Elemente in jeder Gruppe zu zählen und nur diejenigen zu filtern, deren Anzahl streng gleich 1 ist.

Der Code:

1PROC SQL;
2 create TABLE want as
3 select *
4 from have
5 group BY id, year
6 having count(*) = 1;
7QUIT;

Wie funktioniert das?

  1. GROUP BY id, year: SAS© gruppiert virtuell die Zeilen, die dasselbe ID/Jahr-Paar teilen.

  2. HAVING count(*) = 1: Dies ist die Filterbedingung, die nach der Gruppierung angewendet wird.

    • Für ID 1 (Jahr 1999) ist die Anzahl 1. -> Behalten.

    • Für ID 2 (Jahr 2000) ist die Anzahl 3. -> Verworfen (alle Zeilen der Gruppe werden ignoriert).

Dieser Ansatz ist sehr effizient, da er mehrere Sortier- und Markierungsschritte (Flagging) in einem klassischen Data-Schritt vermeidet.

Alternative mit Data-Schritt (zur Information)

Für die Puristen des DATA-Schritts würde das gleiche Ergebnis eine "doppelte Lese"-Logik oder die Verwendung der automatischen Variablen first. und last. nach einer Sortierung erfordern, wobei überprüft wird, ob first.id gleich last.id ist (was bedeutet, dass es nur eine Zeile für diese ID gibt).

1/* Nécessite un tri préalable */
2PROC SORT DATA=have; BY id year; RUN;
3 
4DATA want;
5 SET have;
6 BY id year;
7 /* On ne garde que si c'est à la fois le premier et le dernier du groupe */
8 IF first.year and last.year THEN OUTPUT;
9RUN;