SAS9

Eliminar todos los duplicados (sin guardar una copia)

Simon 7 vistas

En la gestión de datos, la deduplicación es una tarea clásica. Habitualmente, cuando se habla de "eliminar duplicados", se desea conservar una única fila para cada clave y eliminar las repeticiones. Esto es lo que hace muy bien un PROC SORT con la opción NODUPKEY.

Sin embargo, existe un caso más estricto: eliminar por completo cualquier grupo de datos que presente duplicados. Si un identificador aparece varias veces, se considera que el dato está "contaminado" o es ambiguo, y no se quiere guardar ningún rastro de esos registros. Solo los identificadores realmente únicos (que aparecen una sola vez en la tabla original) deben sobrevivir.

Eliminar todos los duplicados (sin guardar una copia) -

El Problema

Tomemos el ejemplo de una tabla que contiene un identificador de cliente (ID) y un año (Year). Una observación se define por la combinación ID + Year.

Datos de entrada:

ObsIDAñoVar1Estado
1119995Único (a conservar)
22200010Duplicado
3220008Duplicado
4220006Duplicado
5320017Único (a conservar)
64200212Duplicado
74200215Duplicado

El objetivo es obtener una tabla que contenga solo las observaciones 1 y 5. Los grupos de ID 2 y 4 deben desaparecer por completo.

Si utiliza PROC SORT NODUPKEY, SAS© conservará la primera fila de cada grupo (la fila 2 y la fila 6 permanecerían), lo cual no es el resultado deseado aquí.

La Solución SQL: GROUP BY y HAVING

El método más elegante y conciso para realizar esta operación utiliza PROC SQL. La idea es agrupar los datos por la clave de identificación, contar el número de elementos en cada grupo y filtrar solo aquellos cuya cuenta sea estrictamente igual a 1.

El Código:

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

¿Cómo funciona?

  1. GROUP BY id, year: SAS© agrupa virtualmente las filas que comparten el mismo par ID/Año.

  2. HAVING count(*) = 1: Es la condición de filtrado aplicada después de la agrupación.

    • Para el ID 1 (Año 1999), la cuenta es 1. -> Conservado.

    • Para el ID 2 (Año 2000), la cuenta es 3. -> Rechazado (todas las filas del grupo son ignoradas).

Este enfoque es muy eficiente porque evita múltiples pasos de ordenamiento y marcado (flagging) en un paso de datos clásico.

Alternativa con Paso de Datos (Para información)

Para los puristas del paso DATA, obtener el mismo resultado requeriría una lógica de "doble lectura" o el uso de las variables automáticas first. y last. después de un ordenamiento, verificando si first.id es igual a last.id (lo que significa que solo hay una fila para ese 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;