Macros SAS. Agrupando variables categóricas

14 Jun

Agrupar variables con SAS es una de las tareas más habituales. Las variables continuas las agrupamos según un criterio y las discretas, en principio, ya vienen agrupadas. El problema con las variables discretas es que pueden tomar muchos valores, muchos de ellos con poco valor que habitualmente agrupamos en un rango “OTROS”. Pues bien, hoy quería mostraros una macro muy sencilla que utilizo para crear ese cajón desastre. El código tiene algún aspecto muy interesante, es el que os pongo a continuación:

%macro agrupa_frecuencias(entrada=,/*DS DE ENTRADA*/
vargrupo=,/*VARIABLE QUE AGRUPA*/
nombre=count,/*VARIABLE DE FRECUENCIAS*/
numgr=,/*NUMERO DE GRUPOS*/
resto=,/*CATEGORIA RESTO*/
salida=/*DS DE SALIDA*/);
*TABLA DE FRECUENCIAS CON TODOS LOS VALORES;
proc freq data=&entrada. noprint;
tables &vargrupo./list missing
out=&salida. (drop=percent rename=&vargrupo.=agr);
quit;
proc sort data=&salida. ; by descending count;
*EN FUNCION DEL TIPO DE VARIABLE CREAMOS EL RESTO;
data &salida. ;
set &salida. ;
&vargrupo.="&resto.";
if _n_<&numgr. then &vargrupo.=put(left(agr),$10.);
run;
*SUMARIZAMOS;
proc summary sum nway missing; class &vargrupo. ;
output out=&salida. (drop=_type_ _freq_) sum(count)=&nombre.;
quit;
%mend;

Breve explicación del mismo, es un código de ejecución muy rápida y no tiene una calidad de producción como casi todo lo que hacemos los que trabajamos sólo con BASE. Necesitamos más parámetros que código. Un DS de entrada, el nombre de la variable discreta que queremos agrupar, el nombre de la variable de conteo, el número de grupos total que deseamos, el nombre de la categoría resto aquí es importante destacar que la variable final siempre será alfanumérica, si deseáis que sea numérica es muy sencillo de modificar, el último parámetros es el DS de salida con la tabla de frecuencias.
La macro comienza con un PROC FREQ que genera una tabla con todos los valores de la variable y su conteo, ordenamos descendientemente por ese conteo y después hacemos un paso DATA que lee la tabla y si está por encima del número de categorías fijado lo etiquetamos con un resto. Al final tenemos que agregar los datos de esta tabla.
Como es habitual, ejemplo de uso:


data uno;
letras="ABCDEFGHIJKLMNOPQRSTUVWXYZ"; drop letras;
do i=1 to 10000;
grupoM=ranpoi(3,16);
grupoK=char(letras,grupoM);
importe=ranuni(4)*10000;
output;
end;
run;
proc means data=uno;
class grupo1;
var importe;
quit;
proc means data=uno;
class grupo2;
var importe;
quit;

Dos variables de grupo con muchas categorías. Interesante el uso de la función CHAR. Deseamos crear una tabla de frecuencias que podamos manejar con facilidad:


*VARIABLES NUMERICAS;
%agrupa_frecuencias(entrada=uno,vargrupo=grupoM,
nombre=clientes,numgr=15,resto=RESTO,salida=frec1);
*VARIABLES ALFANUMERICAS;
%agrupa_frecuencias(entrada=uno,vargrupo=grupoK,
nombre=clientes,numgr=8,resto=OTROS,salida=frec2);

Es un código muy sencillo sin mucha calidad y al que le podéis encontrar más de un problema, pero que podéis rehacer a vuestro antojo para mejorarlo. Yo lo uso bastante para la realización de tablas de autoría de datos.

Dani, Fernando, no he visto nada en FREQ, no vale usar el STAT, no lo tiene todo el mundo.

Saludos.

5 respuestas a «Macros SAS. Agrupando variables categóricas»

  1. No iba tanto por ahí sino por alguna opción de freq que me estaba dejando. Son muchos años los que FREQ y yo nos conocemos y la verdad es que la echo en falta.

    ¿Con format quizá?

  2. Bueno, yo no soy tan amigo de las macros que contengan tantos parámetros.
    En vista a sacar punta al código :) se me ocurren algunas soluciones posibles muy similares al post que escribí ‘LAS CUENTAS CLARAS’ hace poco. Solo haré referencia a segmentar por «grupoM» (variable numerica) tal como la tabla salida «frec1» de Raul.En su caso son 15 grupos, así que nos quedamos con los 14 grupos con mayores casos y un ultimo grupo que Raul llama ‘resto’ yo lo llamo con un numero tan feo como -999999.

    ALTERNATIVA1: usando los OBS y FIRSTOBS.
    Aquí como vemos los parametrizo con solo 2 macrovariables de manera que baste cambiar solo «total_grupos» segun el número de grupos totales que queramos agrupar.
    proc freq data=uno noprint;
    tables grupoM /out= alternativa1;
    run;
    proc sort data=alternativa1;
    by descending count;
    run;

    %let total_grupos=15;
    %let grandes_grupos=%eval(&total_grupos-1);
    proc summary data=alternativa1 (firstobs=&total_grupos);
    var count;
    output out=resto sum()=;
    run;
    data alternativa1 (keep= grupoM count);
    set alternativa1 (obs=&grandes_grupos)
    resto (in=resto);
    if resto then grupoM=-999999;
    run;

    ALTERNATIVA2: esta me gusta más, tira más de paso Data y además solo necesita 1 parámetro (el total de grupos son 15 así que ‘juego’ todo el rato con _N_ es igual superior o inferior a 15).

    proc sort data=uno out=alternativa2 (keep=grupoM); by grupom; run;
    data alternativa2;
    set alternativa2;
    by grupom;
    if first.grupom then count= 1;
    else count + 1;
    if last.grupom;
    run;
    proc sort data=alternativa2; by descending count; run;
    data alternativa2;
    set alternativa2 end=fin;
    if _n_ =15 then unos= count;
    if _n_ >15 then unos+ count;
    if fin then do;
    grupoM=-99999999;
    count=unos;
    end;
    if _n_ <15 or fin then output;
    keep grupoM count;
    run;

    un saludo,
    Dani Fernández.

  3. Siempre queda usar el PROC FORMAT, pero no me veo con ganas de crear 14 nombres de grupos y uno final (para el ‘otherwise’) para tu ejemplo.

    saludos!

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *