2 Questions about macros: 1. Adding text 2. matrix

Accepted Solution Solved
Reply
Contributor
Posts: 25
Accepted Solution

2 Questions about macros: 1. Adding text 2. matrix

Hi everyone,

 

I'm not experienced with macros and I have two questions about them. I have a macro that runs Proc PHReg in a certain setting, and I would like to optimize how it works, so:

 

Question 1:

Can I add a macro variable as text, which would then run as a WHERE statement in the proc phreg. Example:

%MyPHReg (datain, where, time, censor, var);

Proc PHReg data=&datain;
&where.;
model &time. * &censor.(1) = &var.;
run;
%MEnd;

/* and to use the macro*/

%MyPHReg (mydata, Where X = 1, Survival, Censor, Smoking);

I have tried this but it didn't work. I know that macro variables should be variables, but can I integrate text?

 

Question 2:

I'm running a similar functioning macro for several data sets (here as &datain.) and several influence variables (here as &var.). Can I identify a matrix of data sets and variables and request the macro to run all possible combinations. Example:

 

/* something faster and more practicable instead of running the following */ 

%MyPHReg (dataset1, Survival, Censor, Age);
%MyPHReg (dataset1, Survival, Censor, Smoking);
%MyPHReg (dataset1, Survival, Censor, Alcohol);

%MyPHReg (dataset2, Survival, Censor, Age);
%MyPHReg (dataset2, Survival, Censor, Smoking);
%MyPHReg (dataset2, Survival, Censor, Alcohol);

%MyPHReg (dataset3, Survival, Censor, Age);
%MyPHReg (dataset3, Survival, Censor, Smoking);
%MyPHReg (dataset3, Survival, Censor, Alcohol);

Thanks

Ubai

 

 


Accepted Solutions
Solution
‎12-15-2017 05:38 AM
Super User
Posts: 13,358

Re: 2 Questions about macros: 1. Adding text 2. matrix

You can use variables in a data step coupled with call execute to call your macro.

The example below shows using 3 dataset names and 3 variables to create calls as you indicate. If you are looping through more values for your "survival" and "censor" positioned parameters add loops similar to the ones I show and modify the Parmstr assignment code to reference those variables instead of the string literals. Define the lengths for those to be as long as needed. The length of Parmstr should be long enough to hold the macro call needed. Make it bigger if the test put shows it too short.

 

If the code is working creating the parmstr as shown in the log (option for the interested reader would be to Put the value to a text file and then %include that if a record of the code used is needed), then uncommenting the line with call execute should do what your are looking for.

 

data _null_;
   length dataset $ 43 vname $ 32 parmstr $ 200;
   do dataset= 'Dataset1','Dataset2','Dataset3';
         do vname= 'Age','Smoking','Alcohol';
         parmstr = catx(' ','%MyPHReg (', catx(',',dataset,'Survival','Censor',vname),');');
         /* to test if this is building the correct calling strings*/
         put parmstr; 
         /* when it is doing as needed uncomment the line below*/
         /* call execute(parmstr);*/
      end;
   end;
run;
      

DO NOT change the ' ' around the %Myphreg portion of the parmstr assignment code to double quotes, "   ", or the macro processor will attempt to run the macro and generate lots of errors.

 

View solution in original post


All Replies
PROC Star
Posts: 8,150

Re: 2 Questions about macros: 1. Adding text 2. matrix

Answer to your first question: Yes! However, you have to start a macro definition with %macro whatevername; e.g.:

%macro MyPHReg (datain, where, var);

proc print data=&datain;
&where.;
var &var;
run;
%MEnd;

/* and to use the macro*/

%MyPHReg (sashelp.class, Where age = 14, name sex);

Art, CEO, AnalystFinder.com

PROC Star
Posts: 8,150

Re: 2 Questions about macros: 1. Adding text 2. matrix

As for the 2nd part of your question, you can use a combination of counters combined with %scan to incorporate any combination of multiple runs desired. e.g.:

%macro MyPHReg (datain, where, var);
  %let i=1;
  %do %while (%scan(&datain,&i,' ') ne );
    proc print data=%scan(&datain,&i,' ');
      &where.;
      var &var;
    run;
    %let i=&i+1;
  %end;
%MEnd;

/* and to use the macro*/

%MyPHReg (sashelp.class sashelp.class sashelp.class, Where age = 14, name sex);

Art, CEO, AnalystFinder.com

Solution
‎12-15-2017 05:38 AM
Super User
Posts: 13,358

Re: 2 Questions about macros: 1. Adding text 2. matrix

You can use variables in a data step coupled with call execute to call your macro.

The example below shows using 3 dataset names and 3 variables to create calls as you indicate. If you are looping through more values for your "survival" and "censor" positioned parameters add loops similar to the ones I show and modify the Parmstr assignment code to reference those variables instead of the string literals. Define the lengths for those to be as long as needed. The length of Parmstr should be long enough to hold the macro call needed. Make it bigger if the test put shows it too short.

 

If the code is working creating the parmstr as shown in the log (option for the interested reader would be to Put the value to a text file and then %include that if a record of the code used is needed), then uncommenting the line with call execute should do what your are looking for.

 

data _null_;
   length dataset $ 43 vname $ 32 parmstr $ 200;
   do dataset= 'Dataset1','Dataset2','Dataset3';
         do vname= 'Age','Smoking','Alcohol';
         parmstr = catx(' ','%MyPHReg (', catx(',',dataset,'Survival','Censor',vname),');');
         /* to test if this is building the correct calling strings*/
         put parmstr; 
         /* when it is doing as needed uncomment the line below*/
         /* call execute(parmstr);*/
      end;
   end;
run;
      

DO NOT change the ' ' around the %Myphreg portion of the parmstr assignment code to double quotes, "   ", or the macro processor will attempt to run the macro and generate lots of errors.

 

Contributor
Posts: 25

Re: 2 Questions about macros: 1. Adding text 2. matrix

Thanks @art297 and @ballardw for your quick answers.

 

In the first question I did actually try the method However, for the first question I am still receiving errors.

ERROR: The keyword parameter VAR was not defined with the macro.

 

These only occur when I try to use a code that integrates the WHERE statement instead of writing it in the macro. Example:

 

%macro b (where);
proc phreg data=datain;
class sex;
where &where;
model time*censor(0) = sex;
run;
%mend;

%b (var=1);

***** instead of this one *****

%macro a (where);
proc phreg data=datain;
class sex;
&where;
model time*censor(0) = sex;
run;
%mend;

%a (where var=1);

 

 Any ideas?

 

For the second question the solution ballardw used is great, mainly because it allows me to use the method for variables and data names that don't end with numbers, or -as actually in my case- completely different. Thank you guys.

 

 

Super User
Super User
Posts: 7,942

Re: 2 Questions about macros: 1. Adding text 2. matrix

[ Edited ]

If you call a macro with this syntax

%b(var=1)

You are telling it you want the parameter VAR to have the value 1.

If instead you want to set a value for the WHERE parameter then tell SAS that.

%b(where=var=1)

Note that you can always use named parameters in the macro call, even for a parameter that is defined as positional in the macro definition. You just can't try to pass parameters by position, ie without a name, if they are not defined as positional.

 

You could also add parentheses so that the value does not look like name= .

%b((var=1))

Having the extra parentheses in the value of WHERE should not cause any issue. 

PROC Star
Posts: 8,150

Re: 2 Questions about macros: 1. Adding text 2. matrix

[ Edited ]

Both methods will work but, for macro b, the compiler is confused upon seeing the = sign. Both of the following should work:

 

%macro b (where);
proc print data=sashelp.class;
where &where;
run;
%mend;

%b (age eq 14);


%macro a (where);
proc print data=sashelp.class;
&where;
run;
%mend;

%a (where age eq 14);

Art, CEO, AnalystFinder.com

 

Contributor
Posts: 25

Re: 2 Questions about macros: 1. Adding text 2. matrix

@ballardw

Actually I am looping more values for the "survival" and "censor" variables along with different predicting variables, but of course I would like a survival variable to go along with certain censoring variable. How can I make that possible within the data step you showed?

 

So to make it clear I have several data sets of the same structure, several predicting variables, several survival times for different outcomes and along with the survival times their corresponding censoring variables. I would like each survival time and censoring variables to go along together in such loop. How would you do that?

Super User
Posts: 13,358

Re: 2 Questions about macros: 1. Adding text 2. matrix


Ubai wrote:

@ballardw

Actually I am looping more values for the "survival" and "censor" variables along with different predicting variables, but of course I would like a survival variable to go along with certain censoring variable. How can I make that possible within the data step you showed?

 

So to make it clear I have several data sets of the same structure, several predicting variables, several survival times for different outcomes and along with the survival times their corresponding censoring variables. I would like each survival time and censoring variables to go along together in such loop. How would you do that?


You will have to show some examples of what you mean. If "survival" always has the same "censor" then a different loop structure would be needed such as loop Survival and then assign censor based on that value inside the loop.

If you have a complete list of survivals that have to cross with the censors such as in the previous example then add two more loop similar to the existing ones with the macro call in the middle of the whole mess.

You could have a dataset with variables holding value pairs for survival and censor and the first line of the code after data would SET that data set. Then the entire sett of loops get called for each record in the data set.

 

You would add the VARIABLES to the catx code instead of the quoted strings I used but that should be a simple change.

Contributor
Posts: 25

Re: 2 Questions about macros: 1. Adding text 2. matrix

Yes, each "survival" has only its own censor variable, so the variable TimeDeath has TimeDeathCens only and TimeMeta (for metastasis) has TimeMetaCens only. I would be meaningless to have TimeDeath and a censoring variable for other event. What loop structure would you suggest for this problem? How would you do it?

 

I actually came to this question because I wanted two additional loops to the code you provided and then I figured out that it would loop time-to-event with unrelated censoring variables.

Super User
Posts: 13,358

Re: 2 Questions about macros: 1. Adding text 2. matrix


Ubai wrote:

Yes, each "survival" has only its own censor variable, so the variable TimeDeath has TimeDeathCens only and TimeMeta (for metastasis) has TimeMetaCens only. I would be meaningless to have TimeDeath and a censoring variable for other event. What loop structure would you suggest for this problem? How would you do it?

 

I actually came to this question because I wanted two additional loops to the code you provided and then I figured out that it would loop time-to-event with unrelated censoring variables.


Again following the previous code example set lengths for the survival and censor variable names before use.

as an added loop using your examples above I would start with something like inside the VNAME loop.

Do survival = 'TimeDeath','TimeMeta';

   Censor= cats(survival,'Cens'); /* adds Cens to the end of the survival variable name*/

   /* change parmstr to:*/

     parmstr = catx(' ','%MyPHReg (', catx(',',dataset,Survival,Censor,vname),');');
     

 

End;

 

If your survival  and censor variable are not as easily built as the example above then make a data set with the two values needed and add a SET statement pointing to that data set immediately after the data _null_;

☑ This topic is solved.

Need further help from the community? Please ask a new question.

Discussion stats
  • 10 replies
  • 159 views
  • 6 likes
  • 4 in conversation