BookmarkSubscribeRSS Feed
WimB
Fluorite | Level 6

Hey all,

 

I've been trying to write a macro function which return a value based on the input rating value (1 to 23);

 

The goal is to use the output of this function to create a new variable in the table containing the rating scores.

 

 

 

It seems every method I try failed in someway

 

1 Direct call 

 

%macro(cs_factor);

[...]

&output.

%mend;

 

data test;
do cs = 1 to 23;
 cs_score = %cs_factor(cs);
 output;
end;
run;

 

This doesn't resolve because it keeps executing %cs_factor(cs) with cs as a macro variable instead of the value of the variable cs.

It does return values, but they're all equal to 0 due to error handling below which is supposed to be TRUE;

 

SYMBOLGEN: Macro variable CS resolves to cs
SYMBOLGEN: Macro variable MAX_CS resolves to 23
MLOGIC(CS_SCORING): %IF condition %sysevalf(&cs. le &max_cs.) is FALSE

 

2 Call Execute

 

%macro(cs_factor);

[...]

cs_factor=&output.;

%mend;

 

data test;
length cs cs_score 8.;
do cs = 1 to 23;
call execute('%cs_scoring('||cs||')');
output;
end;
run;

 

  • This doesn't give me the expected table of variable cs (1 to 23) and cs_factor either, but generated this error for all 23 iterations;

 

1 + cs_factor=1;
_________
180

ERROR 180-322: Statement is not valid or it is used out of proper order.

NOTE: Line generated by the CALL EXECUTE routine.
2 + cs_factor=0.99999882161769;
_________
180

ERROR 180-322: Statement is not valid or it is used out of proper order.

 

  • if I remove the semicolon from the macro definition (see blue ;) I get the error only once. 

 

1 + cs_factor=1
_________
180
ERROR 180-322: Statement is not valid or it is used out of proper order.

2 + cs_factor=0.99999882161769
3 + cs_factor=0.99999080089355
4 + cs_factor=0.99996111096086
5 + cs_factor=0.99988122640202

 

So, how do I call that macro like I would a general function? I can't use call execute to the right of an equation either like "cs_factor = call execute('%cs_scoring('||cs||')') " so I'm a bit at a loss. The value I get out of it is correct, I just don't know how to get that value imputed into a data step call.

 

Leaving office now so replies come tomorrow. 

Thanks in advance!

5 REPLIES 5
error_prone
Barite | Level 11
Try proc fcmp instead of a macro.
RW9
Diamond | Level 26 RW9
Diamond | Level 26

Really?  Hiding the code in a compiled catalog is going to improve things?

 

Kurt_Bremser
Super User

The macro preprocessor is just an advanced text replacement system built to aid you in writing dynamic and/or repeating code.

It does NOT (that's why I emphasized "pre") have access to the values of data step variables, only to their names (because you supplied them).

%cs_factor(cs) means that the macro will only see the text "cs" (without the quotes, of course) when it executes.

If you want to create a "function style" macro, it must NOT return a value, but code which then runs in the data (or procedure) step and does what you want.

 

  1. create working SAS code
  2. identify parts that need to be made dynamic
  3. replace those with macro variables
  4. manually set macro variables an test
  5. if OK, wrap into a macro and set the macro variables from 3. as parameters

So you first have to show us what you want to do in the place of the future macro, in Base SAS code.

s_lassen
Meteorite | Level 14

Others have suggested that you use PROC FCMP, which is not a bad idea if your code is that complicated. But you can also do it as a function-style macro, if you are trying something relatively simple, e.g.:

%macro CS_factor(index);
ChooseN(&index,
1,
0.99999882161769,
0.99999882161769,
0.99999080089355,
0.99996111096086,
0.99988122640202,
.... rest of values go here
)
%mend;

data test;
  do cs=1 to 23;
    cs_score=%cs_factor(cs);
    output;
    end;
run; 

Note that I did not put a final semicolon in the expression inside the macro; that way, the macro can be used just as you would use a normal function call, e.g. "CS_plustwo=%cs_factor(cs)+2;".

 

Note that the CHOOSEN function truncates the index value, and reports an error if the index is out of range. Which may be OK with you, else you may have to modify the function call, e.g.:

%macro CS_factor(index);
ChooseN(ifn(1<=&index<=23,&index,24),
1,
0.99999882161769,
0.99999882161769,
0.99999080089355,
0.99996111096086,
0.99988122640202,
.... rest of values go here
. /* missing value for index out of range */
)
%mend;

 

Astounding
PROC Star

If I understand properly, you are overcomplicating the problem.  It seems you have a separate table with 23 observations, and want to retrieve a value from that table based on a number going from 1 to 23.  For that:

 

data want;

do k=1 to 23;

   set other_table point=k;

   output;

end;

stop;

run;

 

The STOP statement is important for this example, preventing an infinite loop in the DATA step.  It may be OK to remove it in a more complex DATA step that has a guaranteed ending.

 

There are other approaches possible as well, such as reading the other table into a temporary array:

 

data want;

array factors {k} _temporary_;

if _n_=1 then do k=1 to 23;

   set other_table;

   factors{k} = cs_factor;

end;

set have;

.... retrieve values from the _temporary_ array as needed ....

run;

sas-innovate-2024.png

Don't miss out on SAS Innovate - Register now for the FREE Livestream!

Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.

 

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
  • 5 replies
  • 780 views
  • 3 likes
  • 6 in conversation