BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
LuGa
Obsidian | Level 7

Dear SAS Gurus,

 

please help me debugging my loop. 

 

%let k_interims = 5;
%let n_1 = 100;
%let n_2 = 100;
%let n_3 = 100;
%let n_4 = 100;
%let n_5 = 100;

%let i_nullprop_mean = 0.5;
%let i_nullprop_SD = 0.1;

%let j_alternative_mean = 0.5;
%let j_alternative_SD = 0.1;


	data _null_;
		do i=1 to &k_interims by 1;
			s= '
			data count_'||trim(left(put(i,3.)))||' (drop=j);

				length trt sbi 4;

				if '||trim(left(put(i,3.)))||' eq "1" or '||trim(left(put(i,3.)))||' eq 1 then do;
					
					do j = 1 to round(&n_'||trim(left(put(i,3.)))||', 2) by 1;
						if mod(j, 2) eq 0 then do;
							trt = 1;
							sbi = rand("Bernoulli", abs(rand("Normal", &j_alternative_mean, &j_alternative_SD)));
						end;
						else do;
							trt = 0;
							sbi = rand("Bernoulli", abs(rand("Normal", &i_nullprop_mean, &i_nullprop_SD)));
						end;
						output;
					end;
				end;

				else if '||trim(left(put(i,3.)))||' ne "1" or '||trim(left(put(i,3.)))||' ne 1 then do;

					set count_'||trim(left(put(i-1, 3.)))||';

					do j = 1 to round(&n_'||trim(left(put(i,3.)))||', 2) by 1;
						if mod(j, 2) eq 0 then do;
							trt = 1;
							sbi = rand("Bernoulli", abs(rand("Normal", &j_alternative_mean, &j_alternative_SD)));
						end;
						else do;
							trt = 0;
							sbi = rand("Bernoulli", abs(rand("Normal", &i_nullprop_mean, &i_nullprop_SD)));
						end;
						output;
					end;
				end;
			run;        
			';
        call execute(s);
    end;
run;

results in right at the first if statement for the case that i=1:

ERROR: File WORK.COUNT_0.DATA does not exist.

I don't understand why SAS does not accept the case:

if '||trim(left(put(i,3.)))||' eq "1" or '||trim(left(put(i,3.)))||' eq 1 then do;

As you can see I tried to resolve by handling i as a character.

 

In python I would simply put a:

print(i)

in between the loop. 

 

How is it possible to debug such cases? 

 

THX and BR

Lukas

1 ACCEPTED SOLUTION

Accepted Solutions
Reeza
Super User

Making a 1001 assumptions here, I think one of these two programs is closer to what you're looking for - likely the second. 

 

%let k_interims = 5;
%let n_1 = 10;
%let n_2 = 10;
%let n_3 = 10;
%let n_4 = 10;
%let n_5 = 10;
%let i_nullprop_mean = 0.5;
%let i_nullprop_SD = 0.1;
%let j_alternative_mean = 0.5;
%let j_alternative_SD = 0.1;


proc datasets lib=work;
delete count_:;
run;quit;

options mprint symbolgen;

*expand dataset exponentially;
%macro loop (n=);
    %do i=1 %to &n;

        data count_&i.;
            length trt sbi 4;

            %if &i ne 1 %then
                %do;
                    set count_%eval(&i-1);
                %end;

            do j=1 to &&n_&i;

                if mod(j, 2) eq 0 then
                    do;
                        trt=1;
                        sbi=rand("Bernoulli", abs(rand("Normal", &j_alternative_mean, 
                            &j_alternative_SD)));
                    end;
                else
                    do;
                        trt=0;
                        sbi=rand("Bernoulli", abs(rand("Normal", &i_nullprop_mean, 
                            &i_nullprop_SD)));

                    end;
              output;
            end;
    run;

%end;
%mend;

%loop(n=&k_interims);

Appends data sets together;


proc datasets lib=work;
delete count_:;
run;quit;

*appends each dataset together at the end for the last dataset to have 50 rows;
%macro loop (n=);
    %do i=1 %to &n;

        data count_&i.;
            length trt sbi 4;


            do j=1 to &&n_&i;

                if mod(j, 2) eq 0 then
                    do;
                        trt=1;
                        sbi=rand("Bernoulli", abs(rand("Normal", &j_alternative_mean, 
                            &j_alternative_SD)));
                    end;
                else
                    do;
                        trt=0;
                        sbi=rand("Bernoulli", abs(rand("Normal", &i_nullprop_mean, 
                            &i_nullprop_SD)));

                    end;
              output;
            end;
    run;
    
                %if &i ne 1 %then
                %do;
                    proc append base=count_&i data=count_%eval(&i-1);
                    run;
                %end;

%end;
%mend;

%loop(n=&k_interims);

@LuGa wrote:

Dear SAS Gurus,

 

please help me debugging my loop. 

 

%let k_interims = 5;
%let n_1 = 100;
%let n_2 = 100;
%let n_3 = 100;
%let n_4 = 100;
%let n_5 = 100;

%let i_nullprop_mean = 0.5;
%let i_nullprop_SD = 0.1;

%let j_alternative_mean = 0.5;
%let j_alternative_SD = 0.1;


	data _null_;
		do i=1 to &k_interims by 1;
			s= '
			data count_'||trim(left(put(i,3.)))||' (drop=j);

				length trt sbi 4;

				if '||trim(left(put(i,3.)))||' eq "1" or '||trim(left(put(i,3.)))||' eq 1 then do;
					
					do j = 1 to round(&n_'||trim(left(put(i,3.)))||', 2) by 1;
						if mod(j, 2) eq 0 then do;
							trt = 1;
							sbi = rand("Bernoulli", abs(rand("Normal", &j_alternative_mean, &j_alternative_SD)));
						end;
						else do;
							trt = 0;
							sbi = rand("Bernoulli", abs(rand("Normal", &i_nullprop_mean, &i_nullprop_SD)));
						end;
						output;
					end;
				end;

				else if '||trim(left(put(i,3.)))||' ne "1" or '||trim(left(put(i,3.)))||' ne 1 then do;

					set count_'||trim(left(put(i-1, 3.)))||';

					do j = 1 to round(&n_'||trim(left(put(i,3.)))||', 2) by 1;
						if mod(j, 2) eq 0 then do;
							trt = 1;
							sbi = rand("Bernoulli", abs(rand("Normal", &j_alternative_mean, &j_alternative_SD)));
						end;
						else do;
							trt = 0;
							sbi = rand("Bernoulli", abs(rand("Normal", &i_nullprop_mean, &i_nullprop_SD)));
						end;
						output;
					end;
				end;
			run;        
			';
        call execute(s);
    end;
run;

results in right at the first if statement for the case that i=1:

ERROR: File WORK.COUNT_0.DATA does not exist.

I don't understand why SAS does not accept the case:

if '||trim(left(put(i,3.)))||' eq "1" or '||trim(left(put(i,3.)))||' eq 1 then do;

As you can see I tried to resolve by handling i as a character.

 

In python I would simply put a:

print(i)

in between the loop. 

 

How is it possible to debug such cases? 

 

THX and BR

Lukas


 

View solution in original post

7 REPLIES 7
Patrick
Opal | Level 21

Look at macros as code generators. 

 

Your macro generates syntactically wrong code like:

data _null_;
  data count_0;
    .....
  run;
run;

 

Without doing much digging into your code it looks to me like your mixing macro level and data step level code in a way that's not possible. I've also got some suspicion that you wouldn't need any macro logic at all but could keep things simple using data step only.

I suggest you tell us what you have and what you want to achieve. 

 

LuGa
Obsidian | Level 7

Hi Patrick,

 

thanks for your help.

 

I would like to create data sets sequentially. (Data2 += Data1; Data3 += Data2 ..... DataK += DataJ)

 

2 groups (treatment and placebo) and a bernoulli distributed outcome variable (SBI).

 

Thanks in advance and best regards

Lukas

JosvanderVelden
SAS Super FREQ
Can you provide a bit more detail?
Maybe even an example like:
Data data1;
input vars;
datalines;
;
run;

Data data2;
set data1;
.... statements ....
run;

.
.
.

Data dataK;
set dataJ;
..... statements .....
run;
ballardw
Super User

@LuGa wrote:

Hi Patrick,

 

thanks for your help.

 

I would like to create data sets sequentially. (Data2 += Data1; Data3 += Data2 ..... DataK += DataJ)

 

2 groups (treatment and placebo) and a bernoulli distributed outcome variable (SBI).

 

Thanks in advance and best regards

Lukas


Make a small example of Data 1. Then show us what Data 2 is  supposed to look like. I am afraid that this

Data2 += Data1; Data3 += Data2 ..... DataK += DataJ)  looks like Data2 is supposed to be the same as Data1 as that "+" has no meaning in context that makes sense.

Note that the basic code you need to create a new data set from an existing one is:

data data2;
   set data1;
run;

Plus, why do you think that you need multiple data sets???

 

You are going to a lot of effort apparently to force even/odd assignment to treatment. Why? What analysis are you doing that requires such? Typically if you want 50 in one group and 50 in another group you might do something like:

do j = 1 to 50;
   do trt=0 to 1;
   	if trt = 1 then
   	   sbi = rand("Bernoulli", abs(rand("Normal", &j_alternative_mean, &j_alternative_SD)));
   	else if trt = 0 then 
   	   sbi = rand("Bernoulli", abs(rand("Normal", &i_nullprop_mean, &i_nullprop_SD)));
      output;
   end;
end;

Have you tested a very small attempt to use SET inside a loop as you attempt? You might find the results a little different than you expect (not that I actually follow the intent

 

I suspect that one data set with a variable indicating which "run", probably more correctly referred to as a REPLICATE, that would be equivalent to the numeral in your data set names, would be more understandable. Plus there are procedures that use Replicate for analysis.

Tom
Super User Tom
Super User

What is it that you are trying to do?

Your data _null_ step is completely unreadable.  If I try to convert it into something I can read

data _null_;
  do i=1 to &k_interims by 1;
   s=  'data count_'
     ||trim(left(put(i,3.)))
     ||' (drop=j);length trt sbi 4;if '
     ||trim(left(put(i,3.)))
     ||' eq "1" or '
     ||trim(left(put(i,3.)))
     ||' eq 1 then do;do j = 1 to round(&n_'
     ||trim(left(put(i,3.)))
     ||', 2) by 1;if mod(j, 2) eq 0 then do;trt = 1;'
     ||'sbi = rand("Bernoulli", abs(rand("Normal", &j_alternative_mean, &j_alternative_SD)));'
     ||'end;else do;trt = 0;sbi = rand("Bernoulli", abs(rand("Normal", &i_nullprop_mean, &i_nullprop_SD)));'
     ||'end;output;end;end;else if '
     ||trim(left(put(i,3.)))
     ||' ne "1" or '
     ||trim(left(put(i,3.)))
     ||' ne 1 then do;set count_'
     ||trim(left(put(i-1, 3.)))
     ||';do j = 1 to round(&n_'
     ||trim(left(put(i,3.)))
     ||', 2) by 1;if mod(j, 2) eq 0 then do;trt = 1;'
     ||'sbi = rand("Bernoulli", abs(rand("Normal", &j_alternative_mean, &j_alternative_SD)));'
     ||'end;else do;trt = 0;sbi = rand("Bernoulli", abs(rand("Normal", &i_nullprop_mean, &i_nullprop_SD)));'
     ||'end;output;end;end;run;';
   call execute(s);
 end;
run;

It still makes no sense to me.

 

Is the goal to write a PROGRAM?  Why not just write the program to a file?  Then you can LOOK at the file and see if the generated program makes any sense.  Also then you can use the power of the PUT statement to make writing the code easier.

filename code temp;
data _null_;
  file code ;
  do i=1 to &k_interims by 1;
    put 'data count_' i  '(drop=j);'
      / ' length trt sbi 4;'
....

Some of that logic makes no sense.  For example this block:

'if '||trim(left(put(i,3.)))||' eq "1" or '||trim(left(put(i,3.)))||' eq 1 then do;'

Did you mean to run the IF in the data _NULL_ step?  Do you want to generate different code when I=1 then for the other times through the DO loop?

 

Reeza
Super User

Making a 1001 assumptions here, I think one of these two programs is closer to what you're looking for - likely the second. 

 

%let k_interims = 5;
%let n_1 = 10;
%let n_2 = 10;
%let n_3 = 10;
%let n_4 = 10;
%let n_5 = 10;
%let i_nullprop_mean = 0.5;
%let i_nullprop_SD = 0.1;
%let j_alternative_mean = 0.5;
%let j_alternative_SD = 0.1;


proc datasets lib=work;
delete count_:;
run;quit;

options mprint symbolgen;

*expand dataset exponentially;
%macro loop (n=);
    %do i=1 %to &n;

        data count_&i.;
            length trt sbi 4;

            %if &i ne 1 %then
                %do;
                    set count_%eval(&i-1);
                %end;

            do j=1 to &&n_&i;

                if mod(j, 2) eq 0 then
                    do;
                        trt=1;
                        sbi=rand("Bernoulli", abs(rand("Normal", &j_alternative_mean, 
                            &j_alternative_SD)));
                    end;
                else
                    do;
                        trt=0;
                        sbi=rand("Bernoulli", abs(rand("Normal", &i_nullprop_mean, 
                            &i_nullprop_SD)));

                    end;
              output;
            end;
    run;

%end;
%mend;

%loop(n=&k_interims);

Appends data sets together;


proc datasets lib=work;
delete count_:;
run;quit;

*appends each dataset together at the end for the last dataset to have 50 rows;
%macro loop (n=);
    %do i=1 %to &n;

        data count_&i.;
            length trt sbi 4;


            do j=1 to &&n_&i;

                if mod(j, 2) eq 0 then
                    do;
                        trt=1;
                        sbi=rand("Bernoulli", abs(rand("Normal", &j_alternative_mean, 
                            &j_alternative_SD)));
                    end;
                else
                    do;
                        trt=0;
                        sbi=rand("Bernoulli", abs(rand("Normal", &i_nullprop_mean, 
                            &i_nullprop_SD)));

                    end;
              output;
            end;
    run;
    
                %if &i ne 1 %then
                %do;
                    proc append base=count_&i data=count_%eval(&i-1);
                    run;
                %end;

%end;
%mend;

%loop(n=&k_interims);

@LuGa wrote:

Dear SAS Gurus,

 

please help me debugging my loop. 

 

%let k_interims = 5;
%let n_1 = 100;
%let n_2 = 100;
%let n_3 = 100;
%let n_4 = 100;
%let n_5 = 100;

%let i_nullprop_mean = 0.5;
%let i_nullprop_SD = 0.1;

%let j_alternative_mean = 0.5;
%let j_alternative_SD = 0.1;


	data _null_;
		do i=1 to &k_interims by 1;
			s= '
			data count_'||trim(left(put(i,3.)))||' (drop=j);

				length trt sbi 4;

				if '||trim(left(put(i,3.)))||' eq "1" or '||trim(left(put(i,3.)))||' eq 1 then do;
					
					do j = 1 to round(&n_'||trim(left(put(i,3.)))||', 2) by 1;
						if mod(j, 2) eq 0 then do;
							trt = 1;
							sbi = rand("Bernoulli", abs(rand("Normal", &j_alternative_mean, &j_alternative_SD)));
						end;
						else do;
							trt = 0;
							sbi = rand("Bernoulli", abs(rand("Normal", &i_nullprop_mean, &i_nullprop_SD)));
						end;
						output;
					end;
				end;

				else if '||trim(left(put(i,3.)))||' ne "1" or '||trim(left(put(i,3.)))||' ne 1 then do;

					set count_'||trim(left(put(i-1, 3.)))||';

					do j = 1 to round(&n_'||trim(left(put(i,3.)))||', 2) by 1;
						if mod(j, 2) eq 0 then do;
							trt = 1;
							sbi = rand("Bernoulli", abs(rand("Normal", &j_alternative_mean, &j_alternative_SD)));
						end;
						else do;
							trt = 0;
							sbi = rand("Bernoulli", abs(rand("Normal", &i_nullprop_mean, &i_nullprop_SD)));
						end;
						output;
					end;
				end;
			run;        
			';
        call execute(s);
    end;
run;

results in right at the first if statement for the case that i=1:

ERROR: File WORK.COUNT_0.DATA does not exist.

I don't understand why SAS does not accept the case:

if '||trim(left(put(i,3.)))||' eq "1" or '||trim(left(put(i,3.)))||' eq 1 then do;

As you can see I tried to resolve by handling i as a character.

 

In python I would simply put a:

print(i)

in between the loop. 

 

How is it possible to debug such cases? 

 

THX and BR

Lukas


 

LuGa
Obsidian | Level 7

Hi Reeza,

 

the second one does the job as intended.

 

Thank you and best regards

Lukas

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

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
  • 7 replies
  • 500 views
  • 10 likes
  • 6 in conversation