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

Hi there,

I have 50 categorical variables for which I need to create dummy variables for each level of response. For instance, variable Q1 has 3 levels: 1,2,3. The macro DUMMYLEVEL below will create 3 dummy variables for Q1: Q1_1, Q1_2, and Q1_3.

 

My codes below-- which invokes the macro DUMMYLEVEL twice in the DATA step-- produces the following error message: 

"ERROR 124-185: The variable D has already been defined."

 

This error only occurs when the macro DUMMYLEVEL is called more than once in the DATA step. Anybody have experience working around this error to achieve my goal of creating dummy variables for 50 categorical variables? Thank you!

 

 

/* Macro to create dummy variables for ROOT variable with NUM levels */

 

%MACRO DUMMYLEVEL (ROOT= , NUM= );
ARRAY D(*) &ROOT._1 - &ROOT._&NUM. (&NUM.*0);
   IF &ROOT. NE . THEN D(&ROOT.)= 1; 
   OUTPUT;
   IF &ROOT. NE . THEN D(&ROOT.)= 0;
%MEND;

 

/* Sample DATA step: call macro DUMMYLEVEL twice */
DATA OUT;
SET IN (KEEP= ID Q1--Q50);

   %Dummylevel (root= Q1, num= 3);
   %Dummylevel (root= Q2, num= 2);
RUN;

1 ACCEPTED SOLUTION

Accepted Solutions
Kurt_Bremser
Super User

Adapt your macro to create individually named arrays for each invocation:

/* Macro to create dummy variables for ROOT variable with NUM levels */

%macro dummylevel(root,num);
array d_&root.(*) &root._1 - &root._&num.;
do d__i = 1 to dim(d_&root.);
  d_&root.{d__i) = 0;
end;
if &root. ne . then d_&root.(&root.)= 1; 
drop d__i;
%mend;

Also note that I removed the output and reset to 0, and instead intialized thé whole array for each data step iteration. Otherwise you'd multiply your dataset observations.

In example code:

data have;
input ID Q1 Q2;
cards;
1 2 .
2 1 1
3 2 2
;
run;

data want;
set have;
%dummylevel(Q1,3);
%dummylevel(Q2,3);
run;

proc print;run;

you then get this result:

Obs    ID    Q1    Q2    Q1_1    Q1_2    Q1_3    Q2_1    Q2_2    Q2_3

 1      1     2     .      0       1       0       0       0       0 
 2      2     1     1      1       0       0       1       0       0 
 3      3     2     2      0       1       0       0       1       0 

 

Edit: Corrected to the proper macrocode.

View solution in original post

4 REPLIES 4
Reeza
Super User

You need a unique array declaration for each macro call. 

 

Although you can do this, have you looked into some of the other methods? Here are some references that illustrate alternatives. 

http://blogs.sas.com/content/iml/2016/02/22/create-dummy-variables-in-sas.html

 

https://communities.sas.com/t5/SAS-Statistical-Procedures/How-to-create-dummy-variables-Categorical-...

 

Kurt_Bremser
Super User

Adapt your macro to create individually named arrays for each invocation:

/* Macro to create dummy variables for ROOT variable with NUM levels */

%macro dummylevel(root,num);
array d_&root.(*) &root._1 - &root._&num.;
do d__i = 1 to dim(d_&root.);
  d_&root.{d__i) = 0;
end;
if &root. ne . then d_&root.(&root.)= 1; 
drop d__i;
%mend;

Also note that I removed the output and reset to 0, and instead intialized thé whole array for each data step iteration. Otherwise you'd multiply your dataset observations.

In example code:

data have;
input ID Q1 Q2;
cards;
1 2 .
2 1 1
3 2 2
;
run;

data want;
set have;
%dummylevel(Q1,3);
%dummylevel(Q2,3);
run;

proc print;run;

you then get this result:

Obs    ID    Q1    Q2    Q1_1    Q1_2    Q1_3    Q2_1    Q2_2    Q2_3

 1      1     2     .      0       1       0       0       0       0 
 2      2     1     1      1       0       0       1       0       0 
 3      3     2     2      0       1       0       0       1       0 

 

Edit: Corrected to the proper macrocode.

STTran
Calcite | Level 5

Thank you for your help-- the macro worked perfectly. For some reason, your original macro is not showing on this page. As a reference for others, I've retyped it here:

 

%macro dummylevel (root= , num=);
array d_&root. (*) &root._1 - &root._&num.;
do d__i = 1 to dim(d_&root.);
    d_&root.{d__i} = 0;
end;
if &root. ne . then d_&root.(&root.) = 1;
drop d__i;
%mend;

RW9
Diamond | Level 26 RW9
Diamond | Level 26

Sorry, I am not sure why all that is necessary?  Arrays can be defined with multiple dimensions, its then just the need to get your variables in the necessary order in the define context:

data out;
  set in (keep=id q1--q50);
  array resp{50,3) $20;
  do i=1 to 50;
    resp{i,1}=...;
    resp{i,2}=...;
...
  end;
run;

And please dont code in all upper case, its one of the worse visual things to do code.

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

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
  • 4 replies
  • 2236 views
  • 2 likes
  • 4 in conversation