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
1 | 2 | 4 | 3 |
2 | 1 | 2 | 4 |
3 | 3 | 1 | 2 |
4 | 4 | 1 | 2 |
5 | 4 | 3 | 1 |
6 | 2 | 3 | 1 |
7 | 1 | 4 | 3 |
8 | 3 | 2 | 4 |
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?
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;
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.
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.
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;
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?
Oops, i missed to change this
%do %until(stop ne 0);
to
%do %until(&stop ne 0);
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);
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;
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!
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.
Ready to level-up your skills? Choose your own adventure.