Monográfico. Datos agrupados en SAS

6 Nov

A continuación os planteo un monográfico más orientado a principiantes con SAS. Vamos a realizar un acercamiento a los conjuntos de datos SAS agrupados por variables. La premisa fundamental es: un conjunto de datos SAS está agrupado por una variable si está ordenado por ella. Para ordenar variables empleamos el PROC SORT:

PROC SORT DATA= ;
BY (DESCENDING) ;
RUN;

Repetimos un conjunto de datos SAS puede agruparse por una o varias variables si está ordenado por ellas. Algunas de las posibilidades que nos ofrecen este tipo de conjuntos de datos son:

• Buscar máximos y mínimos por grupos
• Crear ranking por grupos
• Realizar sumarizaciones
• Unir conjuntos de datos

Para ilustrar esto ejemplos vamos a emplear un conjunto de datos SAS de la librería SASHELP llamado SHOES que todos tenemos en nuestra sesión y que contiene las siguientes variables:

# Variable
1 Region
2 Product
3 Subsidiary
4 Stores
5 Sales
6 Inventory
7 Returns

La primera tarea encomendada es encontrar el mínimo y el máximo número de tiendas por producto en el total de las regiones:


data ejemplo;
set sashelp.shoes;
proc sort data=ejemplo; by product stores; quit;
proc freq; tables product; quit;

Trabajamos con una copia del dataset de SASHELP y lo primero es realizar la ordenación por la variable que nos agrupa nuestra tabla y después por la variable que deseamos estudiar. Con FREQ realizamos una tabla de frecuencias y observamos que tenemos 8 grupos, 8 tipos de productos. Una vez realizada la ordenación a la hora de leer el dataset hemos de emplear la instrucción BY:


data minimos_maximos;
set ejemplo;
by product;
if first.product then minimo=stores;
if last.product then maximo=stores;
if minimo ne . or maximo ne .; drop stores--Returns;
run;
proc print; quit;

Al emplear la instrucción BY disponemos de dos nuevas variables de sistema que sólo aparecen durante la ejecución del paso data: FIRST. y LAST.. Estas dos variables no producen salida alguna. Como es evidente FIRST toma valor 1 (verdadero) cuando estamos ante el primer registro del grupo y LAST toma el valor 1 cuando estamos ante el último registro del grupo. Como hemos limitado la salida a datos con mínimos o máximo obtenemos 2 registros por cada uno de los 8 grupos de productos.

Otra de las tareas habituales con conjuntos de datos agrupados es la realización de ranking por grupo. Si, por ejemplo, deseamos realizar un ranking de ventas por región tendremos que hacer:


proc sort data=ejemplo; by region sales; quit;
data ranking;
set ejemplo;
by region;
retain posicion ;
if first.region then posicion=1;
else posicion=posicion+1;
run;

Lo primero es ordenar por región y descendentemente por ventas. En este ejemplo empleamos una nueva instrucción RETAIN . Esta instrucción guarda el valor de la variable indicada para la siguiente iteración del paso data. Con BY hemos activado FIRST y LAST. De esta manera si estamos ante el primer registro por region la posición del ranking será 1, en caso contrario sumamos 1 a la variable retenida posicion.

Si deseamos crear sumarizaciones la metodología será igual que la anterior:


proc sort data=ejemplo; by region sales; quit;
data suma_region;
set ejemplo;
by region;
retain total_ventas;
if first.region then total_ventas=sales;
else total_ventas=sum(total_ventas,sales);
if last.region then output;
keep region total_ventas;
run;
La unión de conjuntos de datos SAS tendremos que analizarla en capítulos posteriores, pero es imprescindible recordar que, para unir conjuntos de datos SAS éstos han de estar agrupados por la variable que realiza la unión. Como siempre si tenéis cualquier duda, sugerencia o trabajo a tiempo parcial que me permita jugar más tiempo con mis hijos podéis contactar conmigo en rvaquerizo@analisisydecsision.es

22 respuestas a «Monográfico. Datos agrupados en SAS»

  1. IdClient IdArtic Fecha Secuencia
    1 23 01/01/2010 1
    1 24 01/01/2010 1
    1 45 05/01/2010 2
    1 67 05/01/2010 2
    1 56 20/01/2010 3
    1 89 20/01/2010 3
    1 90 20/01/2010 3
    2 67 01/01/2010 1
    2 6 01/01/2010 1
    2 7 08/01/2010 2
    2 45 08/01/2010 2
    2 23 08/01/2010 2

    A través de la tabla idcliente y fecha me gustaría crear la variable secuencia de tal forma que me indique las visitas de un cliente. Así, el cliente 1 realiza 3 visitas. En la primera visita y en la segunda compra dos artículos y en la tercera compra tres artículos. La tabla está ordenada en función de Idcliente y por fecha. Me podéis ayudar?.
    Yo hago lo siguiente pero no obtengo buenos resultados. Me gustaría añadir la función retain pero no sé como hacerlo. Si me pueden ayudar se lo agradecería

    data datos;
    set datos;
    by idcliente fecha;
    if first.fecha and first.idcliente then secuencia = 1;
    else secuencia+1;

  2. IdClient IdArtic Fecha Secuencia
    1 23 01/01/2010 1
    1 24 01/01/2010 1
    1 45 05/01/2010 2
    1 67 05/01/2010 2
    1 56 20/01/2010 3
    1 89 20/01/2010 3
    1 90 20/01/2010 3
    2 67 01/01/2010 1
    2 6 01/01/2010 1
    2 7 08/01/2010 2
    2 45 08/01/2010 2
    2 23 08/01/2010 2

  3. Mira esto:

    data datos (drop=secuencia);
    input IdCliente IdArtic Fecha ddmmyy10. Secuencia;
    format fecha ddmmyy10.;
    datalines;
    1 23 01/01/2010 1
    1 24 01/01/2010 1
    1 45 05/01/2010 2
    1 67 05/01/2010 2
    1 56 20/01/2010 3
    1 89 20/01/2010 3
    1 90 20/01/2010 3
    2 67 01/01/2010 1
    2 6 01/01/2010 1
    2 7 08/01/2010 2
    2 45 08/01/2010 2
    2 23 08/01/2010 2
    ;
    run;

    data datos;
    set datos;
    retain secuencia;
    by idcliente fecha;
    if first.idcliente then secuencia=0;
    if first.fecha then secuencia=secuencia+1;
    run;

    Utiliza variables auxiliares para entender mejor el funcionamiento.

  4. Hola, tengo que rellenar las celdas vacías

    1 2372 1
    2 2356
    3 2345
    4 2334 2
    5 2367
    6 2398

    las que estan debajo del 1 se bene llenar con 1´s y las que están debajo del 2 con 2´s, como podria hacerle con retain?

    Gracias!

  5. Hola,

    Una forma de hacerlo con una variable auxiliar:

    data datos;
    input id1 id2 num;
    datalines;
    1 2372 1
    2 2356 .
    3 2345 .
    4 2334 2
    5 2367 .
    6 2398 .
    ;run;

    data datos2;
    set datos;
    retain num_aux 0;
    if num= . then num_aux=max(num_aux,0);
    else num_aux=num;
    run;

    Espero que te sirva. Saludos.

  6. Hola tengo una base de datos muy grande, la estructura de la base de datos es: identificación del individuo(id), identificación del padre(idpad), identiticación de la madre (idmad) y sexo(sex). Quiero buscar en toda la columna de padres y madres si se encuentran como individuos. Ejemplo:
    id idpad idmad sex
    1 2 3 F
    2 4 5 M

    En éste caso el padre del individuo 1 se encuentra como individuo y quiero eliminar cualquiera de los dos renglones. Como le puedo hacer? Gracias

  7. si en mi caso necesito llenar los missing, con la información encontrada en la celda (fila o registro) de la anterior y que no es missing, para el caso de una variable texto es decir:
    Id Nombre Turno
    1 Mario Mañana
    2 Carlos
    3 Lucia
    4 Maria
    5 Rafael
    6 Luis Tarde
    7 Ana
    8 Erika
    9 Adriana
    10 Angelica Noche
    11 Anny
    12 Diana
    13 Xavi
    14 Tomas
    15 Efrain

    Y se espera llenar así:

    Id Nombre Turno
    1 Mario Mañana
    2 Carlos Mañana
    3 Lucia Mañana
    4 Maria Mañana
    5 Rafael Mañana
    6 Luis Tarde
    7 Ana Tarde
    8 Erika Tarde
    9 Adriana Tarde
    10 Angelica Noche
    11 Anny Noche
    12 Diana Noche
    13 Xavi Noche
    14 Tomas Noche
    15 Efrain Noche

  8. Tengo una tabla en la cual la información que se muestra allí es las conexiones que realizan unos asesores al computador especifico, como hago para crear un código que me resuman por gestor los días y la hora en la que se conecta y como genero una frecuencia de la misma información ??

    Gracias !!

  9. Pingback: Mínimo de una matriz de datos en SAS » Análisis y decisión

  10. Tengo un fichero de datos donde una de las variables es la fecha de la operación «aaaammdd». Necesito identificar las operaciones por semana, es decir, agrupar los días en semanas reales y llamar a cada semana con un nombre para identificarlas.
    Está claro que la forma más fácil es:
    IF (FECHA >= ‘20150420’ AND FECHA =’20150427′ AND FECHA<='20150503')
    THEN SEMANA = "20150427"; ……
    …………..

    Pero es un tanto rudimentario hacerlo así con toda las semanas del año, ¿se os ocurre alguna manera de hacerlo más mecánico?
    Gracias.
    Un saludo.

    • Raul te ha contestado con esta solución posible:
      https://analisisydecision.es/truco-sas-identificar-el-lunes-de-cada-semana-para-clasificar-por-semanas/

      Otra solución que te propongo es utilizar la opción ‘week.2’ dentro de la función intnx que hace incrementar las semanas partiendo del día lunes de cada semana en vez de domingo, y finalmente para simplificar la agrupación podrías crear una variable, por ejemplo semana_dentro_año, que contenga el número de semaña del año (aunque tendrás que corregirlo si tienes datos de diferentes años).

      Data ejemplo;
      format fecha lunes DDMMYY10.;
      format lunes_formato_textolargo eurdfwkx30.;

      fecha = ’01sep2015’d;

      do i=1 to 100;
      lunes=intnx(‘week.2′, fecha, i);
      lunes_formato_textolargo=lunes;
      semana_dentro_año=week(lunes,’w’);
      output;
      end;

      drop fecha i;
      Run;

  11. Pingback: Truco SAS. Identificar el lunes de cada semana para clasificar por semanas | Análisis y Decisión

  12. Hola!

    Este es mi primer mensaje y estoy flipando con este blog, me lo estoy empoyando entero, muchas gracias.

    Quiero hacer que en una variable llamada ‘como sea’, me haga la resta de la fila n+1 y la fila n

    Ejemplo;

    1 25 10 es decir: (35-25)
    2 35 5 es decir: (40-35)
    3 40 60 es decir: (100-40)
    4 100

    y así hasta el infinito. He probado con el first pero no me sale.

    Gracias a todos por adelantado!

  13. Me contesto a mi mismo. Lo he hecho con la función DIF que no sabía que existía. Previamente he ordenado el DS Ejemplo.

    Data ejemplo;
    set ejemplo;
    by DN;
    firstDN = first.DN;
    IF first.DN THEN Resta=.;
    ELSE Resta=dif(FR);
    IF Resta =. THEN delete;
    RUN;

    Lo que hago es agruparlo por la variable DN, después creo la variable firstDN para ver en qué momentos cambia (aunque no es necesario). Cuando cambia el grupo hago que la variable «Resta» sea 0 ya que no me interesan las diferencias de valores de FR entre distintos grupos de DN, y si estamos dentro de un mismo grupo que me haga la resta entre la fila siguiente y la anterior (con Dif). Luego limpio las filas que me dan de resta 0 ya que no me valen para el estudio y listo.

    Espero que le sirva a alguien.

    Saludos a todos!

  14. Hola!

    Me pueden ayudar necesito desacumular los días que hay de un renglón a otro por cada cliente es decir obtener la columna dias2 del siguiente ejemplo:

    Cliente dias dias2
    S1 30 30
    S1 61 31 es decir 61 – 30
    S1 91 30 es decir 91 – 61
    S1 121 30 es decir 121 – 91
    S1 142 21 es decir 142 – 121
    S2 30 30
    S2 61 31 es decir 61 – 30
    S2 92 31 es decir 92 – 61

    Gracias!

  15. buenas!!

    Soy totalmente nueva en SAS y tu blog me salva la vida en el trabajo

    Tengo una base de datos por trimestres desde el 95 al 2017, a cada trimestre (son cuatro) se le asocia un dato. Tengo que sumar los cuatro trimestres del mismo año para crear una variable nueva pero no se como hacerlo…

    Muchas gracias

  16. hola tengo en una tabla SAS, registros que estan emparejados es decir con el mismo Id y mismo anno en el primero tengo fecha desde yvacia fecha hasta y en el segundo registro tengo vacia fecha desde y rellena fecha hasta y quiero dejarlo en un solo registro que tenga rellena la fecha desde y la fecha hasta, es posible?, como?

    Gracias

Deja una respuesta

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