DATA Step, Macro, Functions and more

A macro question

Reply
Contributor
Posts: 49

A macro question

Hi,

I posted it yesterday and got some valuable feedback, but it wasn’t what I want. Sorry to bother again. Below is my mini-version data:

data mydata;
input var1 var1_suffix var2 var2_suffix var3 var3_suffix var4 var4_suffix var5 var5_suffix;
datalines;
4.2 1 1.8 0 2.3 0 3.5 0 2.3 1
3 0 2.5 0 5.2 1 6.4 0 2.4 0
3.1 0 6.7 0 5.1 1 3 0 4 0
;
run;

var1 through var5 are five variables of interest. var1_suffix through var5_suffix are corresponding indicators which take values of 0 or 1. If its value=1, then I want set the corresponding variable value to missing. For example, var1=4.2 and var1_suffix=1 so I will change the value of var1 to missing, the result should be var1=. and var1_suffix=1. I wrote a macro to do this:

%MACRO mymacro(varLIST);
DATA mydataout;
SET mydata;
%LET K=1;
%LET a=%SCAN(&varLIST,&K);
%DO %WHILE("a" NE "");
%IF &a._suffix=1 %THEN &a=.;
%LET K=%EVAL(&K+1);
%LET a=%SCAN(&varLIST,&K);
%END;
RUN;
%MEND;
%mymacro(var1 var2 var3 var4 var5);

In fact I have lots of variables(could be var1 to varn), and so var_suffix, that's why I prefer using macro program, cause it is hard to calculate the total number of variables and the total varies everytime I run it. Also, var_suffix is named exactly start with var(i) and followed by _suffix.

Thanks,
Lu
Super Contributor
Super Contributor
Posts: 3,174

Re: A macro question

You still are referencing the character "a" in your %DO statement. Also, now you are testing a SAS macro variable named var1_suffix which I don't believe is your intention.

Therefore the macro you have coded just loops continuously and will not compile.

I encourage the OP to using this OPTIONS statement to generate some self-help diagnostics:

OPTIONS SOURCE SOURCE2 MGEN SGEN MPRINT /* MLOGIC */ ;

Lastly, I don't understand why you abandoned your other post - that is where the discussion should stay until resolved.

Scott Barry
SBBWorks, Inc. Message was edited by: sbb
Contributor
Posts: 49

Re: A macro question

Thanks. I am new to this forum and I don't know I should stay the same post until it is solved since I saw nobody respond any more. Sorry about that.

This time I used options you suggested. I tried &a._suffix and it is referencing var1_suffix to var5_suffix, that is exactly what I want (if var1_suffix=1 then I want to the value of var1 be missing). You are right, when I did this, sas loops forever and I have to quit. If I write sas code: if var1_suffix=1 then var1=. sas will not loop forever. Any suggestion to solve this problem?

Thanks,
Lu
Super Contributor
Posts: 647

Re: A macro question

I changed the variable name var1_suffix etc etc to suffix_1 for the convenience of array declaration.

data mydata;
input var1 suffix_1 var2 suffix_2 var3 suffix_3 var4 suffix_4 var5 suffix_5;
datalines;
4.2 1 1.8 0 2.3 0 3.5 0 2.3 1
3 0 2.5 0 5.2 1 6.4 0 2.4 0
3.1 0 6.7 0 5.1 1 3 0 4 0
;
run;


data mydata_v1;
set mydata;
array vari(*) var:;
array suffi(*) suffix:;
do i= 1 to dim(vari);
if suffi(i)=1 then vari(i)=.;
end;
run;
Contributor
Posts: 49

Re: A macro question

Thank you. Although it is not macro what I am looking for, I appreciated a lot.
Super Contributor
Posts: 647

Re: A macro question

By using colon(Smiley Happy in the array declaration you have the degree of freedom from not naming the variable list.if the variable list exceeds a certain number that will be pain the fingers to type them all.

Caveat:you should have the variable list sharing the same name with a number at the end.
Contributor
Posts: 49

Re: A macro question

Thank you. Although it is not macro what I am looking for, I appreciated a lot.
SAS Super FREQ
Posts: 8,743

Re: A macro question

Hi:
In your previous posting thread and in this posting thread several folks have posted non-macro solutions using ARRAYS. I agree with all the postings that show an ARRAY solution instead of a Macro solution. In this instance, given the data you describe and your stated purpose, using ARRAYS seems the best approach.

If you rejected those solutions because you did NOT want to to rename the variables for the ARRAY statement, as shown, then you could just list the variable names on the ARRAY statement. (although being able to list numbered variables is easier -- but the number should be at the end, unless you use the : wildcard). But anyway:
[pre]
data mydata;
input var1 var1_suffix var2 var2_suffix var3 var3_suffix var4 var4_suffix var5 var5_suffix;
datalines;
4.2 1 1.8 0 2.3 0 3.5 0 2.3 1
3 0 2.5 0 5.2 1 6.4 0 2.4 0
;
run;

data setmiss;
set mydata;
array v var1-var5;
array vs var1_suffix var2_suffix var3_suffix var4_suffix var5_suffix ;
do i = 1 to 5;
putlog 'BEFORE IF statement ' i= v(i)= vs(i)=;
if vs(i) = 1 then v(i)=.;
putlog 'AFTER IF statement ' i= v(i)= vs(i)=;
end;
run;

proc print data=setmiss;
title 'Making Change Using Arrays';
var var1 var1_suffix var2 var2_suffix var3 var3_suffix var4 var4_suffix var5 var5_suffix;
run;
[/pre]

Here's a good introduction to ARRAY processing:
http://www2.sas.com/proceedings/forum2007/273-2007.pdf

cynthia
Contributor
Posts: 49

Re: A macro question

Thank you very much. With no other choices I will use array statement. But I will still look if macro can do it since I think it is easier to change the string (var1 - var5 or var1_suffix - var2_suffix) in parameter in macro program rather than change it during the data step. Thanks again.

Lu
Respected Advisor
Posts: 3,777

Re: A macro question

Your macro was close. Here is a working version.

[pre]
%MACRO mymacro(varLIST);
%local K A;
DATA mydataout;
SET mydata;
%LET K=1;
%LET a=%SCAN(&varLIST,&K);
%DO %WHILE(%superQ(a) NE);
if &a._suffix=1 THEN &a=.;
%LET K=%EVAL(&K+1);
%LET a=%SCAN(&varLIST,&K);
%END;
RUN;
%MEND mymacro;
options mprint=1;
%mymacro(var1 var2 var3 var4 var5);
options mprint=0;
[/pre]
Contributor
Posts: 49

Re: A macro question

Hi,
Thank you very much. The code works perfectly.
I don't quite understand the code, could you tell me why you assign K and A to local variables. I took away the piece of code: "%local K A;" and it didn't affect the result. Another thing is what "%superQ(a)" does here? I tried to use "&a" instead but didn't work.Thanks again.
Respected Advisor
Posts: 3,777

Re: A macro question

It is always good to use %LOCAL for variables that are used exclusively within a macro. If you called this macro from another macro with variable K or A then your macro would use those variable and probably cause a problem. It makes it look like you know what you're doing.

%SUPERQ is "super quote" it keeps variable names like NE or AND from messing up your expression. There are other quoting functions, it is all very confusing for the first 10 or 15 years :-) The quote marks " and ' don't do quoting in macro language.

This guys knows everything about the subject.
http://www.lexjansen.com/sesug/2010/BB10.Whitlock.pdf
Contributor
Posts: 49

Re: A macro question

Thanks so much. I really appreciate it.
Respected Advisor
Posts: 3,777

Re: A macro question

Turn the problem around and use the SUFFIX varaibles to drive the code. Then you don't need to "touch" the VARS at all. Let the list of suffix vars make both lists.

[pre]
data mydata;
input var1 var1_suffix var2 var2_suffix var3 var3_suffix var4 var4_suffix var5 var5_suffix;
datalines;
4.2 1 1.8 0 2.3 0 3.5 0 2.3 1
3 0 2.5 0 5.2 1 6.4 0 2.4 0
3.1 0 6.7 0 5.1 1 3 0 4 0
;
run;

proc sql;
select
name,
substr(name,1,find(name,'_suffix',-length(name))-1)
into :list1 separated by ' ',
:list2 separated by ' '
from dictionary.columns
where libname eq 'WORK' and memname eq 'MYDATA'
and name like '%_suffix';
quit;
run;
%put NOTE: LIST1=&list1;
%put NOTE: LIST2=&list2;

data recode;
set mydata;
array s
  • &list1;
    array v
  • &list2;

    do _n_ = 1 to dim(s);
    if s[_n_] eq 1 then v[_n_]=.;
    end;
    run;

    proc print;
    run;
    [/pre]
  • Ask a Question
    Discussion stats
    • 13 replies
    • 237 views
    • 0 likes
    • 5 in conversation