1
Eliminate Cookie-Cutter Eliminate Cookie-Cutter CodeCode withwith %wordLoop %wordLoop
11
2
Def. of CCC – How It Is Def. of CCC – How It Is CreatedCreated
Write a short chunk of SAS codeWrite a short chunk of SAS code Copy, paste, editCopy, paste, edit Copy, paste, editCopy, paste, edit Copy, paste, editCopy, paste, edit … … (until the list in (until the list in mindmind is is
exhausted)exhausted)
4
%wordLoop Signature%wordLoop Signature
%wordLoop( wordList=<>, contentMacro=<>);
Where: wordList => values to loop over, e.g. data set names contentMacro => code applied on each loop
5
Example Code Example Code
Select a subset of observations from Select a subset of observations from each of N datasets each of N datasets
Create N new suitably-named Create N new suitably-named datasetsdatasets
Subset specified by Subset specified by finderFileDsfinderFileDs Why? subset analysis, data transfer, Why? subset analysis, data transfer,
removal of patients from studyremoval of patients from study
6
Example Cookie-Cutter Example Cookie-Cutter CodeCode
DATA patientDs_subset; MERGE patientDs(in=in1) finderFileDs(in=in2);BY id; IF in1 and in2;RUN;DATA consultDs_subset; MERGE consultDs(in=in1) finderFileDs(in=in2);BY id; IF in1 and in2;RUN;DATA hospStayDs_subset; MERGE hospStayDs(in=in1) finderFileDs(in=in2);BY id; IF in1 and in2;RUN;DATA eventsDs_subset; MERGE eventsDs(in=in1) finderFileDs(in=in2);BY id; IF in1 and in2;RUN;DATA drugsDs_subset; MERGE drugsDs(in=in1) finderFileDs(in=in2);BY id; IF in1 and in2;RUN;
7
Ex. CCC showing Ex. CCC showing SubstitutionsSubstitutions
DATA patientDs_subset; MERGE patientDs(in=in1) finderFileDs(in=in2);BY id; IF in1 and in2;RUN;DATA consultDs_subset; MERGE consultDs(in=in1) finderFileDs(in=in2);BY id; IF in1 and in2;RUN;DATA hospStayDs_subset; MERGE hospStayDs(in=in1) finderFileDs(in=in2);BY id; IF in1 and in2;RUN;DATA eventsDs_subset; MERGE eventsDs(in=in1) finderFileDs(in=in2);BY id; IF in1 and in2;RUN;DATA drugsDs_subset; MERGE drugsDs(in=in1) finderFileDs(in=in2);BY id; IF in1 and in2;RUN;
8
Repeating PatternRepeating Pattern
DATA <Ds from list>_subset; MERGE <Ds from list>(in=in1) finderFileDs(in=in2); BY id; IF in1 and in2;RUN;
Ds list: patientDs consultDs hospStayDs eventDs drugDs
9
Liabilities of CCCLiabilities of CCC
Cut-paste-edit errorsCut-paste-edit errors Bulky and hard to readBulky and hard to read Tedious to change implementationTedious to change implementation List is hiddenList is hidden List tedious to changeList tedious to change
Make a macro of repeating element?
10
Ex. with Macro DefinitionEx. with Macro Definition
%MACRO getSubset(ofDs=); DATA &ofDs._subset; MERGE &ofDs(in=in1) finderFileDs (in=in2); BY id; IF in1 and in2; RUN;%MEND;%getSubset(ofDs=patientDs );%getSubset(ofDs=consultDs );%getSubset(ofDs=hospStayDs);%getSubset(ofDs=eventsDs );%getSubset(ofDs=drugsDs );
Still got cookies!
Still list elements are dispersed.
11
Ex. with %wordLoop Ex. with %wordLoop
%MACRO getSubset( ); DATA &word._subset; MERGE &word.(in=in1) finderFileDs(in=in2); BY id; IF in1 and in2; RUN;%MEND;
%LET ds=patientDs consultDs hospStayDs eventsDs drugsDs;%wordLoop(wordList=&ds,contentMacro=getSubset( ));
Oops! What about sort order?
12
Again with sortAgain with sort
%MACRO getSubset(); proc sort DATA=&word; BY id; RUN; DATA &word._subset; MERGE &word.(in=in1) finderFileDs(in=in2); BY id; IF in1 and in2; RUN;%MEND;
%LET ds=patientDs consultDs hospStayDs eventsDs drugsDs;%wordLoop(wordList=&ds,contentMacro=getSubset( ));
SQL better?
13
Again with SQLAgain with SQL
%MACRO getSubset(); PROC sql; create table &word._subset as select * from &word, finderFileDs where &word..id = finderFileDs.id; QUIT; %MEND;
%LET ds=patientDs consultDs hospStayDs eventsDs drugsDs;%wordLoop(wordList=&ds,contentMacro=getSubset( ));
Change localized!
14
%wordLoop code %wordLoop code
%MACRO wordLoop(wordList=, contentMacro=); %LOCAL word cnt; %LET cnt=0; %DO %WHILE(1 eq 1); %LET cnt = %eval(&cnt+1); %LET word= %scan(&wordList, &cnt, %str( )); %IF &word= %THEN %RETURN; %&contentMacro; %END;%MEND wordLoop;
ContentMacro must not %LOCAL word!
15
Example 2 Code Example 2 Code
Recode 99 to “.” for selected Recode 99 to “.” for selected variablesvariables
5 variables need to be recoded5 variables need to be recoded 3 variables might have valid 99s3 variables might have valid 99s CCC occurs within a DATA step CCC occurs within a DATA step
16
Ex. 2 Cookie-Cutter CodeEx. 2 Cookie-Cutter Code
DATA data99sFixed; SETdataWith99sDs; IF eyeColor eq 99 THEN eyeColor = .; IF hairColor eq 99 THEN hairColor = .; IF bloodtype eq 99 THEN bloodtype = .; IF prevCardiac eq 99 THEN prevCardiac = .; IF prevCancer eq 99 THEN prevCancer = .;RUN;
17
Ex. 2 with Array SolutionEx. 2 with Array Solution
%LET varsWith99 = eyeColor hairColor bloodtype prevCardiac prevCancer;
DATA data99sFixedDs; SET dataWith99sDs; ARRAY vars99arr{*} &varsWith99; DO i=1 to dim(vars99arr); IF vars99arr(i) eq 99 THEN vars99arr(i) = .; END; DROP i;RUN;
This works but so does …
18
Ex. 2 with %wordLoop Ex. 2 with %wordLoop
%LET varsWith99 = eyeColor hairColor bloodtype prevCardiac prevCancer;
%MACRO cnvt99s(); IF &word eq 99 THEN &word= .;%MEND;
DATA data99sFixed; SETdataWith99sDs; %wordLoop(wordList=&varsWith99, contentMacro=cnvt99s());RUN;
19
Misuses of %wordLoopMisuses of %wordLoop
Avoid use with datasets representing Avoid use with datasets representing partitions of DATA (e.g. sites)partitions of DATA (e.g. sites)
Combine and processBY site, insteadCombine and processBY site, instead Avoid use with procs whenBY or Avoid use with procs whenBY or
CLASS can be used (e.g. PROC CLASS can be used (e.g. PROC MEANS) MEANS)
20
Take AwaysTake Aways Avoid cookie-cutter-code!Avoid cookie-cutter-code! %wordLoop() can help you do this%wordLoop() can help you do this SAS macros allow you to adapt the SAS macros allow you to adapt the
SAS language to your purposes.SAS language to your purposes.