syserr macro into ejemplos sas sas-macro

macro - ¿Es posible iterar sobre conjuntos de datos SAS?



macro variables (5)

Así es como resuelvo este problema en mi programación diaria, cuando es necesario llamar una macro repetidamente en base a los datos. Este enfoque funciona igual de bien con muchos conjuntos de datos o muchas variables de un conjunto de datos o muchas llamadas de macro diferentes de un conjunto de datos, cualquiera que sea, simplemente crea un conjunto de datos con la información que varía y llámalo de esta manera.

Este enfoque combina elementos de la solución de Shorack con user2337871 y Neil''s. ¿Por qué hacerlo de manera diferente?

  • Se debe llamar a Macro con parámetros, que no contengan sus definiciones de parámetros dentro de él. Eso lo hace más flexible para uso futuro (donde, por ejemplo, el dataset dataset_list podría ser algo diferente).
  • Tener flexibilidad para llamar en base al conjunto de datos de nombres en lugar de requerir macro para llamar a macro
  • La eliminación de código en una macro (en lugar de dentro de la call execute u otro método de llamada) hace que sea más fácil de leer.
  • call execute puede tener algunos inconvenientes dependiendo de la manipulación que esté realizando (relacionada con el tiempo de macrovariable)

Digamos que está haciendo un PROCEDIMIENTOS y luego anexándolo a un conjunto de datos maestro. Si bien esta es una forma muy lenta e incómoda de hacerlo (en lugar de combinarlos juntos y usar BY, o incluso usar ODS OUTPUT con datasets no combinados), asumiremos que su tarea real es más complicada.

%macro do_my_stuff(dataset=); proc means data=&dataset noprint; var count; output out=dsn_&dataset. mean=; run; proc append base=results data=dsn_&dataset. force; run; %mend do_my_Stuff; proc sql; select cats(''%do_my_stuff(dataset='',name,'')'') into :stufflist separated by '' '' from dictionary.tables where memname=''WORK''; quit; &stufflist;

Puede agregar criterios adicionales a la instrucción where en el sql de proc, o invocar eso usando CALL EXECUTE, o una cantidad de opciones diferentes. También puede usar un conjunto de datos hecho a sí mismo con los nombres de los conjuntos de datos (e incluso las variables como otra columna y parámetro macro, si la (s) variable (s) de interés varían según el conjunto de datos).

Tengo 60 conjuntos de datos sas que contienen datos sobre las características individuales de los consumidores, tales como id, gender, age, amountSpent, .... Cada conjunto de datos muestra datos solo para un período de tiempo (data1 es Jan, data2 es Feb ...). No puedo fusionarlos por el tamaño y algunos otros problemas.

¿Cómo puedo escribir un bucle múltiple para recorrer cada uno de los conjuntos de datos, hacer algunas manipulaciones y guardar los valores estimados en un archivo temporal?

SAS no tiene un bucle for . ¿Cómo puedo usar do ?


Mi respuesta ir es macro.

%MACRO process_datasets(mdataset); data &mdataset.; set &mdataset.; if age >= ''50'' then discountRate = .2; *whatever else you need here; run; data _null_; file ''tmp.csv'' mod dsd dlm='',''; *I''m assuming you''re saving everything to the same file; set &mdataset.; put (_all_) (+0); run; %MEND process_datasets;

entonces puedes llamarlo desde otro macro loop ...

%MACRO loop_through_all; %DO i = 1 to 60; %process_datasets(data&i.); %END; %MEND loop_through_all; %loop_through_all;


Otra opción es crear una vista que combine todos los conjuntos de datos, no obtendrá ningún problema de tamaño de datos con este enfoque (aunque no sé si los otros problemas a los que hace referencia serían un problema aquí). Necesitará una lista de los conjuntos de datos relevantes, que pueden obtenerse de DICTIONARY.TABLES en PROC SQL.

proc sql noprint; select memname into :ds_list separated by '' '' from dictionary.tables where libname=''XXXXX''; quit; data combined / view=combined; set &ds_list; run;

A continuación, ejecute su resumen en la vista, por lo que no es necesario recorrer cada conjunto de datos. Supongo que sus conjuntos de datos tienen una variable de fecha; de lo contrario, deberá agregar alguna funcionalidad adicional (esto se aplica a cualquier solución). Sería interesante ver cómo funciona esto en comparación con las otras soluciones aquí.


Sin necesidad de macros, CALL EXECUTE procesará cada conjunto de datos en un nombre de lib o múltiples nombres de libra simplemente creando una consulta en SASHELP.VTABLE y luego ejecutando un paso de datos para cada instancia. Por lo general, elimino o comprime los nombres de los conjuntos de datos para garantizar que los espacios en blanco no causen problemas, pero le permitirá agregarlos usted mismo. También puede realizar los cambios pertinentes al subconjunto y anexar los resultados a un solo conjunto de datos temporales.

DATA WANT; SET SASHELP.VTABLE (KEEP = LIBNAME MEMNAME WHERE = (LIBNAME = "MAPSSAS")) END=EOF; STR = COMPBL("DATA " || MEMNAME || "; SET " || LIBNAME || "." || MEMNAME ||";" ); STR1 CALL EXECUTE (STR); IF EOF THEN DO; STR = ''RUN;''; CALL EXECUTE (STR); END; RUN;


Pero sas tiene un do while macro loop. Así que, básicamente, necesita 3 cosas: 1. De alguna manera, una lista de sus conjuntos de datos. 2. Una macro que recorre este listado. 3. Lo que quieres hacer

Por ejemplo, supongamos que tiene un conjunto de datos WORK.DATASET_LIST que contiene una biblioteca de variables (nombre de lib) y un miembro de variable (nombre de conjunto de datos) para cada conjunto de datos que desea recorrer.

Entonces podrías hacer:

%macro loopOverDatasets(); /*imho good practice to declare macro variables of a macro locally*/ %local datasetCount iter inLibref inMember; /*get number of datasets*/ proc sql noprint; select count(*) into :datasetCount from WORK.DATASET_LIST; quit; /*initiate loop*/ %let iter=1; %do %while (&iter.<= &datasetCount.); /*get libref and dataset name for dataset you will work on during this iteration*/ data _NULL_; set WORK.DATASET_LIST (firstobs=&iter. obs=&iter.); *only read 1 record; *write the libname and dataset name to the macro variables; call symput("inLibref",strip(libname)); call symput("inMember",strip(member)); *NOTE: i am always mortified by the chance of trailing blanks torpedoing my code, hence the strip function; run; /*now you can apply your logic to the dataset*/ data &inLibref..&inMember.; *assuming you want to apply the changes to the dataset itself; set &inLibref..&inMember.; /*** INSERT YOUR LOGIC HERE ***/ run; /*** ANY OTHER PROCS/DATA STEPS ***/ /*just remember to use &inLibref..&inMember. to refer to the current dataset*/ /*increment the iterator of the loop*/ %let iter=%eval(&iter.+1); %end; %mend; /*call the macro*/ %loopOverDatasets()

Esa es la idea. Tal vez quiera reunir la lista de sus conjuntos de datos de una manera diferente. por ejemplo, una variable macro que los contiene a todos. En ese caso, deberá usar la función% scan en el ciclo para elegir un conjunto de datos. O tal vez haya una lógica en la denominación, por ejemplo, dataset1, dataset2, dataset3 ..., en cuyo caso podría simplemente hacer uso de & iter. variable macro.