I'm fairly new to the SAS macro facility, and try to write a code that sorts variable X into quantiles.
I cannot use PROC RANK because the quantiles may not always be of identical size. So I use PROC UNIVARIATE with the option "pctlpts = &startperc1 to &endperc1 by &stepperc1 pctlpre=pf1_" to generate quantiles p1_20, ..., p1_60:
To present you my problem, I converted my macro-code into open code by deleting the "%" in front of %do, %while, and %end. I define:
%let startperc1=20;
%let endperc1=60;
%let stepperc1=20;
%let sortingvar1=X;
The code I have now is:
%let nowperc=%eval(&startperc1);
%let prevperc=%eval(&startperc1-&nowperc);
data newdata;
set data;
pf1_0 = 0;
do while (%eval(&nowperc) lt %eval(&endperc1));
if &sortingvar1>=pf1_&prevperc AND &sortingvar1<pf1_&nowperc then rank = %eval(( &nowperc - &startperc1 ) / &stepperc1 +1);
%let nowperc = %eval(&nowperc + &stepperc1);
%let prevperc = %eval(&prevperc + &stepperc1);
end;
run;
This code looks extremely easy to me, and should work.... But is doesn't. Please help?
For the sake of discussion, I have generated the following fictitious data:
DATA data;
INPUT President $ Party $ X pf1_20 pf1_40 pf1_60;
DATALINES;
Adams F 2 10 20 30 40
Lincoln R 16 10 20 30 40
Grant R 18 10 20 30 40
Kennedy D 35 10 20 30 40
Adams F 4 10 20 30 40
Lincoln R 17 10 20 30 40
Grant R 22 10 20 30 40
Kennedy D 35 10 20 30 40
Adams F 8 10 20 30 40
Lincoln R 11 10 20 30 40
Grant R 19 10 20 30 40
Kennedy D 40 10 20 30 40
;
RUN;
Maybe you want %DO %WHILE.
If you don't then you have data step and macro all mixed up.
Maybe you want %DO %WHILE.
If you don't then you have data step and macro all mixed up.
The root of the issue is that macro references are resolved once before the DATA step is compiled.
Your code attempts to change the variables referenced by changing the values of the macro variables.
This demonstrates the general idea of what I am attempting to describe. The SAS code runs without syntax errors, but there are no guarantees that it is correct. I will leave that to your expertise.
/* test1.sas */
DATA data;
INPUT President $ Party $ X pf1_20 pf1_40 pf1_60;
DATALINES;
Adams F 2 10 20 30 40
Lincoln R 16 10 20 30 40
Grant R 18 10 20 30 40
Kennedy D 35 10 20 30 40
Adams F 4 10 20 30 40
Lincoln R 17 10 20 30 40
Grant R 22 10 20 30 40
Kennedy D 35 10 20 30 40
Adams F 8 10 20 30 40
Lincoln R 11 10 20 30 40
Grant R 19 10 20 30 40
Kennedy D 40 10 20 30 40
;
RUN;
%let startperc1=20;
%let endperc1=60;
%let stepperc1=20;
%let sortingvar1=X;
%let nowperc=%eval(&startperc1);
%let prevperc=%eval(&startperc1-&nowperc);
data newdata;
set data;
nowprec = &nowperc;
prevperc = &prevperc;
array pf1 (*) pf1_0 pf1_20 pf1_40 pf1_60;
pf1_0 = 0;
pnt = 1; /* pointer for pf1 array */
do while (nowperc lt &endperc1);
if &sortingvar1>=pf1(pnt) AND &sortingvar1<pf1(pnt + 1) then
rank = (nowperc - &startperc1 ) / ( &stepperc1 +1);
nowperc + &stepperc1;
prevperc + &stepperc1;
pnt + 1;
end;
drop pnt pf1_0;
run;
Cheers,
Jan
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
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.