BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
axescot78
Quartz | Level 8

Hello,

 

Beginning SAS student here. I created a table with 49 rows, columns are 2 means and 2 stds. I need to add a column which refers to a macro that calculates CohensD based on the rows of data. I can't for the life of me figure it out!

1 ACCEPTED SOLUTION

Accepted Solutions
axescot78
Quartz | Level 8

I figured this out. If anyone is interested, here is the correct code and output:

 

Capture.PNG

 

%macro CohensD(m_1,m_2,s_1,s_2);
  %let x = (abs(&m_1-&m_2))/(sqrt((&s_1**2 + &s_2**2)/2));
  &x;
%mend CohensD;

proc iml;
 
Year = {1936, 1946, 1951, 1963, 1975, 1997, 2006};
x = nrow(Year);

Year1 = repeat(Year,x,1);
Year2 = repeat(Year[1],x,1) // repeat(Year[2],x,1) // repeat(Year[3],x,1) // repeat(Year[4],x,1) // repeat(Year[5],x,1) // repeat(Year[6],x,1) // repeat(Year[7],x,1);

CaloriesPerRecipeMean = {2123.8, 2122.3, 2089.9, 2250.0, 2234.2, 2249.6, 3051.9};
Mean1 = repeat(CaloriesPerRecipeMean,x,1);
Mean2 = repeat(CaloriesPerRecipeMean[1],x,1) // repeat(CaloriesPerRecipeMean[2],x,1) // repeat(CaloriesPerRecipeMean[3],x,1) // repeat(CaloriesPerRecipeMean[4],x,1) // repeat(CaloriesPerRecipeMean[5],x,1) // repeat(CaloriesPerRecipeMean[6],x,1) // repeat(CaloriesPerRecipeMean[7],x,1);

CaloriesPerRecipeSD = {1050.0, 1002.3, 1009.6, 1078.6, 1089.2, 1094.8, 1496.2};
SD1 = repeat(CaloriesPerRecipeSD,x,1);
SD2 = repeat(CaloriesPerRecipeSD[1],x,1) // repeat(CaloriesPerRecipeSD[2],x,1) // repeat(CaloriesPerRecipeSD[3],x,1) // repeat(CaloriesPerRecipeSD[4],x,1) // repeat(CaloriesPerRecipeSD[5],x,1) // repeat(CaloriesPerRecipeSD[6],x,1) // repeat(CaloriesPerRecipeSD[7],x,1);

create CookingTooMuch var {Year1, Year2, Mean1, Mean2, SD1, SD2};
append;
close CookingTooMuch;

quit;
proc print data=CookingTooMuch;
run;

data CookingTooMuch2;
   set CookingTooMuch;
   CohensD=%CohensD(Mean1,Mean2,SD1,SD2);
run;
                  
proc print data=CookingTooMuch2;
run;

View solution in original post

13 REPLIES 13
Community_Guide
SAS Moderator

Hello @axescot78,


Your question requires more details before experts can help. Can you revise your question to include more information? 

 

Review this checklist:

  • Specify a meaningful subject line for your topic.  Avoid generic subjects like "need help," "SAS query," or "urgent."
  • When appropriate, provide sample data in text or DATA step format.  See this article for one method you can use.
  • If you're encountering an error in SAS, include the SAS log or a screenshot of the error condition. Use the Photos button to include the image in your message.
    use_buttons.png
  • It also helps to include an example (table or picture) of the result that you're trying to achieve.

To edit your original message, select the "blue gear" icon at the top of the message and select Edit Message.  From there you can adjust the title and add more details to the body of the message.  Or, simply reply to this message with any additional information you can supply.

 

edit_post.png

SAS experts are eager to help -- help them by providing as much detail as you can.

 

This prewritten response was triggered for you by fellow SAS Support Communities member @Kurt_Bremser

.
RW9
Diamond | Level 26 RW9
Diamond | Level 26

"I need to add a column which refers to a macro that calculates CohensD based on the rows of data." - first things first.  

Base SAS - this is the programming language.  It is fully functional with all data types and can do anything you want.

Macro - this is a sub-component designed for creating text, which can be code.  It is not used as a replacement for Base SAS.

 

Now from this, how does a column of values relate to a macro?  They don't, data in datasets is controlled and manipulated by Base SAS.  So there is your starting point, writing Base SAS to do the process.  Once you have that fully down, then you can look at methods to generalise code and such like using macro once you fully grasp what is being generated.  Don't run before you can walk and all that.

 

As for specifics, post code, example test data in the form of a datastep, show what the output should look like, any information at all that helps us, who cannot see your computer, to see the problem.

axescot78
Quartz | Level 8

Capture.PNG

 

This is the first 8 rows of the table that I created. I need to add another column that calculates CohensD, which takes values from  this table: (absolute value of mean1 - mean2) divided by sqrt((SD1^2+SD2^2)/2). The calculation needs to be done in a macro and the table columns are the macro's parameters.

 

My code is below. The parts in bold are where I am stuck. It's throwing an error: ERROR: Undeclared array referenced: CookingTooMuch. Also, is there special notation to pass an array into a macro?

 

%macro CohensD(m_1,m_2,s_1,s_2);
  %let x = (abs(&m_1-&m_2))/(sqrt((&s_1**2 + &s_2**2)/2)));
  &x;
%mend CohensD;

proc iml;
 
Year = {1936, 1946, 1951, 1963, 1975, 1997, 2006};
x = nrow(Year);

Year1 = repeat(Year,x,1);
Year2 = repeat(Year[1],x,1) // repeat(Year[2],x,1) // repeat(Year[3],x,1) // repeat(Year[4],x,1) // repeat(Year[5],x,1) // repeat(Year[6],x,1) // repeat(Year[7],x,1);

CaloriesPerRecipeMean = {2123.8, 2122.3, 2089.9, 2250.0, 2234.2, 2249.6, 3051.9};
Mean1 = repeat(CaloriesPerRecipeMean,x,1);
Mean2 = repeat(CaloriesPerRecipeMean[1],x,1) // repeat(CaloriesPerRecipeMean[2],x,1) // repeat(CaloriesPerRecipeMean[3],x,1) // repeat(CaloriesPerRecipeMean[4],x,1) // repeat(CaloriesPerRecipeMean[5],x,1) // repeat(CaloriesPerRecipeMean[6],x,1) // repeat(CaloriesPerRecipeMean[7],x,1);

CaloriesPerRecipeSD = {1050.0, 1002.3, 1009.6, 1078.6, 1089.2, 1094.8, 1496.2};
SD1 = repeat(CaloriesPerRecipeSD,x,1);
SD2 = repeat(CaloriesPerRecipeSD[1],x,1) // repeat(CaloriesPerRecipeSD[2],x,1) // repeat(CaloriesPerRecipeSD[3],x,1) // repeat(CaloriesPerRecipeSD[4],x,1) // repeat(CaloriesPerRecipeSD[5],x,1) // repeat(CaloriesPerRecipeSD[6],x,1) // repeat(CaloriesPerRecipeSD[7],x,1);

create CookingTooMuch var {Year1, Year2, Mean1, Mean2, SD1, SD2};
append;
close CookingTooMuch;

quit;
proc print data=CookingTooMuch;
run;

data CookingTooMuch2;
   set CookingTooMuch;
   CohensD=%CohensD(CookingTooMuch[M1],CookingTooMuch[M2],CookingTooMuch[S1],CookingTooMuch[S2]);
run;
 
proc print data=CookingTooMuch2;
run;


 

 

RW9
Diamond | Level 26 RW9
Diamond | Level 26

See, you have gone and fallen for the old chestnut again:

"The calculation needs to be done in a macro and the table columns are the macro's parameters."

Start by writing Base SAS - it is the programming language:

data CookingTooMuch2;
set CookingTooMuch;
CohensD=(abs(mean1-mean2))/(sqrt((sd1**2 + sd2**2)/2)));
run;

There is no reason for macro anywhere in this code.

 

As for your provided information:

   CohensD=%CohensD(CookingTooMuch[M1],CookingTooMuch[M2],CookingTooMuch[S1],CookingTooMuch[S2]);

What is CookingTooMuch[M1] supposed to mean?  It almost appears you want to refer to an array, but have not created any?

It should perhaps read:

   CohensD=%CohensD(mean1,mean2,sd1,sd2);

 

Astounding
PROC Star

Despite not being an IML user (so I'm assuming your formula and use in context are correct), this looks like the right way to go:

 

%macro CohensD(m_1,m_2,s_1,s_2);
  (abs(&m_1-&m_2))/(sqrt((&s_1**2 + &s_2**2)/2)))
%mend CohensD;

 

The semicolon can be removed at the end of the formula, because you have one in the program after calling the macro.

 

When you test it, add this first to make debugging easier:

 

options mprint;

axescot78
Quartz | Level 8

I figured this out. If anyone is interested, here is the correct code and output:

 

Capture.PNG

 

%macro CohensD(m_1,m_2,s_1,s_2);
  %let x = (abs(&m_1-&m_2))/(sqrt((&s_1**2 + &s_2**2)/2));
  &x;
%mend CohensD;

proc iml;
 
Year = {1936, 1946, 1951, 1963, 1975, 1997, 2006};
x = nrow(Year);

Year1 = repeat(Year,x,1);
Year2 = repeat(Year[1],x,1) // repeat(Year[2],x,1) // repeat(Year[3],x,1) // repeat(Year[4],x,1) // repeat(Year[5],x,1) // repeat(Year[6],x,1) // repeat(Year[7],x,1);

CaloriesPerRecipeMean = {2123.8, 2122.3, 2089.9, 2250.0, 2234.2, 2249.6, 3051.9};
Mean1 = repeat(CaloriesPerRecipeMean,x,1);
Mean2 = repeat(CaloriesPerRecipeMean[1],x,1) // repeat(CaloriesPerRecipeMean[2],x,1) // repeat(CaloriesPerRecipeMean[3],x,1) // repeat(CaloriesPerRecipeMean[4],x,1) // repeat(CaloriesPerRecipeMean[5],x,1) // repeat(CaloriesPerRecipeMean[6],x,1) // repeat(CaloriesPerRecipeMean[7],x,1);

CaloriesPerRecipeSD = {1050.0, 1002.3, 1009.6, 1078.6, 1089.2, 1094.8, 1496.2};
SD1 = repeat(CaloriesPerRecipeSD,x,1);
SD2 = repeat(CaloriesPerRecipeSD[1],x,1) // repeat(CaloriesPerRecipeSD[2],x,1) // repeat(CaloriesPerRecipeSD[3],x,1) // repeat(CaloriesPerRecipeSD[4],x,1) // repeat(CaloriesPerRecipeSD[5],x,1) // repeat(CaloriesPerRecipeSD[6],x,1) // repeat(CaloriesPerRecipeSD[7],x,1);

create CookingTooMuch var {Year1, Year2, Mean1, Mean2, SD1, SD2};
append;
close CookingTooMuch;

quit;
proc print data=CookingTooMuch;
run;

data CookingTooMuch2;
   set CookingTooMuch;
   CohensD=%CohensD(Mean1,Mean2,SD1,SD2);
run;
                  
proc print data=CookingTooMuch2;
run;

Kurt_Bremser
Super User

There's still no reason to use a macro at all. It just moves code away from where it is used, and makes your whole code less readable and less maintainable, for no apparent gain. Remove the macro defintion and put the code where it belongs in the last data step:

data CookingTooMuch2;
   set CookingTooMuch;
   CohensD=(abs(Mean1-Mean2))/(sqrt((SD1**2 + SD2**2)/2));
run;
axescot78
Quartz | Level 8
I'm doing this for a class and part of the requirements is to use a macro 😉
axescot78
Quartz | Level 8
Actually, if you have a more elegant solution to how to get the 2nd, 4th, and 6th columns to repeat like that, I'm all ears!
Kurt_Bremser
Super User

@axescot78 wrote:
Actually, if you have a more elegant solution to how to get the 2nd, 4th, and 6th columns to repeat like that, I'm all ears!

Repeating code is a valid argument for a macro, in which case I have a suggestion to make your macro simpler:

%macro CohensD(m_1,m_2,s_1,s_2);
abs(&m_1-&m_2))/(sqrt((&s_1**2 + &s_2**2)/2);
%mend CohensD;

although the gain here (in terms of code that needs typing) is still very limited.

Kurt_Bremser
Super User

There's a conflict here:

 

Beginning SAS student

refers to a macro

 

As a beginner, you should NOT think about macro programming AT ALL. Since all SAS issues can be solved without the use of a macro (albeit inefficiently in some cases), you absolutely need to learn to solve those issues with Base SAS language alone. Only when you have a sufficiently advanced grasp of what can and should be done with Base SAS and the data step, you can start optimizing your code by using macro.

 

The macro preprocessor is not a problem solver, but a helper in making code writing more efficient.

axescot78
Quartz | Level 8

Maybe I'm a Super User and didn't even know it! hahahahahaha

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

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
  • 13 replies
  • 1234 views
  • 3 likes
  • 5 in conversation