12-05-2015 10:53 PM
Working with the following toy dataset, I'm trying to create code which will automatically calculate two-way interaction variables for a given set of main effects named "black", "white" and "red".
data test; input black white red; cards; 10 20 30 40 50 60 70 80 90 ; run; proc contents data=test out=varlist(keep=name); run; data _null_; length allvars $20; retain allvars ' '; set varlist end=eof; allvars = trim(left(allvars))||' '||left(name); if eof then call symput('varlist', allvars); run; %put &varlist; /* black red white */ %macro create_interaction_vars(); data test; set test; %let separator_s =%str( ); %do i=1 %to 3; %let v&i = %scan(&varlist, &i, %str( )); %end; %do i=1 %to 3; %do j=1 %to 3; %if &i <= &j %then %goto continue; data test; set test; w&i.&j = &&v&i.*&&v&j; rename w&i.&j = "&v&i._&v&j_int"; run; %continue: %end; %end; run; %mend; %create_interaction_vars();
I have no problems creating interactions variables named w12, w13, and w23. However, I'd like the interaction terms to have more informative names created from the main effect terms such as: "white_red_int", "white_black_int", and "red_black_int", but am getting tied up when it comes to concatenating two macro variable names.
Any help is much appreciated, thanks!
12-05-2015 11:40 PM
Are you familiar with the SAS shortcut notation for creating two way interactions.
You can use the | with @N to create your two way interactions. I can't find the documentation but I'm sure it's in there somewhere.
Here's an example using SASHELP.CARS
proc glm data=sashelp.cars; model weight = invoice | length | mpg_city | mpg_highway @2; run;
12-06-2015 09:00 AM
Yes, I've used that feature and it's quite handy.
In this case I have a lot of variables & the dataset will be exported to a text file for analysis in other programs. Otherwise I'd use the | and n@ option.
12-06-2015 09:18 AM
12-06-2015 03:42 PM
You can build on @Reeza's suggestion with proc GLMMOD and get your design matrix directly into a dataset. Just add your dependent variable to your dataset :
data test; input id green black white red; cards; 1 2.1 10 20 30 2 3.2 40 50 60 3 4.3 70 80 90 ; proc glmmod data=test outdesign=testd outparm=testp; model green = black | white | red @2 / noint; weight id; /* Just copy this variable */ run; proc sql; select cats("Col", _COLNUM_, "=", translate(EFFNAME, "_", "*")), cats("Col", _COLNUM_, "=""", EFFNAME, """") into :renameVars separated by " ", :labelVars separated by " " from testp; quit; data myDesign; set testd; rename &renameVars; label &labelVars; run; proc print data=myDesign noobs label; run;
12-07-2015 10:05 AM
Thanks PGStats, this works great!
There must still be a way to combine two macro variable names like "black" and "white" into a single varibale name "black_white_int", but getting the macro code syntax right with the ampersands and quotation marks has always been tricky for me.
12-07-2015 05:13 PM
Here's another solution to creating interaction variables that avoids macro programming.
Create a variable list of the main effects of interest from proc contents, then accumulate all of the interaction variable creation data step statements into one long macro variable.
For example, to create the interaction variables green_red_int, black_red_int, and white_red_int, run the following code:
data test; input id green black white red; cards; 1 2.1 10 20 30 2 3.2 40 50 60 3 4.3 70 80 90 ; proc contents data=test out=varlist(keep=varnum name) order=varnum; run; proc sort data=varlist; by varnum; run; data varlist; set varlist; if varnum in(2:4); run; data _null_; length allvars $90; retain allvars; set varlist end=eof; allvars =trim(left(allvars))||' '||trim(name)||'_red_int = '||trim(name)||'*red;'; if eof then call symput('interactions', allvars); run; %put &interactions; data test2; set test; &interactions; run;