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

I am attempting to make a macro function that creates macro variables holding the 99th percentile value of a variable. Here is a working example of the logic.

data test;
input var1 var2;
datalines;
1 2
2 4
3 6
4 8
5 10
6 12
7 14
8 16
9 18
;
run;


proc means data=test p99;
var var1 var2;
output out=sumt p99= / autoname;
run;

data sumt;
set sumt;
drop _TYPE_ _FREQ_;
run;

data _null_;
	set sumt;
	call symputx("var1_p99", var1_p99);
	call symputx('var2_p99', var2_p99);
run;
%put &var1_p99;
%put &var2_p99;

OUTPUT

 

167  data _null_;
168      set sumt;
169      call symputx("var1_p99", var1_p99);
170      call symputx('var2_p99', var2_p99);
171  run;

NOTE: There were 1 observations read from the data set WORK.SUMT.
NOTE: DATA statement used (Total process time):
      real time           0.01 seconds
      cpu time            0.00 seconds


172  %put &var1_p99;
9
173  %put &var2_p99;
18

 

The problem is when I try to write the macro.

 

%macro p99(dsn);
	%let dsid=%sysfunc(open(&dsn));
	%let n=%sysfunc(attrn(&dsid,nvars));
	data _null_;
		set &dsn;
		%do i=1 %to &n;
			%let var=%sysfunc(varname(&dsid,&i));
			call symputx("&var",&var);
		%end;
	run;
	%do i=1 %to &n;
		%let var=%sysfunc(varname(&dsid,&i));
		%put &&var;
	%end;
	%let rc=%sysfunc(close(&dsid));
%mend p99;

%p99(sumt);

%put &var1_p99;

OUTPUT

146  %macro p99(dsn);
147      %let dsid=%sysfunc(open(&dsn));
148      %let n=%sysfunc(attrn(&dsid,nvars));
149      data _null_;
150          set &dsn;
151          %do i=1 %to &n;
152              %let var=%sysfunc(varname(&dsid,&i));
153              call symputx("&var",&var);
154          %end;
155      run;
156      %do i=1 %to &n;
157          %let var=%sysfunc(varname(&dsid,&i));
158          %put &&var;
159      %end;
160      %let rc=%sysfunc(close(&dsid));
161  %mend p99;
162
163  %p99(sumt);

NOTE: There were 1 observations read from the data set WORK.SUMT.
NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds


var1_P99
var2_P99
WARNING: Apparent symbolic reference VAR1_P99 not resolved.

I'd like it if someone could explain why the macro function won't write the values with SYMPUTX and then point out the correction.

 

Thanks.

 

1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

If I understand the question you want to take this code:

data _null_;
	set sumt;
	call symputx("var1_p99", var1_p99);
	call symputx('var2_p99', var2_p99);
run;

And turn it into a macro where the name of the input dataset is passed as a parameter.

%macro p99(dsn);
data _null_;
	set &dsn;
	call symputx("var1_p99", var1_p99);
	call symputx('var2_p99', var2_p99);
run;
%mend p99;

Since the CALL SYMPUTX() statements are now running in macro by default the macro variable VAR1_P99 will be local to the macro and so disappear. You could just use the third argument to CALL SYMPUTX() to force them to be made as global. 

call symputx('var2_p99', var2_p99,'g');

Or you could make the macro a little more dynamic and only make them global if they do not already exist.  Then you could call this macro from inside another macro that has already defined those macro variables in its local macro space.

%macro p99(dsn);
%if not %symexist(var1_p99) %then %global var1_p99;
%if not %symexist(var2_p99) %then %global var2_p99;
data _null_;
	set &dsn;
	call symputx("var1_p99", var1_p99);
	call symputx('var2_p99', var2_p99);
run;
%mend p99;

View solution in original post

8 REPLIES 8
PeterClemmensen
Tourmaline | Level 20

First, why do you want a macro to do what you can already do without it?

Tom
Super User Tom
Super User

If I understand the question you want to take this code:

data _null_;
	set sumt;
	call symputx("var1_p99", var1_p99);
	call symputx('var2_p99', var2_p99);
run;

And turn it into a macro where the name of the input dataset is passed as a parameter.

%macro p99(dsn);
data _null_;
	set &dsn;
	call symputx("var1_p99", var1_p99);
	call symputx('var2_p99', var2_p99);
run;
%mend p99;

Since the CALL SYMPUTX() statements are now running in macro by default the macro variable VAR1_P99 will be local to the macro and so disappear. You could just use the third argument to CALL SYMPUTX() to force them to be made as global. 

call symputx('var2_p99', var2_p99,'g');

Or you could make the macro a little more dynamic and only make them global if they do not already exist.  Then you could call this macro from inside another macro that has already defined those macro variables in its local macro space.

%macro p99(dsn);
%if not %symexist(var1_p99) %then %global var1_p99;
%if not %symexist(var2_p99) %then %global var2_p99;
data _null_;
	set &dsn;
	call symputx("var1_p99", var1_p99);
	call symputx('var2_p99', var2_p99);
run;
%mend p99;
Astounding
PROC Star

I would guess your problem lies here:

 

%let var=%sysfunc(varname(&dsid,&i));

 

You are interested in numeric variables only.  But VARNAME (and &i) applies to all variables, not just the numeric ones.

 

It might be easier to begin by extracting one long macro variable holding the names of all numeric variables in the data set.

Tom
Super User Tom
Super User

Why do you need a macro? 

Before you start writing macro code first get the SAS code set.

If you want to generate every variable in a dataset into macro variable there is no need for macro code.

proc means data=test p99;
  var var1 var2;
  output out=sumt(drop=_type_ _freq_) p99= / autoname;
run;

data _null_;
  set sumt;
  array _n _numeric_;
  do i=1 to dim(_n);
    call symputx(vname(_n(i)),n(i));
  end;
run;

 

publicSynechism
Fluorite | Level 6

I don't know SAS well, so after finding percentiles for a certain variable, I would type in the value by hand to subset the data. And I was doing this every time I updated the dataset. I wanted code that allows me to call a macro holding the percentile value regardless of the data I'm using.

I'm not sure I understand you're second suggestion. The log returns the symbolic reference not resolved warning when I call the macro associated with a particular variable.

Thanks for you help.

Tom
Super User Tom
Super User

If the goal is to use the value of the variable in calculations then you will get better precision by leaving it the data and not using either the manual copy/paste or the macro version of that.

For example here is a little program to calculate the 99th percentile for a set of variables and then use those values to flag observations where the value is greater than that 99th percentile.

%let indsn=have;
%let varlist=var1 var2;
%let outdsn=want;

proc summary data=&indsn ;
  var  &varlist ;
  output out=percentiles(drop=_type_ _freq_)  p99= /autoname ;
run;

data &outdsn ;
  set &indsn ;
  if _n_ =1 then set precentiles;
  array x &varlist;
  array p %sysfunc(tranwrd(&varlist%str( ),%str( ),%str(_p99 )));
  array f %sysfunc(tranwrd(&varlist%str( ),%str( ),%str(_flag )));

  do i=1 to dim(x);
     f(i) = ( x(i) > p(i) );
  end;
run;
publicSynechism
Fluorite | Level 6

Thanks Tom. This is excellent, but I need to tweak it. It stops prematurely and gives null values for the remaining selected variables if I don't use all the variables in the dataset for &varlist. 

Tom
Super User Tom
Super User

@publicSynechism wrote:

Thanks Tom. This is excellent, but I need to tweak it. It stops prematurely and gives null values for the remaining selected variables if I don't use all the variables in the dataset for &varlist. 


Post the SAS log. Make sure to use the Insert Code icon so that the forum editor doesn't corrupt the text.

Even better would be to post a small sample dataset (in the form or a data step) that everyone on the forum can use to recreate your issue.

SAS Innovate 2025: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 8 replies
  • 1849 views
  • 0 likes
  • 4 in conversation