Hi everyone,
I'd like to create a function where I assign a value depending on the parameters of the function as such:
proc fcmp outlib=mydata.functions.func;
function Lx(Age,Sex);
Lx(1,1)=100;
Lx(2,1)=99;
Lx(3,1)=97;
/*
.
.
.
*/
Lx(1,2)=99;
Lx(2,2)=95;
Lx(3,2)=82;
/*
.
.
.
*/
return(Lx);
endsub;
Unfortunately it doesn't work at all 😁.
I can use "If then Statement " to achieve what I want like shown below, but I would like to learn a different way to get it.
proc fcmp outlib=mydata.functions.func;
function Lx(Age,Sex);
if sex=1 then
do;
if age = 1 then
Lx=100;
else if age=2 then
Lx=99;
else if age=3 then
Lx=97;
/*
.
.
.
*/
end;
else if sex=2 then
do;
if age = 1 then
Lx=99;
else if age=2 then
Lx=95;
else if age=3 then
Lx=82;
/*
.
.
.
*/
end;
return(Lx);
endsub;
If someone has any clue on how to achieve this , it'd be awesome to share the solution.
Thank u all
So, there is no formula for the return value in terms of Age and Sex? You have a table of values for
Sex=1, 2
and for
Age=1,2,3?
In that case, define an array in the PROC FCMP function and look up the value you want:
proc fcmp outlib=work.funcs.TestFuncs;
function Lx(Age,Sex);
array f[3,2] (100 99 87
99 95 82);
if (0 < Age <= 3) and (0 < Sex <= 2) then
return( f[Age, Sex] );
else
return( . );
endsub;
quit;
options cmplib=work.funcs; /* define location of function */
data Want;
do Age = 1 to 3;
do Sex=1 to 2;
y = Lx(Age, Sex);
output;
end;
end;
run;
proc print; run;
So, there is no formula for the return value in terms of Age and Sex? You have a table of values for
Sex=1, 2
and for
Age=1,2,3?
In that case, define an array in the PROC FCMP function and look up the value you want:
proc fcmp outlib=work.funcs.TestFuncs;
function Lx(Age,Sex);
array f[3,2] (100 99 87
99 95 82);
if (0 < Age <= 3) and (0 < Sex <= 2) then
return( f[Age, Sex] );
else
return( . );
endsub;
quit;
options cmplib=work.funcs; /* define location of function */
data Want;
do Age = 1 to 3;
do Sex=1 to 2;
y = Lx(Age, Sex);
output;
end;
end;
run;
proc print; run;
Thank u very much for the quick solution.
This is exactly what I need. It does the job perfectly.
I have a dataset with the age and the sex for each person. Sex can only have 2 values, either 1=Man or 2=Women.
The Lx correspond to the values of a mortality table from age 1 to age 120.
Do u have any support to recommend for array. I didn't know it was possible to have multiple argument when using array.
I just have a general question regarding this kind of array. Is it possible to replace parameter 3 by an asterisk in case I don't want count the number of output?
proc fcmp outlib=work.funcs.TestFuncs;
function Lx(Age,Sex);
array f[*,2] (100 99 87
99 95 82);
if (0 < Age <= 3) and (0 < Sex <= 2) then
return( f[Age, Sex] );
else
return( . );
endsub;
quit;
@adil256 wrote:
I just have a general question regarding this kind of array. Is it possible to replace parameter 3 by an asterisk in case I don't want count the number of output?
array f[*,2] (100 99 87 99 95 82);
No, the asterisk is not allowed in the definition of two-dimensional arrays.
@adil256 wrote:
I just don't understand why the parameters are reversed in your array [2,3] instead of [3,2] from Rick_Sas.
Maybe the order is not important in my case.
Note that the order of initial values depends on your "style choice" between a 2×3 array (sex,age) and a 3×2 array (age,sex). You must use "row-major order" (see documentation).
With the example values from your initial post your choices are:
array a[2,3] (100 99 97 99 95 82); array b[3,2] (100 99 99 95 97 82);
You may write either of these in tabular form (ideally reflecting the array dimensions) for better readability, ...
array a[2,3] (100 99 97 99 95 82); array b[3,2] (100 99 99 95 97 82);
... but the compiler ignores these fancy arrangements and only demands row-major order.
And since the SAS compiler does not care if you use space or commas or both in delimiting the list you can use:
array a[2,3] (100 99 97,99 95 82); array b[3,2] (100 99,99 95,97 82);
to make is clearer to humans what is happening.
Your boundary checks can be done easier and more precisely by using IN operator.
if age in (1:3) and sex in (1:2) then
Now non-integer values of AGE like 2.5 will be trapped.
Your first FCMP doesn't work because you aren't assigning values to LX unless you expect to pass an array back as a value (or maybe an element of an array).
This may be what you are looking for. I used a different function name and library so there isn't confusion with yours while testing.
proc fcmp outlib=sasuser.funcs.trial;; function lukup (age,sex); /* this array ONLY uses sex=1 and 2 with ages= 1, 2 and 3 the two rows of values are for easy alignment age=4 would be the 4th value in each row age=5 would be the 5th value in each row repeat as needed */ array s_a[2,3] (100 99 97 99 95 87 ); lx = s_a[sex,age]; return (lx); endsub; run; options cmplib=sasuser.funcs; data example; do sex =1,2; do age= 1 to 3; result=lukup(age,sex); output; end; end; run;
If you have more values for sex or age then the ARRAY definition would need to have the numbers in the (2,3) updated to match the number of sex and age values. Additional sex values would require more rows. IF you have gaps in the numbers of values, such as you need an age=7 but don't have an age=6 value then place a . (missing) in the corresponding place in the row.
Thank u too for ur solution. It's very similar to Rick_Sas's solution.
I just don't understand why the parameters are reversed in your array [2,3] instead of [3,2] from Rick_Sas.
Maybe the order is not important in my case.
Yeah basically I need to lookup the value but I also need to perform calculations with iteration depending on the Age. That's why the merge is not possible for what I want to do I think.
I intended to do it manually but if there is a way to do it automatically. I'll change my mind :).
Let's say I have a dataset with 1 person with age=20 and a mortality table with value from age 20 to 22 for each sex.
I want to calculate the probability of death for each age. To do so,i need to compute the following formula : qx=(Lx[i,Sex]-Lx[i+1,Sex])/Lx[i,Sex];
Data have;
ID=1;
Age=20;
Sex=1;
run;
Data T_Mortality;
retain Age 20;
do Lx=100 to 97 by-1;
Sex=1;
output;
Age=Age+1;
end;
Age=20;
do Lx=99 to 96 by-1;
Sex=2;
output;
Age=Age+1;
end;
run;
Data want;
set have;
Do i=Age to 22;
qx=(Lx[i,Sex]-Lx[i+1,Sex])/Lx[i,Sex];
output;
end;
run;
With the following information, how can I use a merge to perform the calculation?
Normally, with your FCMP function, I can perform the calculation. I'll just need to write the Lx value manually which is kind of annoying but it'll work.
Thx for ur help.
Data have;
ID=1;
Age=20;
Sex=1;
do age = age to 22;
output;
end;
run;
Data T_Mortality;
retain Age 20;
do Lx=100 to 97 by-1;
Sex=1;
output;
Age=Age+1;
end;
Age=20;
do Lx=99 to 96 by-1;
Sex=2;
output;
Age=Age+1;
end;
run;
proc sql;
create table want as
select t1.ID, t1.Age, t1.Sex, mort1.lx as lx_age, mort2.lx as lx_age_1, (mort1.lx - mort2.lx)/mort1.lx as qx
from have as t1
left join t_mortality as mort1
on mort1.age=t1.age
and mort1.sex=t1.sex
left join t_mortality as mort2
on mort2.age = t1.age+1
and mort2.sex = t1.sex;
quit;
@adil256 wrote:
I intended to do it manually but if there is a way to do it automatically. I'll change my mind :).
Let's say I have a dataset with 1 person with age=20 and a mortality table with value from age 20 to 22 for each sex.
I want to calculate the probability of death for each age. To do so,i need to compute the following formula :
qx=(Lx[i,Sex]-Lx[i+1,Sex])/Lx[i,Sex];
Data have; ID=1; Age=20; Sex=1; run; Data T_Mortality; retain Age 20; do Lx=100 to 97 by-1; Sex=1; output; Age=Age+1; end; Age=20; do Lx=99 to 96 by-1; Sex=2; output; Age=Age+1; end; run; Data want; set have; Do i=Age to 22; qx=(Lx[i,Sex]-Lx[i+1,Sex])/Lx[i,Sex]; output; end; run;
With the following information, how can I use a merge to perform the calculation?
Normally, with your FCMP function, I can perform the calculation. I'll just need to write the Lx value manually which is kind of annoying but it'll work.
Thx for ur help.
@adil256 wrote:
Thank u too for ur solution. It's very similar to Rick_Sas's solution.
I just don't understand why the parameters are reversed in your array [2,3] instead of [3,2] from Rick_Sas.
Maybe the order is not important in my case.
Yeah basically I need to lookup the value but I also need to perform calculations with iteration depending on the Age. That's why the merge is not possible for what I want to do I think.
Style choice for which variable is the "row" and which is the "column" position. No technical or practical difference.
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.