Archivos de la categoría SAS

Truco SAS. Tablas de una librería en una macro variable

Me plantean una duda, como crear un conjunto de datos con las tablas de una librería en sas y posteriormente generar una macro variable con ellos, esta es una entrada análoga a otra del blog pero sirve para recordar como funciona el ODS de SAS y el PROC DATASETS un procedimiento que no he usado habitualmente. Lo primero que vamos a hacer es observar que resultados arroja el PROC DATASETS en su sintaxis más sencilla, ver los contenidos de una librería:

 ods trace on;
proc datasets lib=datos;
quit;
ods trace off;

Recordamos que ODS (Output Delivery System) TRACE ON nos permite ver en la log de SAS los elementos que se obtienen como resultado, en este caso, el más sencillo, tenemos:

Output Added:
-------------
Name: Directory
Label: Directory Information
Template: Base.Datasets.Directory
Path: Datasets.Directory
-------------

Output Added:
-------------
Name: Members
Label: Library Members
Template: Base.Datasets.Members
Path: Datasets.Members
-------------

Evidentemente nos interesa Members para poner en una tabla SAS todos los miembros de la librería:

ods output Members=tablas;
proc datasets lib=datos ;
quit;

Ahora tenemos que meter en una macrovariable todos los elementos del campo name de la tabla SAS que hemos generado. Para ello en vez de emplear el habitual PROC SQL podemos usar una concatenación sobre los valores de name que diera como resultado final la macrovariable con la lista de las tablas: Sigue leyendo Truco SAS. Tablas de una librería en una macro variable

Bucle de fechas con SAS para tablas particionadas

Partimos de un mes inicial hasta un mes final es necesario crear una tabla SAS con dos variables, el inicio del mes y el final del mes. Trabajo con fechas en SAS que todos sabemos es una tarea un "poco ardua".  El título de la entrada también es un poco peculiar pero es la respuesta a la duda que planteaba un lector:

Cogemos dos fechas en formato yyyymmaa
Ej: 20150101 a 2016131

Necesito una salida como la siguiente
20150101   20150131
20150201   20150228
20150301   20150331
20150401   20150430
.

20161101  20161130
20161201  20161231

Pero para que los datos pedidos en este periodo salgan en una tabla por mes con un proc sql  ya diseñado que funciona pero sin particionarlo en una tabla por mes en el log

Se me han ocurrido varias formas de hacerlo pero a continuación os planteo la siguiente. Como referencia hemos de irnos a una entrada anterior del blog, una entrada del 2008 cuando puse en marcha analisisydecision.es

*IDENTIFICA EL ULTIMO DIA DE UN MES;
%macro finmes(fec);
intnx("month",&fec.,1)-1
%mend;


data bucle (drop=i);
do i=201501 to 201612;
    if mod(i,100)=13 then i = i + 88;
else do;
    inicio = i * 100 + 1;
    *PRIMERO TRANSFORMAMOS EN FECHA SAS;
    fin = mdy(mod(i,100),1,int(i/100));
    *DESPUES OBTENEMOS EL ULTIMO DIA DEL MES;
    fin = %finmes(fin);
    *POR ULTIMO LO TRANSFORMAMOS A NUMERICO;
    fin = year(fin)*10000+month(fin)*100+day(fin);
    output;
end;
end;
run;

Lo he hecho de una forma sencilla, se trata de un bucle DO desde el mes inicial a el mes final, en realidad son unos 90 números sin embargo si el módulo del número, el mes, está entre 1 y 12 entonces identifica el primer día del mes e identifica el último día del mes transformando el número a fecha SAS primero, obteniendo el último día después y por último lo transforma del modo más sencillo a un número que pueda entender la partición. Es un bucle SAS susceptible de ser parametrizado. Saludos.

Como obtener los centroides de municipios con SAS. Mapas con SGPLOT

mapa_municipios_sas2

Un amigo y lector del blog me ha pedido un mapa de códigos postales donde poder identificar los centroides para andar calculando distancias a otros puntos. Yo no tengo un mapa de España por códigos postales para poder usar con fines comerciales, pero si cuento en el blog como poder obtenerlo bajo ciertas condiciones. Lo que si puedo contar a Juan es como hacer un mapa por municipios con SAS, aunque ya he hablado de ello hay ciertos aspectos que pueden ser interesantes. y todo empieza donde siempre http://www.gadm.org/country la web donde tenemos los mapas "libres" por países, seleccionáis Spain y el formato shapefile una vez descargados los mapas en vuestros equipos empezamos con el trabajo en SAS:

proc mapimport datafile="\directorio\mapa\ESP_adm_shp.shp"
out = work.espania;
run;
proc contents;quit;

mapa_municipios_sas1

El procedimiento MAPIMPORT ha creado un conjunto de datos SAS donde tenemos caracterizados todos los polígonos que componen el shapefile. Entonces si tenemos que calcular el centroide de un municipio con SAS sugiero realizar un PROC SQL de la siguiente forma Sigue leyendo Como obtener los centroides de municipios con SAS. Mapas con SGPLOT

Qué pasa si uso una regresión de poisson en vez de una regresión logística

Para un tema de mi trabajo voy a utilizar una regresión de poisson en vez de una regresión logística, el evento es si o no y no tiene nada que ver el tiempo, ni se puede contabilizar como un número, pero a efectos prácticos es mejor para mi usar una regresión de poisson. Entonces, ¿qué pasa si hago una poisson en vez de binomial? Como siempre si mi n es muy grande hay relación entre ambas distribuciones. Pero yo quiero saber si me puede clasificar mis registros igual una regresión de poisson y una binomial y se me ha ocurrido hacer un ejercicio teórico muy simple.

Construyo con SAS 10.000 datos aleatorios con las variables independientes x e y normalmente distribuidas y la variable dependiente z que es una función logística "perfecta" de x e y:

data logistica;
do i=1 to 10000;
x=rannor(8);
y=rannor(2);
prob=1/(1+exp(-(-10+5*x-5*y)));
z=ranbin(8,1,prob);
output;
end;
drop i;
run;

data entrenamiento test;
set logistica;
if ranuni(6)>0.8 then output test;
else output entrenamiento;
run;

proc freq data=entrenamiento;
tables z;
quit;

Separo los datos en entrenamiento y test y vemos que un 8% aproximadamente de mis registros tienen valor 1. Sobre estos datos hago una logística y una poisson y veo los parámetros Sigue leyendo Qué pasa si uso una regresión de poisson en vez de una regresión logística

Test de bondad de ajuste con SAS

Pregunta que me han hecho hoy. Cómo hacer un test de bondad de ajuste con SAS y la respuesta que he dado:

data datos_aleatorios;
do i=1 to 200000;
*GENERAMOS UNAS VARIABLES ALEATORIAS;
variable_gamma = rangam(89,450); 
variable_exponencial = ranexp(23)*100+0.17045;
output;
end;
run;

*ods select ParameterEstimates GoodnessOfFit ;
proc univariate data=datos_aleatorios;
   var var:;
   histogram /   gamma;
run;

Mucho cuidado con estos test de hipótesis. Yo suelo conformarme con ver la tabla de cuantiles. Saludos.

 

Truco SAS. Como leer PC Axis con SAS

Estoy leyendo información del INE que tiene que terminar cargándose en SAS y estos datos están en formato PC Axis. Existen macros en SAS para generar datasets a partir de PC Axis pero la verdad es que no he llegado a entender muy bien como funcionan y tras varios errores la mejor opción que he encontrado es emplear R y el paquete pxR que han creado algunos miembros de la Comunidad de R-Hispano. Como realizo esta tarea es más que sencillo:

En R realizamos la importación del archivo *.px:

nacionalidad = read.px("ubicacion\\seccion_censal_nacionalidad.px")
nacionalidad = data.frame(nacionalidad)
write.csv( nacionalidad, file = "ubicacion\\nacionalidad.csv" )

Hemos generado un csv que importamos desde SAS:

proc import datafile="ubicacion\nacionalidad.csv"
     out=nacionalidades
     dbms=csv
     replace;
     getnames=yes;
run;

También quería aprovechar esta entrada para comentaros que es preferible usar los viejos csv para mover archivos entre R  y SAS que usar librerías como SASxport que generan ficheros "portables" de SAS, aunque los ficheros "portables" garantizan que se puedan leer con distintas versiones de SAS este paquete tarda mucho (demasiado) tiempo en crear los archivos. Y si alguien tiene una versión más sencilla de la macro de SAS que mande el link. Saludos.

KNN con SAS. Mejorando K-Means

Imagen de previsualización de YouTube

La clasificación por k vecinos más cercanos es EL MÉTODO supervisado no paramétrico. El KNN, si empleamos las siglas en inglés, clasifica las observaciones en función de su probabilidad de pertenecer a uno u otro grupo, en el video que encabeza la entrada queda muy bien explicado. El caso es que tenemos la posibilidad de realizar esta clasificación con SAS STAT y el PROC DISCRIM y me parece interesante dedicarle unas líneas. Hace años ya hablamos de segmentación con SAS  y vamos a emplear los mismos datos para ilustrar esta entrada. Primero generamos un conjunto de datos con datos simulados de 3 esferas que clasificamos en 3 grupos:

data pelota;
do i = 1 to 1000;
a=0; b=5; x = a+(b-a)*ranuni(34);
a=0; b=5; y = a+(b-a)*ranuni(14);
grupo=1;
distancia = sqrt(((x-2.5)**2)+((y-2.5)**2));
if distancia < 2.5 then output;
end;
run;

data pelota1;
set pelota;
grupo=1;
run;

data pelota2;
set pelota;
x = x+4.5;
grupo=2;
run;

data pelota3;
set pelota;
x = x+2.5;
y = y+3.5;
grupo=3;
run;

data datos;
set pelota1 pelota2 pelota3;
run;

proc gplot data=datos;
	plot y * x = grupo; 
run;quit;

KNN_SAS1

Si realizamos un análisis mediante k-means sin asignar centroides obtenemos esta clasificación Sigue leyendo KNN con SAS. Mejorando K-Means

Interpretación de los parámetros de un modelo GLM

Muchos estudiantes  terminarán trabajando con GLM que siguen buscando relaciones lineales en multitud de organizaciones a lo largo del planeta. Y hoy quería ayudar a esos estudiantes  a interpretar los parámetros resultantes de un GLM, más concretamente los resultados de un PROC GENMOD de SAS aunque lo que vaya a contar ahora se puede extrapolar a otras salidas de SAS o R. En la línea de siempre no entro en aspectos teóricos y os remito a los apuntes del profesor Juan Miguel Marín. Con un GLM al final lo que buscamos (como siempre) es distinguir lo que es aleatorio de lo que es debido al azar a través de relaciones lineales de un modo similar a como lo hace una regresión lineal, sin embargo los GLM nos permiten que nuestra variable dependiente no sólo siga una distribución normal, puede seguir otras distribuciones como Gamma, Poisson o Binomial. Además un GLM puede trabajar indistintamente con variables categóricas y numéricas pero yo recomiendo trabajar siempre con variables categóricas y en la práctica cuando realizamos un modelo de esta tipo siempre realizaremos agrupaciones de variables numéricas. Si disponemos de variables agrupadas, de factores, los parámetros de los modelos nos servirán para saber como se comporta nuestra variable dependiente a lo largo de cada nivel del factor.

El modelo siempre fija un nivel base del factor, un nivel que promedia nuestros datos y el resto de niveles corrigen el promedio en base al coeficiente estimado. Imaginemos que modelizamos el número de abandonos en 3 carreras de coches, cuando la carrera se disputa en un circuito A el número de abandonos es 5, sin embargo en el circuito B son 10 y en el circuito C son 15. Si fijamos como nivel base de nuestro factor circuito el B tendríamos un modelo de este modo abandonos = 10 + 0.5*es circuito A + 1*es circuito B + 1.5*es circuito C + Error. El nivel base promedia nuestro modelo por lo que va multiplicado por 1 y el resto de niveles se corrigen por su multiplicador. Esta es la base de la modelización multivariante en el sector asegurador. Veamos en un ejemplo como se articulan los parámetros de estos modelos. Simulamos unos datos con la probabilidad de tener un siniestro por edad, zona y edad:

data datos_aleatorios;
do idcliente = 1 to 2000;
if ranuni(1) >= 0.75 then sexo = "F";
else sexo="M";
edad = ranpoi(45,40);
if ranuni(8)>=0.9 then zona=1;
else if ranuni(8)>0.7 then zona=2;
else if ranuni(8)>0.4 then zona=3;
else zona=4;
output;end;
run;

data datos_aleatorios;
set datos_aleatorios;
if zona=1 then incremento_zona = 0.1+(0.5-0.1)*ranuni(8);
if zona=2 then incremento_zona = 0.1+(0.7-0.1)*ranuni(8);
if zona=3 then incremento_zona = 0.1+(0.2-0.1)*ranuni(8);
if zona=4 then incremento_zona = 0.1+(0.9-0.1)*ranuni(8);

incremento_edad=exp(1/edad*10)-1;

sini = (ranuni(9) - sum(incremento_zona, -incremento_edad))>0.8 ;
run;

Se da una probabilidad aleatoria de tener un siniestro que se ve incrementada o decrementada por la zona y la edad, el sexo, aunque aparece, no influye. El número de siniestros suponemos que sigue una distribución de poisson. Para entender mejor como funciona un GLM vamos a agregar los datos por los factores en estudio y contamos el número de clientes sumando el número de siniestros:

proc sql;
create table datos_agregados as select
sexo,
case
when edad<= 30 then "1 menos 30"
when edad<= 40 then "2 31-40"
when edad<= 50 then "3 41-50"
else "4 mas 50" end as edad,
zona,
log(count(idcliente)) as exposicion,
sum(sini) as sini
from datos_aleatorios
group by 1,2,3;
quit;

Nuestros datos tienen que ir ponderados por el logaritmo del número de clientes, será nuestro offset, ya que no es lo mismo tener un siniestro en un grupo de 2 clientes que un siniestro en un grupo de 20 clientes. Ponderados por el logaritmo porque siempre cuesta menos trabajar con números pequeños y además tienen unos superpoderes de los que no somos conscientes hasta que trabajamos con ellos. Ahora estos datos son los que emplearemos para el modelo:

proc genmod data=datos_agregados;
class sexo edad zona;
model sini = sexo edad zona / dist = poisson
link = log
offset = exposicion;
run;

GENMOD como todos los procedimientos de SAS necesita que le indiquemos las variables categóricas, en model especificamos el modelo y las opciones son los aspectos más interesantes. En dist especificamos la distribución de nuestra variable dependiente en link la función de enlace que vamos a emplear y como offset para ponderar la variable exposición que hemos creado a la hora de agregar los datos. Y los parámetros que estima este modelo son:

parametros_modelo_GENMOD1

El intervalo de confianza de algunos estimadores contiene el valor 0, esos factores no son significativos como es el caso del sexo o bien puede haber agrupación de niveles de factores como es el caso de la edad entre 31 y 50 años o la zona 2 que puede unirse con otra zona. Vemos que el estimador del nivel base siempre es el último nivel del factor (esto puede cambiarse) y toma valores 0 y no 1 como habíamos usado en el ejemplo, para transformarlo en 1 sólo hemos de realizar el exponencial:

Parameter   Estimate
Intercept 0.062
sexo F 0.932
sexo M 1.000
edad 1 menos 30 2.951
edad 2 31-40 2.062
edad 3 41-50 1.494
edad 4 mas 50 1.000
zona 1 1.854
zona 2 1.218
zona 3 3.091
zona 4 1.000
Scale 1.000

Vemos que la zona 3 tiene casi el triple de siniestralidad que la zona 4 y lo mismo sucede con las edades jóvenes frente a las mayores edades, en cuanto al sexo que no fue significativo tenemos que las mujeres tienen un 7% menos de siniestralidad. Algunos resultados, aunque no salgan estadísticamente significativos, es evidente que pueden interesarnos comercialmente ya que mi producto puede dar un descuento a las mujeres y aunque sea pequeño se puede mantener, igual razonamiento para algunas zonas o grupos de edad susceptibles de unirse entre ellos. Este ejemplo es muy burdo pero aquellos que empiecen a trabajar con GLM se van a encontrar situaciones de este tipo, es necesario interpretar los parámetros estimados para describir como funciona el modelo pero igual de  importante es la agrupación de factores y el posterior suavizado de los parámetros.

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.