DATA Step, Macro, Functions and more

Do UNTIL Loop with conditional stop

Accepted Solution Solved
Reply
Occasional Contributor
Posts: 12
Accepted Solution

Do UNTIL Loop with conditional stop

Hello, I wish to use a do until loop until the condition that there is a unique drug for each observation with some form of randomization for 3 repetitions is met.

 

data units;
do Unit = 1 to 8;
	output;
	end;
run;

 

The top shows dummy data. I will explain the overall problem that I have and how I'm trying to solve it.

 

id           Drug_1 Drug_2 Drug_3

1243
2124
3312
4412
5431
6231
7143
8324

 

In the second-fourth column, 1 shows up 2 times, 2 shows up 2 times, 3 shows up 2 times, and 4 shows up 2 times. They also do not repeat through each observation. In this example, the groups (1-4) are evenly distributed but I'd like to have the option to change their sizes depending on the condition

 

To solve this, I am trying to cycle through different seeds to be able to get the desired outcome. To accomplish this, I created two local macros. n is to cycle through seed numbers and stop is to indicate when I've obtained the desired dataset. This outcome is shown through the sum of indicator being 0 or through drug 1 - drug 3 not equal to one another.

 

 

%macro m(start);

	%local n;
	%let n=&start;

	%local stop;
	%let stop = 0;

	%do %until(stop ne 0);

			proc surveyselect data=units groups=(2,2,2,2) seed=&n reps=3 noprint
			    out=assignedUnits(rename=groupId=drug); 
			run;

			proc sort data=assignedUnits;
				by Unit;
			run;

			proc transpose data=assignedUnits out=wide1(drop=_NAME_ _LABEL_) prefix=drug_;
			    by Unit;
			    var drug;
			run;

			data desiredData;
				set wide1;
				
				indicator=.;				
				if drug_1 ne drug_2 and drug_1 ne drug_3 and drug_2 ne drug_3 then drug = 0;
					else indicator=1;
				
				st=.;
				if drug_1 ne drug_2 and drug_1 ne drug_3 and drug_2 ne drug_3 then st = 0;
					else %let stop=%eval(&stop+1);
			run;

			proc print data=desiredData;
				sum indicator;
				title "Seed number &n";
			run;

		%let n=%eval(&n+1);
	%end;
%mend m;

 

Unfortunately, the second if statement is not working. I want it to change the local variable stop to when the if statement is true but it has not been performing as desired. Is there any way to perform this?

 


Accepted Solutions
Solution
‎01-16-2018 04:40 PM
Super User
Posts: 2,061

Re: Do UNTIL Loop with conditional stop

[ Edited ]
Posted in reply to Learning_S

Nope, won't work. If i can guess, You may have to change the part of the  program to this :

data desiredData;
				set wide1 end=last;
				
				indicator=.;	
				st=.;
				if (drug_1 ne drug_2) and (drug_1 ne drug_3) and (drug_2 ne drug_3) then do;
					drug = 0;
					st = 0;
					end;
					else do; 
					indicator=1;
					end;
				sum_indicator+indicator;
      if last then do; if sum_indicator=0 then /*your call symputx goes here*/
				
			run;

 

 

View solution in original post


All Replies
Super User
Posts: 2,061

Re: Do UNTIL Loop with conditional stop

Posted in reply to Learning_S

That is because you are trying to execute a macro statement at execution time(datastep execution). Unfortunately, that execution

%let stop=%eval(&stop+1);

happens at compile time. 

Super User
Posts: 6,933

Re: Do UNTIL Loop with conditional stop

Posted in reply to Learning_S

I can't promise this fixes everything, but here are two items that must be changed.

 

%do %until (stop ne 0);

 

This comparison will always be true, because STOP does not refer to a DATA step variable named STOP.  Instead, you can use:

 

%do %until (&stop = 1);

 

Secondly, the DATA step cannot execute a %LET statement.  This statement is not doing anything when the DATA step executes:

 

else %let stop = %eval(&stop + 1);

 

This might be closer to what you want:

 

else call symputx('stop', '1');

 

That would assign the macro variable &STOP a value of 1, when the ELSE statement executes.

 

There may be more, but fixing this would at least be a starting point.

Super User
Posts: 2,061

Re: Do UNTIL Loop with conditional stop

Posted in reply to Learning_S

i tried to fix a bit, see if this helps:

 

%macro m(start);

	%local n;
	%let n=&start;

	%local stop;
	%let stop = 0;

	%do %until(stop ne 0);

			proc surveyselect data=units groups=(2,2,2,2) seed=&n reps=3 noprint
			    out=assignedUnits(rename=groupId=drug); 
			run;

			proc sort data=assignedUnits;
				by Unit;
			run;

			proc transpose data=assignedUnits out=wide1(drop=_NAME_ _LABEL_) prefix=drug_;
			    by Unit;
			    var drug;
			run;

			data desiredData;
				set wide1;
				
				indicator=.;	
				st=.;
				if (drug_1 ne drug_2) and (drug_1 ne drug_3) and (drug_2 ne drug_3) then do;
					drug = 0;
					st = 0;
					end;
					else do; 
					indicator=1;
					call symputX('stop',resolve('&stop')+1);
					end;
				
				
			run;

			proc print data=desiredData;
				sum indicator;
				title "Seed number &n";
			run;

		%let n=%eval(&n+1);
	%end;
%mend m;
Occasional Contributor
Posts: 12

Re: Do UNTIL Loop with conditional stop

Posted in reply to novinosrin

Thanks, that almost works. Unfortunately, it continues past seed 93 (I verified that it meets the aforementioned conditions). I read that symputX converts it to character. Am I correct in that assertion as could that be why it keeps going?

Super User
Posts: 2,061

Re: Do UNTIL Loop with conditional stop

Posted in reply to Learning_S

Oops, i missed to change this

	%do %until(stop ne 0);

to

	%do %until(&stop ne 0);

 

Occasional Contributor
Posts: 12

Re: Do UNTIL Loop with conditional stop

Posted in reply to novinosrin

I apologize, but I saw a major error in my program. The symputX('stop',resolve('&stop')+1); portion should somehow be related to the sum of the indicator variable. Would the following work?

if sum(indicator) = 0 then call symputX('stop',resolve('&stop')+1);
Solution
‎01-16-2018 04:40 PM
Super User
Posts: 2,061

Re: Do UNTIL Loop with conditional stop

[ Edited ]
Posted in reply to Learning_S

Nope, won't work. If i can guess, You may have to change the part of the  program to this :

data desiredData;
				set wide1 end=last;
				
				indicator=.;	
				st=.;
				if (drug_1 ne drug_2) and (drug_1 ne drug_3) and (drug_2 ne drug_3) then do;
					drug = 0;
					st = 0;
					end;
					else do; 
					indicator=1;
					end;
				sum_indicator+indicator;
      if last then do; if sum_indicator=0 then /*your call symputx goes here*/
				
			run;

 

 

☑ This topic is solved.

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

Discussion stats
  • 7 replies
  • 201 views
  • 5 likes
  • 3 in conversation