Trucos SAS. Primer y último elemento de un array

Breve entrada sobre el uso de arrays en SAS. Dada una tabla SAS como esta con una variable mes1, mes2, … mesN:

arrays_sas.PNG

Necesitamos identificar el primer y el último elemento no nulo de un array y el número de elementos no nulos de ese array. Veamos el ejemplo:

data datos;
input id mes1 mes2 mes3 mes4 mes5 mes6;
datalines;
1 . . . . . .
2 162.18 88.41 919.62 891.25 837.73 163.14
3 . 790.52 160.03 . 60.31 343.30
4 . . 482.45 755.39 . .
5 265.17 963.53 . . 392.06 .
6 . 214.95 616.17 183.01 778.48 57.42
7 191.52 . 208.50 50.55 705.72 .
8 711.76 . . . 193.20 658.45
9 782.67 172.49 539.42 663.28 4.53 358.51
10 695.12 367.74 . 573.47 366.30 951.98
;
run;

Para este proceso creamos un array que recorreremos 2 veces, una hacia delante para identificar el primer elemento y otra a hacia atrás para identificar el último elemento:

data datos;
set datos;
array m(*) mes:;
*PRIMER ELEMENTO;
num=0;
do i = 1 to dim(m);
if m(i) ne . then do;
  primero=m(i);
  num=i;
  i=dim(m);
end;
end;
*ULTIMO ELEMENTO;
do i = dim(m) to 1 by -1;
if m(i) ne . then do;
  ultimo=m(i);
  num=i-num;
  i=1;
end;
end;
drop i;
num=num+1;
run;

Como hemos indicado el array se recorre dos veces, la primera vez de forma ascendente para buscar el primer elemento y la segunda de forma descendente para encontrar el último, la diferencia más uno es el número de elementos no nulos que tiene ese array. Ejemplo de uso de arrays en SAS. Saludos.

14 comentarios en “Trucos SAS. Primer y último elemento de un array

  1. Una pequeña corrección en tu código, Raíl. Parece que la variable num te calcula el número de columnas entre la primera informada y la última no nula. Para calcular el número de elementos no nulos del array sería:


    data datos;
    set datos;
    array m(*) mes:;
    /*PRIMER ELEMENTO*/
    num=0;
    do i = 1 to dim(m);
    if m(i) ne . then do;
    primero=m(i);
    i=dim(m);
    end;
    end;
    /*ULTIMO ELEMENTO*/
    do i = dim(m) to 1 by -1;
    if m(i) ne . then do;
    ultimo=m(i);
    i=1;
    end;
    end;
    /*NUMERO DE NO NULOS*/
    do i = 1 to dim(m);
    if m(i) ne . then do;
    num=num+1;
    end;
    end;
    drop i;
    run;

  2. Buenas tardes Raúl,

    Tengo una duda, por si puedieras ayudarme,en macros estoy muy pegada… tengo una macro que he heredado que tengo que ejecutar 12 veces desde el cierre del año anterior, por ejemplo 201106 hasta el actual 201204 y el paso data que he generado funciona pero no se llamarla bien dentro… ¿podrías ayudarme?

    Gracias de antemano por la ayuda.

    Este es el código:

    /*En esta paso generaremos 12 meses de medias mensuales, desde el cierre anterior del mes actual hasta el cierre actual*/
    /*genera 12 medias mensuales*/
    data _null_;
    *generamos año y mes;
    anyo=int(&periodo_ini./100);
    mes= &periodo_ini. – anyo*100;

    *genera 12 meses;
    do a=1 to 12;
    mes=mes+1;
    if mes >12 then do;
    anyo=anyo+1;
    mes=1;
    end;
    periodo=anyo*100+mes;

    *genera 12 medias mensuales, AQUI FALLA!;
    %medias_mensuales(&periodos);

    end;
    run;

    Saludos cordiales.

  3. Buenas tardes Raúl,

    Te escribo un poco tarde porque no daba con la tecla… hata hoy!! que por fin lo he logrado!!! eso sí, con tu ayuda ;)

    Muchas gracias por tu rapidez en contestarme y por tu amabilidad.

    Saludos.

  4. Hola Raúl,
    Tengo una duda muy relacionada con este tema y la verdad es que con el SAS me manejo pero no llego al nivel de macros y bucles…
    Estoy trabajando en una tabla con clientes que tienen diferentes ingresos realizados en una fecha distinta.
    Lo que no se muy bien es como hacer un bucle que me marque, para cada cliente, cual ha sido el primer ingreso, el segundo, el tercero…esto es, que me indique el orden de cada ingreso para el cliente según la fecha.
    Ahora mismo lo estoy haciendo generando tablas complementarias a partir de la máxima fecha y asi voy marcando a cada cliente pero imagino que con una macro el proceso sería mucho mas sencillo…me podrías ayudar???
    Muchisimas gracias!!
    Un saludo

  5. Os dejo una versión modificada del programa en el que se realiza todo en una sóla iteración.

    Primer elemento, último y recuento de no nulos.

    data datos_2version;
    set datos;
    array m(*) mes:;
    *PRIMER ELEMENTO;
    do i = 1 to dim(m);
    if i = 1 then num=0;
    if m(i) ne . then do;
    if primero eq . then primero=m(i);
    ultimo=m(i);
    num=num+1;
    end;
    end;
    drop i;
    run;

  6. Estimado,
    necesito su ayuda urgente
    resulta que tengo unos datos de esta forma

    Campo1 campo2
    2002 10
    2343 .
    2152 .
    1234 8
    2131 .

    Necesito ir recorriendo el campo 2 y agregar el numero anterior no nulo(10) hasta que aparezca otro numero en el campo no nulo(8), es decir dejarla así.
    (campos insertados con el codigo)
    Campo1 campo2
    2002 10
    2343 (10)
    2152 (10)
    1234 8
    2131 (8)

    Favor tu ayuda

    Gracias

  7. Hola Rodrigo,

    Necesitas usar retain como una sentencia dentro de un paso DATA:

    data datos;
    input Campo1 campo2;
    datalines;
    2002 10
    2343 .
    2152 .
    1234 8
    2131 .
    ;run;

    data datos;
    set datos;
    retain suma 0;
    suma = sum(suma,campo2);
    run;

    Saludos.

  8. Quisiera saber cómo puedo rellenar los valores vacíos entre dos variables.

    Por ejemplo, en la base de ejemplo:

    data datos;
    input id mes1 mes2 mes3 mes4 mes5 mes6;
    datalines;
    1 . . . . . .
    2 162.18 88.41 919.62 891.25 837.73 163.14
    3 . 790.52 160.03 . 60.31 343.30
    4 . . 482.45 755.39 . .
    5 265.17 963.53 . . 392.06 .
    6 . 214.95 616.17 183.01 778.48 57.42
    7 191.52 . 208.50 50.55 705.72 .
    8 711.76 . . . 193.20 658.45
    9 782.67 172.49 539.42 663.28 4.53 358.51
    10 695.12 367.74 . 573.47 366.30 951.98
    ;
    run;

    Quisiera llenar los espacios vacios entre el primer y el último registro con un cero, esto haría que por ejemplo, el registro número 5 quedara así:

    265.17 963.53 0 0 392.06 .

    ¿Alguien me podría ayudar?

Deja un comentario

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