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

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; 

 

1 ACCEPTED SOLUTION

Accepted Solutions
ballardw
Super User

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.

 

 

 

View solution in original post

5 REPLIES 5
PaigeMiller
Diamond | Level 26

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
ballardw
Super User

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.

 

 

 

sophiec
Obsidian | Level 7

Thank you so much! This worked perfectly! 

ballardw
Super User

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.

sophiec
Obsidian | Level 7

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

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

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
  • 486 views
  • 2 likes
  • 3 in conversation