I am stumped with a very simple do loop problem. For reasons unknown, the loop logic is ignoring the equals sign I'm using so that the output is not what I need.
This works:
data work.retail;
input year:32. quarter:32. sales:32.;
datalines;
2007 1 921266
2007 2 1013371
2007 3 1000151
2007 4 1060394
2008 1 950268
2008 2 1028016
2008 3 999824
2008 4 957207
;;;;
run;
data work.retail2;
set work.retail;
if quarter = 1
then do;
d1 = 1;
end;
else do;
d1 = 0;
end;
if quarter = 2
then do;
d2 = 1;
end;
else do;
d2 = 0;
end;
if quarter = 3
then do;
d3 = 1;
end;
else do;
d3 = 0;
end;
run;
/* But this does not work */
%macro MakeRetail2;
data work.retail2;
set work.retail;
%do i =1 %to 3;
%if quarter = &i
%then %do;
d&i = 1;
%end;
%else %do;
d&i = 0;
%end; * end else-do;
%end; * end do-loop *;
output;
run;
%mend MakeRetail2;
%MakeRetail2
/* Any guidance would be appreciated */
%if quarter = &i %then %do;
Here is the problem — %if cannot access the values of data set variables like QUARTER. This actually compares a text string (not the data set variable) quarter to the value of &i, and since &i is always an integer, the text string quarter is never equal to &i.
So, you can use arrays to eliminate the need for macros. Arrays specifically access the value of data set variables, which macro %IF cannot do. Also the resulting code is much simpler.
data retail2;
set retail;
array d d1-d3;
do i =1 to 3;
if quarter = i then d(i) = 1;
else d(i)=0;
end;
drop i;
run;
Please also note the indenting of the code makes following the code and following the looping easier, visually.
Lastly, there is rarely a need to create dummy variables like this. What do you plan to do with these dummy variables? Most SAS PROCs don't need dummy variables to do analyses.
%if quarter = &i %then %do;
Here is the problem — %if cannot access the values of data set variables like QUARTER. This actually compares a text string (not the data set variable) quarter to the value of &i, and since &i is always an integer, the text string quarter is never equal to &i.
So, you can use arrays to eliminate the need for macros. Arrays specifically access the value of data set variables, which macro %IF cannot do. Also the resulting code is much simpler.
data retail2;
set retail;
array d d1-d3;
do i =1 to 3;
if quarter = i then d(i) = 1;
else d(i)=0;
end;
drop i;
run;
Please also note the indenting of the code makes following the code and following the looping easier, visually.
Lastly, there is rarely a need to create dummy variables like this. What do you plan to do with these dummy variables? Most SAS PROCs don't need dummy variables to do analyses.
@fcolina wrote:
The array approach is far simpler. Thank you for the explanation and thank you to the others that came up with answers for this problem. I really appreciate it.
@fcolina Next, lets address why you feel you need dummy variables ... this is rarely necessary in most SAS PROCs. Please explain why you need these dummy variables for quarter?
data work.retail;
input year:32. quarter:32. sales:32.;
datalines;
2007 1 921266
2007 2 1013371
2007 3 1000151
2007 4 1060394
2008 1 950268
2008 2 1028016
2008 3 999824
2008 4 957207
;
;
;
;
run;
data work.retail2_correct;
set work.retail;
if quarter=1 then
do;
d1=1;
end;
else
do;
d1=0;
end;
if quarter=2 then
do;
d2=1;
end;
else
do;
d2=0;
end;
if quarter=3 then
do;
d3=1;
end;
else
do;
d3=0;
end;
run;
data retail2_array;
set retail;
d1=0;
d2=0;
d3=0;
d4=0;
array d(*) d1-d4;
d(quarter)=1;
run;
%macro MakeRetail2;
data work.retail2_macro;
set work.retail;
%do i=1 %to 3;
if quarter=&i
then
d&i=1;
else
d&i=0;
%end;
* end else-do;
run;
%mend MakeRetail2;
%MakeRetail2;
Format your code including indents as a start.
See the two different options above.
FYI - see this post plus the links below to see the different options to create dummy variables more easily. And note that if the proc supports a CLASS statement (LOGISTIC/PHREG) this isn't necessarily required at all. https://communities.sas.com/t5/SAS-Communities-Library/How-to-create-dummy-variables-Categorical-Var...
First of all don't bother to use looping when it adds no value.
data retail;
input year quarter sales;
datalines;
2007 1 921266
2007 2 1013371
2007 3 1000151
2007 4 1060394
2008 1 950268
2008 2 1028016
2008 3 999824
2008 4 957207
;;;;
data retail2;
set retail;
d1=quarter=1;
d2=quarter=2;
d3=quarter=3;
d4=quarter=4;
run;
If you do need to repeat a series of actions for a set of common variables the default tool to use is an ARRAY. There is no need to use CODE GENERATION.
data retail2;
set retail;
array d[4];
do index=1 to 4;
d[index]=quarter=index;
end;
drop index;
run;
If you do have a need for code generation then make sure it is generating the code you want. This macro %DO loop will generate the code in my first data step.
data retail2;
set retail;
%do quarter=1 %to 4;
d&quarter=quarter=&quarter;
%end;
run;
@fcolina wrote:
Yes thank you, I agree that the array works best.
With an N of 4 the wallpaper code it easier to create and understand then the DO loop.
@fcolina wrote:
I don't know what happened to the indents I had, they vanished when I pasted to the website.
Use the Insert Code or Insert SAS Code button on the editor menu to get a pop-up window where you can paste text that preserve the spacing. If you put the code into the body of your message it assumes it is paragraphs to be reflowed to fit the current browsers width.
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
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.