Hello,
I am attempting to calculate participants' cardiovascular risk using a macro I found in a published paper. It requires common variables like blood pressure, age, sex, etc .
The macro works when I call it and reference specific values for each variable, as shown below. However, I would like to use it to calculate the risk score for thousands of participants (and not have to do each by hand) and eventually have it exported to a new dataset (still working on this also).
Is there any way to transform it from requiring values to referencing variables? I tried using %let and removing the = in the macro line, but neither were successful ("ERROR: Variable age is uninitialized")
Thanks in advance!
%MACRO PCE_RISK(AGE=, SEX=, TCHOL=, HDL=, SBP=, HTN=, SMK=, DIA=);
DATA RISK;
SCORE = (&SEX=0)*( -29.799*LOG(&AGE) +4.884*(LOG(&AGE)**2)
+13.540*LOG(&TCHOL) -3.114*LOG(&AGE)*LOG(&TCHOL)
-13.578*LOG(&HDL) +3.149*LOG(&AGE)*LOG(&HDL)
+(2.019*(&HTN=1)+1.957*(&HTN=0))*LOG(&SBP)
+7.574*(&SMK=1)-1.665*LOG(&AGE)*(&SMK=1)
+0.661*(&DIA=1))+
(&SEX=1)*( +12.344*LOG(&AGE)+ 0*(LOG(&AGE)**2)
+11.853*LOG(&TCHOL)-2.664*LOG(&AGE)*LOG(&TCHOL)
-7.990*LOG(&HDL)+1.769*LOG(&AGE)*LOG(&HDL)
+(1.797*(&HTN=1)+1.764*(&HTN=0))*LOG(&SBP)
+7.837*(&SMK=1)-1.795*LOG(&AGE)*(&SMK=1)
+0.658*(&DIA=1));
RISK = 100*(1 - (&SEX=0)*(0.96652**EXP(SCORE+29.1817)) - (&SEX=1)*(0.91436**EXP(SCORE-61.1816)) );
RUN;
PROC PRINT DATA=RISKWHITE; RUN; %MEND;
%PCE_RISK(AGE=55, SEX=0, TCHOL=200, HDL=60, SBP=130, HTN=1, SMK=0, DIA=1); run;
If you have a data set with the variables holding the values to be used in that Score code then you could modify the code to something like the following code block.
Where DSIN would be the name of your source data set. Then each observation would be scored.
Personally I wouldn't automatically include proc print with a data set unless you really think you need to print that much stuff. Then place the names of your variables that hold the appropriate values instead of a litteral number. Those variables have to be in the correct units, values and numeric to be reliable with code like this.
%MACRO PCE_RISK(DSIN= ,AGE=, SEX=, TCHOL=, HDL=, SBP=, HTN=, SMK=, DIA=); DATA RISK; set &dsin. ; SCORE = (&SEX=0)*( -29.799*LOG(&AGE) +4.884*(LOG(&AGE)**2) +13.540*LOG(&TCHOL) -3.114*LOG(&AGE)*LOG(&TCHOL) -13.578*LOG(&HDL) +3.149*LOG(&AGE)*LOG(&HDL) +(2.019*(&HTN=1)+1.957*(&HTN=0))*LOG(&SBP) +7.574*(&SMK=1)-1.665*LOG(&AGE)*(&SMK=1) +0.661*(&DIA=1))+ (&SEX=1)*( +12.344*LOG(&AGE)+ 0*(LOG(&AGE)**2) +11.853*LOG(&TCHOL)-2.664*LOG(&AGE)*LOG(&TCHOL) -7.990*LOG(&HDL)+1.769*LOG(&AGE)*LOG(&HDL) +(1.797*(&HTN=1)+1.764*(&HTN=0))*LOG(&SBP) +7.837*(&SMK=1)-1.795*LOG(&AGE)*(&SMK=1) +0.658*(&DIA=1)); RISK = 100*(1 - (&SEX=0)*(0.96652**EXP(SCORE+29.1817)) - (&SEX=1)*(0.91436**EXP(SCORE-61.1816)) ); RUN; PROC PRINT DATA=RISKWHITE; RUN; %MEND;
And the call would look like:
%PCE_RISK(DSIN=mylib.somedataset, AGE=agevariablename, SEX=sexvar, TCHOL=tcholvar, HDL=hdlvar, SBP=sbpvar, HTN=htnvar, SMK=smkvar, DIA=diavar); run;
I would be temped to make the output data set name optional as well.
If you have all of these variables in a SAS data set, with the same names as the macro variables, just turn macro variables into data step variables in the code.
DATA RISK;
set your_data_set_name;
SCORE = (SEX=0)*( -29.799*LOG(AGE) +4.884*(LOG(AGE)**2)
+13.540*LOG(TCHOL) -3.114*LOG(AGE)*LOG(TCHOL) ...
/* and so on, you do the rest */
; /* don't forget the semi-colon! */
RISK = 100*(1 - (SEX=0)*(0.96652**EXP(SCORE+29.1817)) - (SEX=1)*(0.91436**EXP(SCORE-61.1816)) );
RUN;
If you have a data set with the variables holding the values to be used in that Score code then you could modify the code to something like the following code block.
Where DSIN would be the name of your source data set. Then each observation would be scored.
Personally I wouldn't automatically include proc print with a data set unless you really think you need to print that much stuff. Then place the names of your variables that hold the appropriate values instead of a litteral number. Those variables have to be in the correct units, values and numeric to be reliable with code like this.
%MACRO PCE_RISK(DSIN= ,AGE=, SEX=, TCHOL=, HDL=, SBP=, HTN=, SMK=, DIA=); DATA RISK; set &dsin. ; SCORE = (&SEX=0)*( -29.799*LOG(&AGE) +4.884*(LOG(&AGE)**2) +13.540*LOG(&TCHOL) -3.114*LOG(&AGE)*LOG(&TCHOL) -13.578*LOG(&HDL) +3.149*LOG(&AGE)*LOG(&HDL) +(2.019*(&HTN=1)+1.957*(&HTN=0))*LOG(&SBP) +7.574*(&SMK=1)-1.665*LOG(&AGE)*(&SMK=1) +0.661*(&DIA=1))+ (&SEX=1)*( +12.344*LOG(&AGE)+ 0*(LOG(&AGE)**2) +11.853*LOG(&TCHOL)-2.664*LOG(&AGE)*LOG(&TCHOL) -7.990*LOG(&HDL)+1.769*LOG(&AGE)*LOG(&HDL) +(1.797*(&HTN=1)+1.764*(&HTN=0))*LOG(&SBP) +7.837*(&SMK=1)-1.795*LOG(&AGE)*(&SMK=1) +0.658*(&DIA=1)); RISK = 100*(1 - (&SEX=0)*(0.96652**EXP(SCORE+29.1817)) - (&SEX=1)*(0.91436**EXP(SCORE-61.1816)) ); RUN; PROC PRINT DATA=RISKWHITE; RUN; %MEND;
And the call would look like:
%PCE_RISK(DSIN=mylib.somedataset, AGE=agevariablename, SEX=sexvar, TCHOL=tcholvar, HDL=hdlvar, SBP=sbpvar, HTN=htnvar, SMK=smkvar, DIA=diavar); run;
I would be temped to make the output data set name optional as well.
Thank you so much! This worked perfectly!
One of the advantages of Keword parameters to a macro, those defined like your Age=, is that you can provide a default value in the definition. So if you are likely to have a variable named Age in your data set you could define the macro with that default value for the parameter. Then if your data set has Age, or what ever you set as the default variable name, in the data set you don't need to pass it as a parameter.
This can be handy if you know you are going to process multiple data sets with mostly the same variables.
Then you only need to provide the variable name as a parameter when that particular data set uses a different name.
Thank you! I'm still very new to macros. This explanation is very appreciated.
Join us for SAS Innovate 2025, our biggest and most exciting global event of the year, in Orlando, FL, from May 6-9. Sign up by March 14 for just $795.
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.