☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
Obsidian | Level 7

## Convert macro from requiring values to using variables to calculate a risk score

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")

``````%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;
``````

1 ACCEPTED SOLUTION

Accepted Solutions
Super User

## Re: Convert macro from requiring values to using variables to calculate a risk score

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.

5 REPLIES 5
Diamond | Level 26

## Re: Convert macro from requiring values to using variables to calculate a risk score

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;  ``````
--
Paige Miller
Super User

## Re: Convert macro from requiring values to using variables to calculate a risk score

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.

Obsidian | Level 7

## Re: Convert macro from requiring values to using variables to calculate a risk score

Thank you so much! This worked perfectly!

Super User

## Re: Convert macro from requiring values to using variables to calculate a risk score

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.

Obsidian | Level 7

## Re: Convert macro from requiring values to using variables to calculate a risk score

Thank you! I'm still very new to macros. This explanation is very appreciated.

Discussion stats
• 5 replies
• 600 views
• 2 likes
• 3 in conversation