Archivos de la categoría SAS

Macro SAS. Número de variables de un dataset en una macro

Una macro que nos permite saber el número de variables que tiene un conjunto de datos SAS. Es una petición de una lectora y la macro es análoga a otra que ya pusimos en el blog allá por 2010. Veamos cómo funciona:

%macro numvars(datos);
 %global numvars;
 /*ABRIMOS EL CONJUNTO DE DATOS PARA VER SUS CARACTERISTICAS*/
 %let datosid = %sysfunc(open(&datos));
 /*SI ESTA ABIERTO ENTONCES LA FUNCION ATTRN NOS DA EL NUMERO DE VARIABLES*/
 %if &datosid %then %do;
 %let numvars =%sysfunc(attrn(&datosid,nvars));
 /*CERRAMOS EL CONJUNTO DE DATOS*/
 %let rc = %sysfunc(close(&datosid));%end;
 %mend;
data ejemplo;
 a=1;
 b=2;
 c=3;
 d=4;
 f=5;
 g=6;
 run;
%numvars(ejemplo);
 %put _user_;

Utilizamos las funciones I/O de SAS, en concreto ATTRN que unido a NVARS nos permite saber el número de variables que tiene un dataset, el número de variables lo ponemos en la macrovariable global &numvars..

Saludos.

Macro SAS. Crear variables dummy desde una variable categórica

En alguna ocasión ya he conjugado el verbo dumificar y preparando una segmentación he creado una macro SAS que genera variables dummy a partir de variables categóricas, es decir, si la variable A toma valores 1, 2 y 3 tendría que generar A_1 con valor 1 si A toma 1 y con valor 0 en caso contrario, A_2 tiene valor 1 si A es igual a 2 y A_3 tiene valor 1 si A es igual a 3, no es complicado de comprender, pasamos de una variable con 3 niveles a 3 variables con valores 0 o 1. Para esto podemos emplear arrays o la siguiente macro:

%macro dumificar(varib, grupos, mv);
%global &mv.;
data instruccion;
do i=1 to &grupos.;

instruccion="&varib._"||compress(put(i,3.))||
"=0; IF &varib.="||put(i,3.)||" THEN &varib._"||compress(put(i,3.))||"=1";

output;
end;
run;

proc sql noprint ;
select instruccion into:&mv. separated by ";"
from instruccion;
quit;
proc delete data=instruccion;quit;
%mend;

La intención es crear de forma automática un código del tipo VARIABLE_1=0; IF VARIABLE = 2 THEN VARIABLE_1=1; La macro tiene 3 parámetros, VARIB que es la variable que deseamos dumificar, GRUPOS que es el número de grupos de la variable que vamos a transformar en dummies y MV que es el nombre de la macrovariable que tiene el código SAS que generamos de forma automática. A modo de ejemplo de uso:

data aleatorios;
do i=1 to 1000 ;
datoA = min(ranpoi(2,4),9);
if datoA <= 3 then datoB = ranpoi(89,2);
else if datoA <= 5 then datoB = min(ranpoi(89,6),6);
else datoB = min(ranpoi(89,2),3);
output;
end;
drop i;
run;

%dumificar(datoA, 9, dumifica_datoA);
%dumificar(datoB, 8, dumifica_datoB);

data aleatorios;
set aleatorios;
&dumifica_datoA.;
&dumifica_datoB.;
run;

Espero que os sea de utilidad esta macro. Saludos.

Mapas SAS a partir de shapefile

Mapa shp SAS

Los mapas como este no los hago habitualmente con SAS pero que puede interesaros saber como se pueden hacer. Para la realización de mapas a partir de shapefiles suelo usar R, los que seáis habituales del blog sabéis que hay entradas al respecto. Sin embargo, recientemente, he conocido QGIS que interactúa a la perfección con Excel. El ejemplo de hoy es para aquellos que no conocéis QGIS o R y estáis más habituados a trabajar con SAS. Se trata de importar un shapefile con SAS poder hacer un sencillo tratamiento de datos y posteriormente realizar un mapa muy simple con SAS. Para ilustrar el ejemplo vamos a realizar un mapa por municipios de una provincia española con SAS y para ello necesitamos un fichero *.shp que os vais a descargar de http://www.gadm.org/country seleccionáis los mapas de España y descargáis el ZIP que contiene los archivos. El primer paso es crear un conjunto de datos SAS a partir del shapefile:

proc mapimport datafile="/directorio/mapa_sas/ESP_adm4.shp"
out = work.espania;
run;

Se emplea el proc mapimport que genera un conjunto de datos SAS compuesto por las coordenadas, identificadores y nombres de los municipios. Hacemos un tratamiento de datos muy sencillo:

data cadiz;
set espania;
if name_2 = "Cádiz";
run;

proc sort data=cadiz out=municipios nodupkey;
by id_4;
run;

data municipios;
set municipios;
aleatorio = ranpoi(3,4);
run;

Seleccionamos la provincia de Cádiz, sobre sus municipios calculamos una varible aleatoria (muy fácil todo) que será la que representemos en SAS con el proc gmap:

proc gmap data=municipios map=cadiz;
id id_4;
choro aleatorio/discrete;
run;quit;

Ya sabéis hacerlo con SAS, pero os recomiendo que vayáis instalando QGIS. Saludos.

Mínimo de una matriz de datos en SAS

El otro día una lectora del blog me preguntaba como obtener el mínimo de una matriz de datos de 100x1000 con SAS. El ejercicio es muy práctico para ayudar a que se entienda mejor como “piensa” SAS. Probablemente esta lectora estaba pensando en complicados bucles que recorren, que almacenan, que arrastran,… con SAS las cosas no son así. El paso data es un bucle en si mismo y SAS no tiene pereza en crear tablas intermedias. Así que la mejor solución para encontrar ese mínimo sería:

data matriz;
do j=1 to 1000;
array varib(100);
do i=1 to 100;
varib(i) = ranuni(56)*1000;
end;output;
end;
drop i j;
run;

proc summary data=matriz;
var varib:;
output out=minimos min=;
quit;

data _null_;
set minimos;
minimo_total = min(of varib:);
put minimo_total=;
run;

Se crea una matriz de datos aleatorios con un paso data de 100x1000 las variables se llaman varib ya que se generan con ese array. La mejor solución es hacer una tabla SAS con todos los mínimos por variable y meterlo en un conjunto de datos SAS. Por último el mínimo de los mínimos será el mínimo total o el más mínimo como diría alguno. Si programáis con SAS pensad en SAS. Saludos.

Trucos SAS. Calcular percentiles como Excel o R

Alguna vez habréis calculado un percentil en Excel o en R y os saldrá distinto de SAS. Esto se debe a que los métodos de cálculo son distintos tanto R como Excel utilizan el mismo método consistente en una interpolación en función de la distancia entre los registros que dan la posición del percentil. SAS dispone de 5 métodos distintos para calcular el percentil y por defecto emplea el número 5 y ninguno de los 4 métodos restantes es el que utilizan R o Excel. Pero podemos programar el método de un modo sencillo, cuesta más entender porque no lo implementa SAS que calcularlo. A continuación tenéis una sencilla macro que calcula el percentil con el método de Excel:

 
%macro percentil_excel(ds /*DATOS DE ENTRADA*/
	,varib     /*VARIABLE SOBRE LA QUE SE CALCULA*/
	,percentil /*PERCENTIL DESEADO*/);

%global pct;

proc sort data=&ds. (keep=&varib.) out=intermedio; by &varib.; run; 

data _null_;
 	datossid=open('intermedio');
 	no=attrn(datossid,'nobs');
 	call symput ("obs",compress(no));
 	datossid=close(datossid);
run;

*POSICIÓN (P*(N-1)/100)+1;
data _null_;
pos = (&percentil.*(&obs.-1)/100)+1;
call symput ('entera',int(pos));
call symput ('decimal',mod(pos,1));
run;

*APROXIMACION X(p) = X[k] + d(X[k + 1] - X[k]);
data _1;
set intermedio;
if _n_=&entera. or _n_=&entera. + 1;
run;

proc transpose data=_1 out=_1; run;

data _1;
set _1;
d = col2 - col1;
percentil = col1 + &decimal. * (col2 - col1);
call symput('pct',round(percentil,0.0001));
run;

proc delete data=_1 intermedio; run;
%mend;


%percentil_excel(DATOS,x,0.5);

%put &pct.;

Una breve explicación. Creamos una tabla sólo con la variable que deseamos analizar, determinamos el número de observaciones de la tabla y la posición donde debe caer el percentil como (percentil * (observaciones – 1) entre 100 más uno. Sacamos justo los puntos k y k + 1 y realizamos la interpolación en función de la distancia de esos dos puntos para obtener la macrovariable pct que tiene el resultado que deseamos. Espero que os sea de utilidad. Saludos.

Determinar el mímino tamaño muestral para detectar un cambio en la fracción no conforme

Este año he aprendido algo sobre metodología 6 sigma para el control de la calidad, me gustó mucho lo que aprendí. Para la realización de algunos ejercicios cree libros Excel y algún proceso SAS. Hoy quería traeros al blog una macro de SAS que nos permite determinar el tamaño mínimo muestral para detectar un cambio en la fracción no conforme con una determinada probabilidad. El programa es un bucle de SAS que crea los límites de control para la fracción no conforme y estandariza la diferencia del límite superior con la nueva fracción no conforme. Se calcula la probabilidad que deja este dato estandarizado y el paso del bucle será el número mínimo de muestras. Es más sencillo el código que la definición:

 %macro determina_tamanio(p0,p1,prob);
/*DETERMINAMOS LIMITES PARA CADA N*/
data _NULL_;
do n=1 to 5000;
/*LIMITE SUPERIOR*/
lsc=&p0.*n + 3*sqrt(&p0.*(1-&p0.)*n);
/*LINEA CENTRAL*/
lc=&p0.*n;
/*LIMITE INFERIOR, SIN NEGATIVOS*/
lic=max(&p0.*n - 3*sqrt(&p0.*(1-&p0.))*n,0);
/*DIFERENCIA CON RESPECTO AL LIMITE SUPERIOR*/
z=(lsc-(n*&p1.))/sqrt(n*&p1.*(1-&p1.));
prob=probnorm(z);
if round(prob,0.01)=&prob. then put n= prob=;
end;
run;
%mend;


%determina_tamanio(0.1,0.2,0.25);

Definimos el límite superior, la línea central y el límite inferior para la fracción p0. Sólo necesitamos el límite superior para el ejemplo que estamos tratando pero ahí lo tenéis. Entonces determinamos la diferencia con la nueva fracción de no conformes p1 y estandarizamos. Calculamos la probabilidad que deja la normal del dato estandarizado y si es parecida a la que nos pide el proceso la mostramos en la ventana log. En el ejemplo que he puesto determina el tamaño muestral mínimo para detectar un cambio en la fracción de no conformes de 0.1 a 0.2 con una probabilidad del 25%. Espero que a alguien le sea de utilidad. Saludos.

PROC FCMP para crear funciones en SAS

Unas pinceladas del PROC FCMP para SAS. Este procedimiento nos permite crear nuestras propias funciones que posteriormente podremos utilizar en nuestras sesiones de SAS. yo he programado mucho en SAS y tengo que decir que no utilizo mucho este procedimiento por la propia filosofía de SAS. Al final siempre se tiende a crear una macro antes que una función, pero hay que reconocer que el lenguaje macro de SAS en ocasiones no es sencillo y muchos olvidamos el PROC FCMP. En mi caso concreto hago unas macros muy enrevesadas antes que programarme una función. Para ilustrar el ejemplo de uso vamos a crear una función dif_anios para determinar la diferencia en años entre dos fechas SAS. El código es:

proc fcmp outlib=sasuser.fun.pru; 
function dif_anios(ini_date, fin_date); 
n1 = year(fin_date)-year(ini_date);
if month(fin_date)

El PROC FCMP guarda las funciones en una librería, en este caso se recomienda guardar en SASUSER y es necesario usar un nombre de 3 niveles aunque el resultado final de esta ejecución será un conjunto de datos SAS llamado FUN creado en la librería SASUSER que contiene las instrucciones necesarias para la función. La función necesita dos parámetros ini y fin date, dentro de ella empleamos código SAS, el mismo que si no usáramos la función. Por último retornamos un valor como resultado de nuestra función.

Para poder emplear la función sólo tenemos que hacer:

options cmplib=sasuser.fun; 

  data _null_;
   start = '15Feb2007'd;
   today = '27Mar2008'd;
   sd = dif_anios(start, today); 
     put sd=;
  run;

Con la opción cmplib compilamos rutinas en la librería especificada, ya os digo que lo recomendable es SASUSER o bien una librería común en la que se guarden todas las funciones. Una vez hagáis eso ya estáis en disposición de poder utilizar vuestra función. Saludos.

Haciendo ventanas con %WINDOW en SAS

No es habitual emplear SAS BASE para crear menús o ventanas, aunque con el PROC PMENU se han hecho maravillas. Hoy vamos a poner un ejemplo sencillo de uso de %WINDOW para hacer el menú más simple posible con SAS BASE, nuestro objetivo es consultar los datos de un cliente sobre una tabla. Creamos unos datos aleatorios para ilustrar el ejemplo y una macro para hacer consultas:

 data aleatorio(index=(id_cliente));
do id_cliente=1 to 11000;
	importe=ranuni(56)*450;
	output;
end;
run;
%macro selecciona(cli=);
proc sql;
select a.*
from aleatorio a
where id_cliente=&cli.;
quit;
%mend;

Partimos de una tabla con 2 variables id_cliente e importe y deseamos crear un menú en el que nos liste los datos para un id_cliente. Lo más sencillo que podemos hacer con SAS BASE es:

%window consulta color=grey        
  #2 @2 'Seleccionar id_cliente:'       
  #3 @26 id 8 attr=underline ;
%display consulta;   

%selecciona(cli=&id.);

Creamos la ventana consulta donde añadimos un texto en la línea (#) 2 posición (@) 2 y leemos la macro variable global id con longitud 8 en la línea 3 columna 26 ponemos un subrayado para que quede claro donde está. Posteriormente llamamos a la macro selecciona y como parámetro le pasamos el id. No es muy complicado pero tampoco podemos hacer grandes cosas. Saludos.