BookmarkSubscribeRSS Feed
Etoo12121
Obsidian | Level 7

Hi,

I'm not very good with macros and stuck trying to get the below code to run multiple times based on the parameters listed below? 

 


%macro T04_DEM(dsn =, var =, var2 =, var3 =);
proc sort data=&dsn.; by actarmcd; run;

Proc Univariate data=&dsn. noprint;
Var &var.;
by actarmcd ;
Output out =Stats_&var.
n =X1_Freq
nmiss =X1_Miss
mean =X2_Mean
std =X2_std
median=X3_Median
min =X4_Min
max =X4_Max
;
run;

Proc Univariate data=&dsn. noprint;
Var &var.;
by GROUPING ;
Output out = stats2_&var.
n =X1_Freq
nmiss =X1_Miss
mean =X2_Mean
std =X2_std
median=X3_Median
min =X4_Min
max =X4_Max
;
run;

data stats3_&var.; set stats2_&var.;
rename grouping =actarmcd;
run;

data table_4_stats_&var.; set Stats_&var. stats3_&var.; run;

ods exclude all ;
ods output ttests=ttest_&var.;
Proc ttest data=&dsn. ;
var &var.;

class actarmcd;
run;
ods exclude none;

 

ods exclude all;
ods output fishersexact=Fisher_Sex;
Proc freq data= &dsn. ;

tables &var2.*actarmcd / fisher out=fish_&var2.;
run;
ods exclude none;


Proc freq data= &dsn. noprint;

tables &var2.*GROUPING / out=fish2_&var2.;
run;


data fish2_&var2.; set fish2_&var2.;
rename grouping =actarmcd;
run;

data table_4_stats_&var2.; set fish_&var2. fish2_&var2.; run;

 

ods exclude all;
ods output cmh=CMH_&var3. ;
Proc freq data= &dsn. ;
tables &var3.*actarmcd / CMH out=stats_&var3.;
run;
ods exclude none;

Proc freq data= &dsn. noprint;
tables &var3.*grouping / CMH out=stats2_&var3.;
run;


data stats2_&var3.; set stats2_&var3.;
rename grouping =actarmcd;
run;

data table_4_stats_&var3.; set stats_&var3. stats2_&var3.; run;


%mend T04_DEM;

%T04_DEM (dsn=adsl2, var =age);
%T04_DEM (dsn=adsl2, var =bmi);
%T04_DEM (dsn=adsl2, var2 =sex);
%T04_DEM (dsn=adsl2, var2 =ethnic);
%T04_DEM (dsn=adsl2, var3 =BMIGR1);

 

Running just the first one errors out because there are data steps within the macro that reference var2 but since it isn't in the first macro call, I get the error below

Etoo12121_1-1647188349311.png

How can I rewrite it so that it runs:

both age and bmi for var

both ethnic and sex for var2

BMIGR1 for var3

 

3 REPLIES 3
yabwon
Onyx | Level 15

In your macro when you call it with empty var2= parameter this part of your code:

 

tables &var2.*actarmcd / fisher out=fish_&var2.;

resolves to:

 

 

tables *actarmcd / fisher out=fish_;

which is syntactically wrong. You can't have  tables statement with a list of variable starting with "*".

 

 

You wrote "I'm not very good with macros", in this case the best approach would be to start with writing plain 4GL code which works properly, and the start to add macro parameters.

 

With that part I mentioned you could try to do a test if var2= is not null, e.g.

 

tables %if &var2. ne %then &var2.*; actarmcd / fisher out=fish_&var2.;

Which will resolve to:

 

tables actarmcd / fisher out=fish_;

when var2 is null.

 

 

Bart

 

 

P.S. Next time use the "running man" icon to paste your code, it will be more readable.

_______________
Polish SAS Users Group: www.polsug.com and communities.sas.com/polsug

"SAS Packages: the way to share" at SGF2020 Proceedings (the latest version), GitHub Repository, and YouTube Video.
Hands-on-Workshop: "Share your code with SAS Packages"
"My First SAS Package: A How-To" at SGF2021 Proceedings

SAS Ballot Ideas: one: SPF in SAS, two, and three
SAS Documentation



ballardw
Super User

How about a clear description of what you are attempting.

 

Why multiple calls to proc freq with separate variables? With the ODS output you can create tables of multiple variables with a single call (which should reduce the burden on dealing with the number of macro parameters

An example below that gets fisher exact tests and frequencies for 4 tables: type*origin type*drivetrain cylinders*origin cylinders*drivetrain. The Where statement reduces the observations used to allow the example to run in a short period of time by reducing lots of output from uncommon cases, such as the 3 cylinder engines types that are less common that would have lots of cells with 0 counts making fisher run for a very long time.

ods output fishersexact=Fisher_vars
           crosstabfreqs= fish_freq
;
Proc freq data= sashelp.cars;
where type =:'S' and cylinders in (4 6 8);
tables (type cylinders)*(origin drivetrain) /fisher;
run;

There will be variables in the output indicating which table is involved and with frequencies whether a row of data is a cell, row, column or table summary value.

PaigeMiller
Diamond | Level 26

As I started scrolling down your code, I was struck that you don't need macros, you don't need macro variables. So, this part of the code is easily replaced with code that has no macro and no macro variables.

 

proc sort data=&dsn.; by actarmcd; run;

Proc Univariate data=&dsn. noprint;
Var &var.;
by actarmcd ;
Output out =Stats_&var.
n =X1_Freq
nmiss =X1_Miss
mean =X2_Mean
std =X2_std
median=X3_Median
min =X4_Min
max =X4_Max
;
run;

Proc Univariate data=&dsn. noprint;
Var &var.;
by GROUPING ;
Output out = stats2_&var.
n =X1_Freq
nmiss =X1_Miss
mean =X2_Mean
std =X2_std
median=X3_Median
min =X4_Min
max =X4_Max
;
run;

 

Instead of using macros, which you admit you are not good at, you should be using the power of SAS to allow you to do lots of calculations with not a lot of code. It is inefficient to use macros here, because it doesn't take advantage of the power of SAS, and will take longer to program and longer to run. It is also inefficient and confusing to have means as X2 and medians as X3 and min and max are denoted as X4, what sense does any of that make? But for the part of your code above, here is example of how to do all of that part of code without macros and without macro variables, and takes advantage of the power of SAS.

 

proc means data=yourdatasetname noprint;
    class actarmcd grouping; /* More than two CLASS variables can go here if desired */
    ways 1;
    var yourvariablenames; /* More than one variable name can go here */
    output out=stats n= nmiss= mean= std= median= min= max=/autoname;
run;

May I also suggest, as others did, that you write code without macros and without macros variables for one or two instances, get that to work properly, and only then try turning it into a macro. If you can't get code to work properly without macros and without macro variables, it will NEVER work properly with macros and with macro variables. But in this case, macros and macro variables are simply not needed.

--
Paige Miller

Ready to join fellow brilliant minds for the SAS Hackathon?

Build your skills. Make connections. Enjoy creative freedom. Maybe change the world. Registration is now open through August 30th. Visit the SAS Hackathon homepage.

Register today!
How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 3 replies
  • 2033 views
  • 1 like
  • 4 in conversation