Guía completa para dominar Bucles Do-loop, Do-while y Do-Until en SAS

Do-loop, Do-while y Do-Until en SAS ¿Necesita aprender a menudo ejecutar los mismos extractos una y otra vez en sus programas SAS? ¿Deseas desarrollar una habilidad más como programador SAS?

Los bucles iterativos DO loops, DO UNTIL y DO WHILE en SAS proporcionan una amplia variedad para realizar acciones repetidas en un conjunto de datos, una y otra vez sin tener que escribir código duplicado o ejecutar las mismas sentencias varias veces de forma manual.

Estaremos considerando las diferencias entre los bucles iterativos y los bucles condicionales, proporcionando ejemplos de cómo usar cada uno de ellos . Los arreglos (arrays) en SAS también serán comentados para usarlos en tareas repetitivas más complejas .

Entre los principales temas que se tratarán figuran los siguientes:

  • Los Bucles iterativos (Do-Loop)
  • Bucles Condicionales (DO UNTIL vs DO WHILE)
  • Combinación de bucles condicionales e iterativos
  • Arreglos
    • Bucles iterativos
    • DO OVER

Software

Antes de continuar, asegúrate que tienes instalado o acceso SAS Studio . ¿No tienes SAS? Descarga SAS University Edition. Es gratis!

Datos que se usarán

En esta ocasión utilizamos los datos que se encuentran disponibles en la biblioteca de SASHELP: FISH, BASEBALL y PRICEDATA

Bucles iterativos (DO-LOOP)

Los bucles iterativos son la forma más simple para hacer tareas repetitivas y que pueden ser ejecutados dentro de un Paso de Datos SAS. Las acciones de un bucle iterativo son incondicionales, lo que significa que si se define un bucle para que se ejecute 100 veces, se ejecutará 100 veces sin parar (a menos que se produzca un error durante el procesamiento, por ejemplo la falta de espacio).

Estos bucles iterativos son útiles para el contar de forma incremental o para hacer cálculos repetitivos n númmero de veces. Veamos un par de ejemplos de bucles SAS en los que se puede utilizar el comando DO-LOOP.

Ejemplo 1 – Incremento del saldo de una cuenta

En este ejemplo de DO-LOOP en SAS vamos a calcular cuál es el saldo de una cuenta después de que se hagan 6 depósitos en ella, 2,000 pesos.

Primero. Supongamos que el saldo actual es de 2,000 pesos, para indicar esta asignación en un programa de SAS, escribimos saldo = 2000.

El siguiente paso es especificar la variable índice o contador. la letra más usada es la “i”, que en este caso es la abreviación de la palabra índice. Se puede utilizar cualquier nombre de variable que siga las reglas de la nomenclatura para variables de SAS.

Video sobre Do Loop Básico en SAS

En el siguiente video se muestra la forma de utilizar el doo loob de forma básica en SAS

[video_lightbox_youtube video_id=”pSf1u9qhDg0″ width=”640″ height=”480″ auto_thumb=”1″]

Como queremos iterar 6 veces para determinar el saldo final, la variable índice se restringe al rango desde 1 hasta 6. La variable iterará en incrementos de 1, hasta que alcance el valor máximo especificado en la sentencia:

do i = 1 to 6;

Una vez que se ha configurado el bucle, es necesario especificar lo que debe suceder durante cada iteración. En este caso, se sumarán 2000 durante cada iteración:

saldo + 1000;

El último paso es cerrar el bucle con una declaración END. Aquí la sintaxis completa:

Data cuenta;
   saldo = 2000;
   do i = 1 to 6;
      saldo + 2000;
   end;
run;

En el conjunto de datos de salida que se muestra a continuación, hay dos variables. La primera variable es “balance”, con el saldo después de 6 iteraciones y la segunda variable es “I”, que muestra el valor final de i al copletarse todas las iteraciones:

Si quieres eliminar la variable i usa la opción DROP al final del código, para propósitos del ejemplo dejamos la variable i.

Ejemplo 2 – Generación de registros con bucle incremental

Además de calcular un número final, se puede utilizar un bucle DO-LOOP para generar registros, almacenando el resultado de cada iteración en el dataset.

En este ejemplo, queremos saber cuál es el saldo de una hipoteca después de 1 año de pagos quincenales de 500 pesos. También deseamos ver el saldo después de cada pago.

Para simplificar, en este ejemplo ignoramos cualquier interés que normalmente se tendría en cuenta en el cálculo de la hipoteca.

Para crear un conjunto de datos que muestre el saldo la hipoteca después de cada pago quincenal, podemos usar un bucle iterativo.

Primero, creamos una nueva variable, el balance, y lo fijamos igual a 300000. A continuación, hacemos definimos el número de semanas a calcular: 52 (1 año). Los pagos son quincenales (cada 2 semanas). En código SAS, iteraremos la variable índice “i” de 1 a 52 de dos en dos , debido a los pagos quincenales durante 52 semanas.

Para mantener un registro de cada iteración en el dataset de salida, incluimos una declaración OUTPUT dentro del bucle, antes del END:

data Hipoteca;
   balance = 300000;
      do i = 1 to 52 by 2;
      balance = balance - 500;
      output;
   end;
run;

Como se puede ver en la salida. se muestra el saldo en cada intervalo quincenal el cálculo, junto con el valor actual de i:

Ejemplo 3 – Bucles anidados

Cuando un bucle se itera dentro de otro bucle, se conoce como un bucle anidado. Los bucles anidados son más fáciles de entender con un simple ejemplo.

Crearemos 3 registros para cada valor de ID, donde ID es un número del 1 al 4. Para cada ID, debe haber un registro para cada valor de SUBID, que va de 1 a 3. En total 12 registros, con 3 registros para cada valor de ID.

Primero empezamos por hacer un bucle a través de la variable índice i de 1 a 4. Dentro de este bucle, establecemos ID = i para que la variable ID tome el valor de i después de cada iteración

do i = 1 to 4;
ID = i;

El segundo bucle utiliza la variable índice j, empezando en 1 y terminando en 3, donde SUBID toma los valores de j después de cada iteración:

do j = 1 a 3;
SUBID = j;

La sentencia OUTPUT se incluye para que se cree un nuevo registro cada vez que haya una iteración. Ambos bucles se cierran con una sentencia END. Las variables i y j se eliminan del conjunto de datos.

Aquí está la sintaxis completa:

data ids;
   do i = 1 to 4;
     ID = i;
     do j = 1 to 3;
       SUBID = j;
       output;
     end;
  end;
   drop i j;
run;

La ejecución del código anterior producirá el conjunto de datos de salida deseado con un total de 2 variables (ID y SUBID) y 12 filas (3 registros para cada uno de los 4 valores posibles de ID), como se muestra aquí.

Bucles condicionales (DO-UNTIL y DO-WHILE)

Otro tipo de bucles que puedes usar en un paso de datos SAS son los bucles condicionales. Hay dos tipos de bucles condicionales:

  • Los bucles DO UNTIL, continúan ejecutándose hasta que la condición que has especificado se hace realidad.
  • Bucles DO WHILE, se siguen ejecutando mientras la condición que ha especificado se mantiene verdadera.

Comencemos con un ejemplo simple para cada bucle: DO UNTIL y DO WHILE.

Ejemplo 1 – Calcular número de pagos usando DO UNTIL SAS

Usando un bucle DO UNTIL, puedes calcular fácilmente el número de pagos que se necesitan para pagar un préstamo de 30,000 pesos para un coche.

Para empezar, fijamos el préstamo = 30000 y los pagos iguales a 0, todavía no se han hecho ninguno. A continuación se utiliza una sentencia DO UNTIL, seguida de la condición que debe cumplirse para detener el bucle.

En este caso, el bucle se ejecutará hasta que el valor del préstamo sea igual a cero, por lo que encerramos préstamo = 0 entre paréntesis inmediatamente después de la sentencia DO UNTIL, para indicar a SAS que el bucle se ejecutará hasta que el valor del préstamo sea exactamente cero.

Dentro del bucle DO UNTIL, restamos 500 del valor del préstamo ya que asumimos que se hace un pago de 500 dólares cada mes. El valor de los pagos se incrementa en 1 para que podamos contar el número de pagos mientras se paga el préstamo. Por último, el bucle DO UNTIL se cierra con una declaración END.

data carloan_until;
   préstamo = 30000;
   pagos = 0;
   do until (loan = 0);
      loan = loan - 500;
      pagos = pagos + 1;
   end;
run;

Como se puede ver en la salida, el préstamo llega a cero después de 60 pagos:

Ejemplo 2 – Calcular número de pagos usando DO WHILE SAS

Aunque es ligeramente diferente, un bucle DO WHILE también puede ser usado para obtener el mismo resultado. Comencemos tomando el mismo código que usamos en el ejemplo anterior, pero reemplazando el DO UNTIL con un DO WHILE:

data carloan_until;
   préstamo = 30000;
   pagos = 0;
   do while (loan = 0);
      loan = loan - 500;
      pagos = pagos + 1;
   end;
run;

Se observa que el bucle no se iteró en absoluto, debido al valor de la variable préstamo sigue siendo la cantidad original de 30000 y los pagos son iguales a cero.

La principal diferencia entre el bucle DO WHILE y DO UNTIL es que la expresión DO UNTIL se evalúa en la parte inferior del bucle, mientras que la expresión DO WHILE se evalúa en la parte superior del bucle. El bucle DO UNTIL siempre se ejecutará al menos una vez, mientras que DO WHILE puede no ejecutarse en absoluto si la expresión DO WHILE no es verdadera desde el principio.

El bucle no se ejecuta mientras el préstamo es igual a cero. Como el préstamo es igual a 30000 al comienzo del programa, el bucle no se ejecuta en absoluto.

Para la sentencia DO WHILE, el bucle continuará ejecutándose mientras la declaración sea verdadera, por lo que necesitamos modificar la condición para que SAS sepa que debe seguir ejecutando el programa MIENTRAS el saldo del préstamo sea aún mayor que cero.

Así que, simplemente reemplazamos la condición dentro del paréntesis de loan = 0 a loan > 0:

data carloan_while;
data carloan_until;
   préstamo = 30000;
   pagos = 0;
   do while (loan > 0);
      loan = loan - 500;
      pagos = pagos + 1;
   end;
run;

Como se puede ver en la salida se muestran los resultados, ahora son los mismos que los de DO UNTIL; el préstamo ha alcanzado un valor de 0 después de 60 iteraciones.

Combinando bucles condicionales e iterativos

Los bucles pueden mejorarse aún más combinando los condicionales e iterativos en uno sólo.

Ejemplo 1 – Determinar el número de años para ahorrar 20,000

En este ejemplo, se calcula cuánto dinero se necesita aportar mensualmente y cuántos años llevaría ahorrar 20,000 pesos. El número de años no excede a 18.

Se fija el valor del fondo=0 ya que aún no se tiene dinero en la cuenta de ahorros. El formato de dollar8.2 se aplica a la variable del fondo para que los valores de salida se formateen como moneda. Afortunadamente se puede usar este formato para moneda mexicana.

Para el bucle, se establece la variable de índice i para que empiece en 1 y termine después de 18, límite deseado. Como sólo queremos ahorrar 20,000 dólares, añadimos la condición de “UNTIL”:

do i = 1 to 18 until(fund >= 20000);

Con estas condiciones, SAS ejecutará el bucle hasta que se cumplan los 18 años o el fondo supere los 20,000.

Si se aportan 1000 al año en una cuenta de ahorros que proporciona una tasa de interés anual del 1%. Para tener en cuenta esto, el valor del “fondo” se incrementa en 1000 con cada iteración, y luego se multiplica por 1.01 para añadir un 1% de interés al valor del fondo. La variable “Años” se establece igual a la variable de índice i para que podamos rastrear fácilmente cuántos años llevará alcanzar los 20,000.

data college_fund;
 
   fund = 0;
   format fund dollar8.2;
 
   do i = 1 to 18 until(fund >= 20000);
      fund = (fund + 1000) * 1.01;
      years = i;
      output;
  end;
 drop i;
run;  

El resultado muestra, que si ingresa 1,000 al año en una cuenta de ahorros que gana un 1% de interés anual, estaría justo por debajo de la marca de 20,000 después de 18 años:

Modificando la cantidad del depósito anual a 1200, podemos ver un resultado diferente:

data college_fund;
 
 fund = 0;
 format fund dollar8.2;
 
 do i = 1 to 18 until(fund >= 20000);
  fund = (fund + 1200) * 1.01;
  years = i;
    output;
 end;
 
 drop i;

run;  

Ahora se muestran que el bucle ahora dejó de ejecutarse después de 16 iteraciones, ya que 16 años fueron suficientes para que el fondo universitario superara el umbral de los 20.000 dólares.

¿Cómo usar Arreglos y Bucles juntos?

El procesamiento de arreglos en SAS es un método por el cual podemos realizar la misma acción sobre más de una variable a la vez. El procesamiento de arreglos puede ser útil para una variedad de tareas como la realización de cálculos repetitivos sobre múltiples variables o la creación de múltiples variables con los mismos atributos.

Veamos algunos ejemplos en los que las matrices (arrays) pueden ser útiles.

Ejemplo 1 – Uso de arreglo y bucle para generar múltiples variables

El conjunto de datos SASHELP.FISH contiene longitudes y una medición de ancho para una variedad de peces. Las longitudes y anchuras se registran en centímetros y se almacenan en 4 variables diferentes, Longitud1, Longitud2, Longitud3 y Width.

Vamos a convertir las longitudes y anchuras en centímetros a pulgadas para almacenar los valores convertidos en 4 nuevas variables denominadas Longitud1_in, Longitud2_in, Longitud3_in y width_in. Para convertir centímetros a pulgadas, se multiplica por 0,3937. En el código de abajo también añadimos una declaración de formato para mostrar sólo 2 decimales y sólo las variables Length1, Length2, Length3 y width:

data fish_inches;
  set sashelp.fish;
 
  length1_in = length1 * 0.3937;
  length2_in = length2 * 0.3937;
  length3_in = length3 * 0.3937;
  width_in = width * 0.3937;
 
  format length1_in length2_in length3_in width_in 6.2;
 
  drop length1 length2 length3 width;
 
run;

Como puedes ver la salida ahora tienes 4 nuevas variables, longitud1_in, longitud2_in, longitud3_in y anchura_in:

Aunque este código el resultado deseado, el código se puede mejorar, para no escribir el mismo cálculo en 4 variables, no es una programación ni elegante ni eficiente. Esto se vuelve especialmente cierto cuando necesitas realizar cálculos repetidos en un número aún mayor de variables.

Código SAS con arreglos (array)

Primero, necesitamos definir un arreglo con una declaración ARRAY, el nombre del arreglo, y el número de variables en el arreglo . Una vez que el arreglo ha sido definido, necesitas listar las variables que serán usadas en el arreglo.

Como en este ejemplo queremos crear 4 nuevas variables a partir de 4 variables existentes, necesitaremos definir 2 arreglos. Al primer arreglo la llamaremos original. Enumeramos las variables que irán en el arreglo sobre las que queremos hacer nuestro cálculo:

array original(4) length1 length2 length3 width;

El segundo arrelgo, lo llamaremos pulgadas, encerramos un 4 en el paréntesis porque la matriz contendrá 4 variables y luego enumeramos los nuevos nombres de las variables en las que queremos que se almacenen nuestros valores calculados:

array pulgadas(4) length1_in length2_in length3_in width_in;

Para entender los diferentes elementos del arreglo y sus valores asociados en cada iteración, consulta esta tabla:

ioriginal (i)pulgadas(i)
1length1length1_in
2length2length2_in
3length3length3_in
4widthwidth_in

Ahora que nuestras declaraciones ARRAY se han definido, podemos usar un bucle iterativo Do-Loop para recorrer los 4 elementos de cada arreglo y realizar la conversión de centímetros a pulgadas usando el siguiente código:

data fish_array_inches;
 set sashelp.fish;
 
 array original(4) length1 length2 length3 width;
 array inches(4) length1_in length2_in length3_in width_in;
 
 do i = 1 to 4;
  inches(i) = original(i) * 0.3937;
 end;
 
 format length1_in length2_in length3_in width_in 6.2;
 
 drop length1 length2 length3 width;
 
run;

Los resultados son los mismos que en el ejemplo anterior sin los arreglos.

En este ejemplo, sólo hay 4 elementos en el arreglo y por lo tanto la cantidad de programación reducida es mínima. Sin embargo, puedes ver cómo las situaciones con más de 4 variables se beneficiarían enormemente de los arrays.

Ejemplo 2 – Uso de arreglo y bucle para crear múltiples variables

En lugar de definir variables propias, se puede dejar que SAS cree y nombre las variables automáticamente en un arreglo. La ventaja de dejar que SAS cree las variables, es que pueden ser fácilmente agrupadas para su posterior análisis.

Por ejemplo, si SAS crea las variables VAR1 a VAR10, puede usar sentencias como “var1-var10” en varios procedimientos de SAS para reducir la cantidad de codificación que se necesita hacer para analizar múltiples variables al mismo tiempo.

Un ejemplo más detallado usando el conjunto de datos BASEBELL. Se calculará el promedio por juego considerando estadísticas de béisbol. Suponemos que el número de partidos jugados en una temporada es 162 y el conjunto de datos de BASEBELL representa una sola temporada.

Para ello, se crea un nuevo conjunto de variables que puedan ser fácilmente agrupadas y analizadas.

Se define una lista de los 9 nombres originales de las variables. El arreglo se llamará “original”, se coloca un 9 entre paréntesis para indicar que tenemos 9 elementos en el arreglo, y luego siguen las variables que lo formarán:

array original(9) nAtBat nHits nHome nRuns nRBI nBB nOuts nAssts nError;

Creación de nuevas variables no definidas

A continuación, como no queremos definir nombres de variables específicos para las variables recién creadas, especificamos un arreglo sin variables llamado stats:

array stats(9);

Una vez definidas las matrices, se puede usar un DO Loop para iterar de 1 a 9, dividiendo cada elemento de la matriz por 162 para obtener la estadística media por juego.

Para comprobar que las nuevas variables fueron creadas, ejecutamos un PROC CONTENTS después del paso de datos de BASEBALL_ARRAY.

Para verificar que el arreglo se creó correctamente y demostrar cómo aprovechar las variables con prefijos idénticos, también podemos ejecutar un PROC MEANS para calcular la media de cada variable estadística utilizando el código PROC MEANS que se muestra en el programa SAS a continuación:

data baseball_array;
 set sashelp.baseball;
 
 array original(9) nAtBat nHits nHome nRuns nRBI nBB nOuts nAssts nError;
 array stat(9);
 
 do i = 1 to 9;
  stat(i) = original(i)/162;
 end;
 
run;
 
proc contents data=baseball_array;
run;
 
proc means data=baseball_array mean;
 var stat1-stat9; 
run;

La salida de PROC CONTENTS y PROC MEANS que se muestra, tiene 9 nuevas variables STAT1-STAT9 sobre las que podemos realizar más análisis:

Ejemplo 3 – Uso de DO OVER para simplificar bucles con arreglos

Para evitar contar manualmente los elementos de los arreglos, SAS también proporciona la opción de bucle DO OVER para trabajar con arreglos no indexados. A medida que se empiezan a construir arreglos más grandes con más y más variables, los arreglos no indexados pueden ser una herramienta útil.

Un arreglo no indexado es similar a un arreglo indexado regular, excepto que no necesitas especificar el número de elementos en el arreglo. La sentencia DO OVER evita la necesidad de que especificar los valores de inicio y final del bucle.

Este ejemplo utiliza el conjunto de datos SASHELP.PRICEDATA que contiene múltiples variables de precio.

Considera un escenario en el que se quiere aumentar los precios (y por lo tanto todas tus variables de precio) en un 3%. Debido a que hay un gran número de variables, este escenario es candidato para usar arreglos y más específicamente para un arreglo no indexado.

Al igual que con los arreglos indexados, se comienza con la declaración del arreglo. Sin embargo, no especificamos el número de elementos, sólo las variables deseadas. En este caso, las correspondientes al precio: price1 a price17, así que podemos simplemente especificar el rango para acortar aún más nuestro código:

array origprice price1-price17;

A continuación definimos los nombres de las nuevas variables en el arreglo “newprice” que se ajustará al incremento del 3%:

array newprice newprice1-newprice17

Después de que los arreglos se definen, una declaración DO OVER se utiliza para decirle a SAS que haga un bucle a través de todo el arreglo. En cada iteración, el precio original se multiplica por 1.03 para aumentarlo en un 3%.

Aquí está la sintaxis completa:

Usando un PROC PRINT, podemos comparar rápidamente dos de las nuevas variables de precio# recién creadas con tres variables de precio# que coincidan para confirmar que fueron creadas correctamente.

data pricedata_array;
 set sashelp.pricedata;
 
 array origprice price1-price17;
 array newprice newprice1-newprice17;
 
 do over newprice;
  newprice = origprice * 1.03;
 end;
 
run;   
 
proc print data=pricedata_array(obs=10);
 var price1 newprice1 price2 newprice2;
run;

La salida confirma que el bucle y los ajustes de precio funcionaron correctamente:

Deja un comentario