LISTSERV at the University of Georgia
Menubar Imagemap
Home Browse Manage Request Manuals Register
Previous (more recent) messageNext (less recent) messagePrevious (more recent) in topicNext (less recent) in topicPrevious (more recent) by same authorNext (less recent) by same authorPrevious page (May 2002, week 4)Back to main SAS-L pageJoin or leave SAS-L (or change settings)ReplyPost a new messageSearchProportional fontNon-proportional font
Date:   Thu, 23 May 2002 16:57:52 -0400
Reply-To:   Ian Whitlock <WHITLOI1@WESTAT.COM>
Sender:   "SAS(r) Discussion" <SAS-L@LISTSERV.UGA.EDU>
From:   Ian Whitlock <WHITLOI1@WESTAT.COM>
Subject:   Re: Problem with %if
Comments:   To: Sheila Whitelaw <sw75@BOXFROG.COM>
Content-Type:   text/plain; charset="iso-8859-1"

Subject: RE: Problem with %if Summary: Short macro lesson on decisions and loops Respondent: IanWhitlock@westat.com

Sheila Whitelaw <sw75@BOXFROG.COM> asks a question about a %IF and shows her macro. Since she said she is new to macro and shows good promise I decided to look at some of the issues her question and example should raise. I hope that the effort is also useful to some other struggling macro programmers.

The business of macros is to generate SAS code. Hence %IF is used to decide which SAS code to generate. IF, on the other hand, decides which generated code to execute. Thus one can usually tell whether to use %IF or IF just by asking what do I want to decide.

Now let's look at your macro, %DOIT. Bad choice of name. the name should show function. What is it suppose to do? Ans: Generate 30 random numbers, X and distribute based on which third of the unit interval X falls. So RANDOM3 would be a better name. Your macro has no parameters. What would be natural parameters? Ans: NOBS=10, OUTROOT=TEST, DEBUG=YES (should prints be made?)

Now let's look at the code. All three files generated in one step. Good! One should ask if it wouldn't be better to have one set and use Y to pick out the subsets. In the long run this is usually a better strategy, but it doesn't matter much here.

How should the assignment lines look? I.e. should you use a DO loop over two lines or should you use a %DO loop to generate many assignments? Either is possible and has its advantages. DO has tight code and short log, but a little overhead to compile the DO-loop thus costing a micro second. %DO makes a longer log, it is known as unrolling the loop. It avoids the cost of compiling the DO but runs into the cost of compiling more assignments. As the length of the loop grows the advantages lie with DO. Personally I prefer the DO to keep the code as short as possible, but would not quibble with a loop of only 10 iterations. The macro variable I should be local, i.e. only known inside the macro while it is executing. %LOCAL statement should declare your intentions. (Common beginner mistake.)

Now the big question - how do we make the decision to which data set? Well we need 3 OUTPUT statements for 3 data sets so we do not want to decide which OUTPUT statement to generate so it is probably not a %IF. The decision is based on the value generated so it must be at SAS execution time, hence it must be an IF (or SELECT might be better style).

More possible parameters, NSETS=3. Let the user decide whether the data should be split out or not.

So here is my revision.

%macro Random ( outroot = test /* root for output data sets */ , split= yes /* one file or many */ , nobs = 10 /* num obs in total */ , nsets = 3 /* determines split var */ , debug = yes /* are prints wanted? */ ) ; %local i ; /* looping variable */ %let split = %upcase ( &split ) ; %let debug = %upcase ( &debug ) ;

data %if &split = NO %then test ; %else %do ; %do i = 1 %to &nsets ; &outroot&i %end ; %end ; ; drop j ; do j=1 to 10; x=ranuni(0); y=mod(int(10*x),&nsets);

%if &split = YES %then output test ; %else %do ; select ( y ) ; %do i = 1 %to &nsets ; when (&i) output &outroot&i ; %end ; otherwise error ; end ; %end ; run;

%if &debug = YES %then %do ; %if &split = YES %then %do ; %do i=1 %to &nsets ; proc print data=&outroot&i; title2 "&outroot&i"; run; %end ; %end ; %else %do ; proc print data=&outroot&i; title2 "&outroot&i"; run; %end ; %end; %mend random ;

Note that indentation is used to show the structure of the program. Macro decisions and looping are needed where used. The WHEN statements are in SAS not macro, however, a macro loop is used to generate them because I have not assumed a fixed number of them.

The code is somewhat harder, but it introduces a lot of the problems you should be thinking about. It also illustrates how concentration on the parameters leads to a more interesting and useful macro.

Oh, I never got around to the original question - why only one record in each data set and always the same value? Well the letter Y is never a digit so all the %IF tests in Sheila's code fail. Hence the DATA step generated has not OUTPUT statement. Thus she generates 10 assignements to each X and Y. The last pair of assignments is output by default to all three data sets.

IanWhitlock@westat.com

-----Original Message----- From: Sheila Whitelaw [mailto:sw75@BOXFROG.COM] Sent: Thursday, May 23, 2002 11:10 AM To: SAS-L@LISTSERV.UGA.EDU Subject: Problem with %if

Hi, I am new to macro. I tried out the following codes which are supposed to generate 3 datasets based on the value of the remainder. However only one record is output to each dataset. The code is working if I use if instead of %if. Can anyone tell me what I did wrong?

Code: %macro DOIT; data test1 test2 test3; %do j=1 %to 10; x=ranuni(0); y=mod(int(10*x),3); %if y=0 %then output test3; %else %if y=1 %then output test1; %else %if y=2 %then output test2; %end; run; %do i=1 %to 3; proc print data=test&i; title2 "test&i"; run; %end; %mend DOIT; %DOIT;

Output: test1 OBS X Y 1 0.84581 2

test2 OBS X Y 1 0.84581 2

test3 OBS X Y 1 0.84581 2

Thanks.


Back to: Top of message | Previous page | Main SAS-L page