Hace tiempo ya os propuse una chapuza para eliminar outliers de forma multivariante. Por supuesto, quedaba eliminar outliers en una variable: recortar los valores extremos en aquellas variables cuantitativas que deseemos. Para ello os propongo una macro que no considero muy compleja y que analizaré con mayor detalle; pero, lo primero, la macro al completo:

%macro elimina_outliers(
    varib,          /* VARIABLE PARA ELIMINAR EL OUTLIER */
    entrada,        /* DATASET DE ENTRADA */
    salida,         /* DATASET DE SALIDA, PUEDE SER EL MISMO DE ENTRADA */
    corte_inferior, /* % DE CORTE INFERIOR */
    corte_superior  /* % DE CORTE SUPERIOR */
);

    * CREAMOS LOS PERCENTILES;
    data _null_;
        call symput ("lim1", compress(0 + &corte_inferior.));
        call symput ("lim2", compress(100 - &corte_superior.));
    run;

    * PREPARAMOS MV CON LOS NOMBRES QUE OBTENDREMOS DEL PROC UNIVARIATE;
    data _null_;
        call symput ('nom_lim1', compress("P_" || tranwrd("&lim1.", '.', '_')));
        call symput ('nom_lim2', compress("P_" || tranwrd("&lim2.", '.', '_')));
    run;

    * EL UNIVARIATE GENERA UNA SALIDA SOLO CON LOS PERCENTILES DESEADOS;
    proc univariate data=&entrada. noprint;
        var &varib.;
        output out=sal pctlpre=P_ pctlpts=&lim1., &lim2.;
    run;

    * CREAMOS MV CON LOS CORTES DESEADOS;
    data _null_;
        set sal;
        call symput("inf", &nom_lim1.);
        call symput("sup", &nom_lim2.);
    run;

    * REALIZAMOS EL FILTRO;
    data &salida.;
        set &entrada.;
        if &varib. > &inf. and &varib. < &sup.;
    run;

    proc delete data=sal; 
    run;

%mend;

Su ejemplo de uso correspondiente:

data ent;
    do i = 1 to 10000;
        importe = rannor(2) * 1000;
        if ranuni(3) >= 0.95 then importe = importe * 10;
        if ranuni(4) >= 0.05 then importe = importe / 10;
        output;
    end;
run;

* ANALIZAMOS LA VARIABLE IMPORTE;
proc univariate data=ent;
    var importe;
    histogram;
run;

* RECORTAMOS UN 5% POR ARRIBA Y UN 5% POR DEBAJO;
%elimina_outliers(importe, ent, salida, 5, 5);

proc univariate data=salida;
    var importe;
    histogram;
run;

Tenemos dos histogramas: uno es “imposible”, pero el otro nos permite conocer un poco mejor la distribución de la variable importe tras recortar un 5% las observaciones tanto por arriba como por abajo. Analicemos brevemente el código utilizado en la macro:

%macro elimina_outliers(
    varib,          /* VARIABLE PARA ELIMINAR EL OUTLIER */
    entrada,        /* DATASET DE ENTRADA */
    salida,         /* DATASET DE SALIDA, PUEDE SER EL MISMO DE ENTRADA */
    corte_inferior, /* % DE CORTE INFERIOR */
    corte_superior  /* % DE CORTE SUPERIOR */
);

Los parámetros de la macro son sencillos: la variable que recortamos (varib), el dataset de entrada (entrada), el dataset de salida (salida) que puede ser el mismo, el corte inferior y el corte superior en porcentaje (si no se quiere recortar, ponemos 0).

* CREAMOS LOS PERCENTILES;
data _null_;
    call symput ("lim1", compress(0 + &corte_inferior.));
    call symput ("lim2", compress(100 - &corte_superior.));
run;

* PREPARAMOS MV CON LOS NOMBRES QUE OBTENDREMOS DEL PROC UNIVARIATE;
data _null_;
    call symput ('nom_lim1', compress("P_" || tranwrd("&lim1.", '.', '_')));
    call symput ('nom_lim2', compress("P_" || tranwrd("&lim2.", '.', '_')));
run;

En los parámetros ponemos los porcentajes, y esos porcentajes se tienen que transformar en percentiles. Después creamos los nombres para los percentiles de forma que el PROC UNIVARIATE los “entienda”, es decir, con la forma P_97_5 o P_5. Os lo pongo en dos pasos para hacerlo lo más comprensible posible.

* EL UNIVARIATE GENERA UNA SALIDA SOLO CON LOS PERCENTILES DESEADOS;
proc univariate data=&entrada. noprint;
    var &varib.;
    output out=sal pctlpre=P_ pctlpts=&lim1., &lim2.;
run;

Ésta es la parte más interesante de este proceso: el PROC UNIVARIATE va a crear un dataset con el valor de los percentiles que queremos recortar; esto se realiza en la sentencia OUTPUT con la instrucción pctlpre=P_ y pctlpts=limite_inferior, limite_superior. Los límites están en unas macrovariables y el conjunto de datos sal contendrá los valores sobre los que recortamos la variable.

* CREAMOS MV CON LOS CORTES DESEADOS;
data _null_;
    set sal;
    call symput("inf", &nom_lim1.);
    call symput("sup", &nom_lim2.);
run;

* REALIZAMOS EL FILTRO;
data &salida.;
    set &entrada.;
    if &varib. > &inf. and &varib. < &sup.;
run;

Por último, creamos dos macrovariables con los valores de corte y realizamos un paso DATA donde filtramos por esos valores.

Creo que es un código con algún aspecto interesante y que puede seros práctico a la hora de analizar de forma univariante algunas variables. Saludos.