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;
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.
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!
Really? Hiding the code in a compiled catalog is going to improve things?
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.
So you first have to show us what you want to do in the place of the future macro, in Base SAS code.
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;
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;
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
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.