SAS9

Supprimer tous les doublons (sans en garder une copie)

Simon 7 views

Dans la gestion de données, la déduplication est une tâche classique. Habituellement, lorsqu'on parle de "supprimer les doublons", on souhaite conserver une ligne unique pour chaque clé et éliminer les répétitions. C'est ce que fait très bien un PROC SORT avec l'option NODUPKEY.

Cependant, il existe un cas de figure plus strict : supprimer intégralement tout groupe de données qui présente des doublons. Si un identifiant apparaît plusieurs fois, on considère que la donnée est "contaminée" ou ambigüe, et on ne veut garder aucune trace de ces enregistrements. Seuls les identifiants réellement uniques (qui n'apparaissent qu'une seule fois dans la table d'origine) doivent survivre.

Supprimer tous les doublons (sans en garder une copie) -

Le Problème

Prenons l'exemple d'une table contenant un identifiant client (ID) et une année (Year). Une observation est définie par la combinaison ID + Year.

Données en entrée :

ObsIDYearVar1Statut
1119995Unique (à garder)
22200010Doublon
3220008Doublon
4220006Doublon
5320017Unique (à garder)
64200212Doublon
74200215Doublon

L'objectif est d'obtenir une table qui ne contient que les observations 1 et 5. Les groupes d'ID 2 et 4 doivent disparaître totalement.

Si vous utilisez PROC SORT NODUPKEY, SAS© conservera la première ligne de chaque groupe (la ligne 2 et la ligne 6 resteraient), ce qui n'est pas le résultat souhaité ici.

La Solution SQL : GROUP BY et HAVING

La méthode la plus élégante et la plus concise pour réaliser cette opération utilise PROC SQL. L'idée est de grouper les données par la clé d'identification, de compter le nombre d'éléments dans chaque groupe, et de ne filtrer que ceux dont le compte est strictement égal à 1.

Le Code :

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

Comment ça marche ?

  1. GROUP BY id, year : SAS© regroupe virtuellement les lignes qui partagent le même couple ID/Année.

  2. HAVING count(*) = 1 : C'est la condition de filtrage appliquée après le regroupement.

    • Pour l'ID 1 (Année 1999), le compte est de 1. -> Gardé.

    • Pour l'ID 2 (Année 2000), le compte est de 3. -> Rejeté (toutes les lignes du groupe sont ignorées).

Cette approche est très efficace car elle évite des étapes multiples de tri et de marquage (flagging) dans une étape Data classique.

Alternative Étape Data (Pour info)

Pour les puristes de l'étape DATA, obtenir le même résultat nécessiterait une logique de "double lecture" ou l'utilisation des variables automatiques first. et last. après un tri, en vérifiant si first.id est égal à last.id (ce qui signifie qu'il n'y a qu'une seule ligne pour cet ID).

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;