BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
desireatem
Pyrite | Level 9

ods html close;

%macro surv(replicates=);

%do p=1 %to &replicates;

data tes_&p;

seed=-1;

  alpha1 = 2.50;

  beta1 = 2.00;

  beta2=4;

  do i = 1 to 500;

  X=ranbin(0,1,.5);

   lambdaT = 0.025; *baseline hazard;

   lambdaC= .03;  *heavy=0.15; *light=0.03;

   er=0+(0.05)*rannor(1);

    t = rand("WEIBULL", 0.75, lambdaT);  * time of event;

    c1 = rand("WEIBULL", 1.25, lambdaC) ;* time of censoring;

    c2= rand("WEIBULL", 1.50, lambdaC) ;

    if er le 0.240482 then c=c1; else c=c1;

   time = min(t, c);    * which came first?;

    censored = (c lt t);

      obs=(t lt c); * creating observation vaiable from censored when observeed obs=1;

      obs = (t lt c);

    y= alpha1 + beta1*t + er;

    if  t le 0.015072 then R=0;

      else if  t gt 0.015072 then R=1;

    y1= alpha1 +beta1*R + er;

    output;

  end;

run;

%do i=1 %to 7;

proc surveyselect data=tes_&i  method = urs sampsize = 10 OUTHITS

     reps=1 seed=123410 out=test_&i;

run;

proc means data = test_&i sum;

where obs = 0;

var censored; 

ods output summary = summary_&i;

run;

%end;

data impute_t_&p;

set summary_1 -summary_&i;;

run;

%end;

%mend surv;

%surv(replicates=10);

1 ACCEPTED SOLUTION

Accepted Solutions
Patrick
Opal | Level 21

You can define a macro within a macro but if you want to use the macro then you need to call it. So you would need to add %selecting; to your code.

You normally avoid to define a macro in a macro because in doing so the inner macro definition gets re-compiled for every call of the out macro. So what you would do if such a nesting is required is a construct like:

%macro inner;

   ....

%mend;

%macro outer;

     %inner;

%mend;

%outer;

Also don't forget that macro variables defined within a macro have per default a scope of local. So &i defined in macro %selecting is not available in the outer macro %surv. You need to use a %global i; in your inner macro to change this.

I also believe that at the end of a %do loop the value of &i is the upper boundary of the loop plus 1 - so "summary_&i;" would expect a data set "summary_8" - which doesn't exist.

I actually don't understand why you need macro %selecting at all. Can't you just have your %do loop as part of macro %surv?

Another option to collect data created iteratively would be:

proc append base=impute_t_&p data=summary_&i;

run;

You would have this proc append step inside your do loop. If you don't need to keep a table per iteration then you could also overwrite the summary_.. table in each operation and so using syntax like:

proc append base=impute_t_&p data=summary;

run;

Haven't really looked at the rest of the code. What you normally want to do is make your program work without a macro (so only for a single case) and only once this is working "macrotize" it.

Also: It's most of the times better to use by-group processing instead of calling a procedure multiple times with different data slices. So eventually you could combine the output from proc sureveyselect using proc append but then call proc means only once.

View solution in original post

4 REPLIES 4
Patrick
Opal | Level 21

You can do what you want but the syntax is different (it looks like SAS and not JMP). You might want to have a read of the SAS Macro Language syntax, e.g. the syntax could be:

/* define and compile the macro */

%macro xxxx; ...%do i=1 %to 7; ... out=test_&i... %end; ...%mend;

/* call the macro */

%xxxx;

desireatem
Pyrite | Level 9

So I can have a macro within a macro?

desireatem
Pyrite | Level 9

THis is how my code looks like;, is this format correct, why is it that I cant get the data impute_t_&p

ods html close;

%macro surv(replicates=);

%do p=1 %to &replicates;

data tes_&p;

seed=-1;

  alpha1 = 2.50;

  beta1 = 2.00;

  beta2=4;

  do i = 1 to 500;

  X=ranbin(0,1,.5);

   lambdaT = 0.025; *baseline hazard;

   lambdaC= .03;  *heavy=0.15; *light=0.03;

   er=0+(0.05)*rannor(1);

    t = rand("WEIBULL", 0.75, lambdaT);  * time of event;

    c1 = rand("WEIBULL", 1.25, lambdaC) ;* time of censoring;

    c2= rand("WEIBULL", 1.50, lambdaC) ;

    if er le 0.240482 then c=c1; else c=c1;

   time = min(t, c);    * which came first?;

    censored = (c lt t);

      obs=(t lt c); * creating observation vaiable from censored when observeed obs=1;

      obs = (t lt c);

    y= alpha1 + beta1*t + er;

    if  t le 0.015072 then R=0;

      else if  t gt 0.015072 then R=1;

    y1= alpha1 +beta1*R + er;

    output;

  end;

run;

%do i=1 %to 7;

proc surveyselect data=tes_&i  method = urs sampsize = 10 OUTHITS

     reps=1 seed=123410 out=test_&i;

run;

proc means data = test_&i sum;

where obs = 0;

var censored; 

ods output summary = summary_&i;

run;

%end;

data impute_t_&p;

set summary_1 -summary_&i;;

run;

%end;

%mend surv;

%surv(replicates=10);

Patrick
Opal | Level 21

You can define a macro within a macro but if you want to use the macro then you need to call it. So you would need to add %selecting; to your code.

You normally avoid to define a macro in a macro because in doing so the inner macro definition gets re-compiled for every call of the out macro. So what you would do if such a nesting is required is a construct like:

%macro inner;

   ....

%mend;

%macro outer;

     %inner;

%mend;

%outer;

Also don't forget that macro variables defined within a macro have per default a scope of local. So &i defined in macro %selecting is not available in the outer macro %surv. You need to use a %global i; in your inner macro to change this.

I also believe that at the end of a %do loop the value of &i is the upper boundary of the loop plus 1 - so "summary_&i;" would expect a data set "summary_8" - which doesn't exist.

I actually don't understand why you need macro %selecting at all. Can't you just have your %do loop as part of macro %surv?

Another option to collect data created iteratively would be:

proc append base=impute_t_&p data=summary_&i;

run;

You would have this proc append step inside your do loop. If you don't need to keep a table per iteration then you could also overwrite the summary_.. table in each operation and so using syntax like:

proc append base=impute_t_&p data=summary;

run;

Haven't really looked at the rest of the code. What you normally want to do is make your program work without a macro (so only for a single case) and only once this is working "macrotize" it.

Also: It's most of the times better to use by-group processing instead of calling a procedure multiple times with different data slices. So eventually you could combine the output from proc sureveyselect using proc append but then call proc means only once.

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

Register now!

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
  • 4 replies
  • 528 views
  • 3 likes
  • 2 in conversation