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

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?

 

1 ACCEPTED SOLUTION

Accepted Solutions
novinosrin
Tourmaline | Level 20

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

7 REPLIES 7
novinosrin
Tourmaline | Level 20

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. 

Astounding
PROC Star

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.

novinosrin
Tourmaline | Level 20

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;
Learning_S
Obsidian | Level 7

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?

novinosrin
Tourmaline | Level 20

Oops, i missed to change this

	%do %until(stop ne 0);

to

	%do %until(&stop ne 0);

 

Learning_S
Obsidian | Level 7

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);
novinosrin
Tourmaline | Level 20

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;

 

 

SAS Innovate 2025: Register Now

Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

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