BookmarkSubscribeRSS Feed
kim_trevino1
Fluorite | Level 6
Hello, 
 
I'm new to macros and arrays. This was an assignment I had from a few weeks ago that I don't think I did correctly.  Part three looping macros is what is giving me trouble. Can someone tell me where I am going wrong? I'm attaching the assignment and my code. I think what gets me confused is when my professor tells me to convert my array into a macro. Am I converting an array into a macro? Also, The single macro with parameters runs fine, but my final macro is a mess. What am I doing wrong? 
 
Thank you, 
Kim 
 
***Assignment***
Loops, Arrays, and Macros:A Little Fun? with WordsumIntroduction:
This assignment is due October 5. It will conclude our tour of computational techniques that advanced survey data analysts should be able to employ. The emphasis here is on concise, elegant code that causes great things to happen. Submit code and logs. Grades will be based on how few lines (semicolons) of code you use to accomplish the tasks. To be sure, this one starts out fairly easy and becomes very challenging. You will iterate through a lot of variations in code. Start early. It actually is rewarding when you crack the coding nut.
Background: Study up on the WORDSUM and WORDA—WORDJ variables in the GSS cumulative file. You will find that this is a verbal intelligence test designed for surveys. Like a lot of methodological innovations, Gallup started using this in the 1940s. Pay special attention to the years in which these items appeared on GSS (hint: see around pg. 3761 in the codebook .pdf file).
You should be able to do this in about 20 lines of code. The point is to let the computer do the repetition while you sit back and watch.
 
Tasks:1)Arrays and LoopsLocate the “Simplifying Programs with Arrays” section in the Little SAS Book which is section 3.11 in the fifth edition. Using only the data for 1988, follow the example to define an array that designates the WORDx variables, loops across all array cells, and assigns missing values. Check your results with appropriate tabulations.
 
2)Macro with ParametersUsing the “Adding Parameters to Macros” section (7.4 in the fifth edition), convert the array developed in (1) to a macro which substitutes in 1988 for a generic year variable. That is, instruct the macro to run on the 1988 data. Pay special attention to the macro commands that always begin with “%”.
 
3)Macro that Loops across Multiple YearsOnce you have your macro working for 1988, add code that instructs the macro to parse across all years of available data. This is not documented in the book. The basic form of the macro loop looks like this:
%macro macroname;
%do i = start_value %to end value %by increment ;
%callmacro(var=&i) %end;
%mend macroname;
Where macroname = a name you give the macro that runs across years.
 
The loop start value is the first value you want to use for this loop (e.g., 1988), end value is the last value (end year), and increment is how much the start value is increased on each iteration. It’s easy for the period when GSS data were collected every year. The increment is one (the default). But, you need to figure out what to do when the survey becomes biennial (not exactly rocket science, but you can do it). Look back at the codebook page noted above for a reminder of what years the WORDSUM data were collected. Where I have inserted call macro, you put the name of the macro you developed in step 2. The step 3 loop will keep running that macro over and over until all years have been parsed. Hint: When I did this step I embedded three do loops in the macro due to variations in year increments and skip patterns. Gold star to someone(s) who can figure out a way to do it in fewer loops.
 
 
***My Code***
 

libname in "C:\Users\kim_trevino1\Desktop\Advanced STATS 2020"; run;

*options symbolgen;

Data work.worddata2;
set in.gss7218_r3(Keep= Year ID marital wrkstat hrs1 age educ region sex race
rincome income occ10 prestg10 indus10 size worda wordB wordc wordd worde wordf wordg wordh wordi wordj wordsum wtssall);

Array worddata (10)$ worda --wordj; /*wordsum not included because 9 is a value and not missin*/
Do i= 1 to 10;
if worddata(i)in (9,-1)then worddata (i)=.;
/*Where year=1988*/
end;
run;


Proc freq data=work.worddata2;
Table year*worda--wordsum;
weight wtssall;
Run;

 

Data work.worddatamacro;
set work.worddata2;
run;

 

%macro wordscore(year);
proc sort data=work.worddatamacro; by year; run;

*read following data;
proc freq data=work.worddatamacro;
where year=&year.;
tables worda--wordsum;
title 'Word Score for &year.';
run;
%mend wordscore;

data worddata3; set work.worddatamacro;Run;

%wordscore(1988);

%macro wordscore (year);
%Do i=1974 %to 1984 %by 2; %wordscore(year=&i.) %end;
%Do i=1987 %to 1994 %by 1; %wordscore(year=&i.) %end;
%Do i=1996 %to 2000 %by 2; %wordscore(year=&i.) %end;
%Do i=2004 %to 2018 %by 2; %wordscore(year=&i.) %end;

%mend wordscore;
%wordscore;
Ods rtf close;
run;

 

9 REPLIES 9
PaigeMiller
Diamond | Level 26

This was an assignment I had from a few weeks ago that I don't think I did correctly.  Part three looping macros is what is giving me trouble. Can someone tell me where I am going wrong?

We don't have your data sets, and I'm not going to go line by line through your code to figure out what you mean. You can't simply ask "where I am going wrong?", because we don't know what is wrong, and we need specific information about what you think (or what SAS thinks) is wrong.

 

Please run your code again with this line at the top

options mprint;

We need to see the LOG. We need to see the LOG properly formatted so we can read it. You do this by copying it as text and pasting it into the window that appears when you click on the </> icon. DO NOT SKIP THIS STEP. Otherwise, we get a badly formatted log which is of no use to us.

 

Lastly, I am somewhat annoyed at your professor, as repeating analyses over years is not really something you want to do with macros. Using a BY statement is a much simpler method. Teaching to do this via macros positively re-inforces bad practices.

--
Paige Miller
kim_trevino1
Fluorite | Level 6
      Licensed to BAYLOR UNIVERSITY - SFA - T&R, Site 70092987.
NOTE: This session is executing on the X64_10PRO  platform.



NOTE: Analytical products:

      SAS/STAT 15.1
      SAS/ETS 15.1
      SAS/IML 15.1
      SAS/QC 15.1

NOTE: Additional host information:

 X64_10PRO WIN 10.0.18362  Workstation

NOTE: SAS initialization used:
      real time           1.00 seconds
      cpu time            0.54 seconds

1    libname in "C:\Users\kim_trevino1\Desktop\Advanced STATS 2020";
NOTE: Libref IN was successfully assigned as follows:
      Engine:        V9
      Physical Name: C:\Users\kim_trevino1\Desktop\Advanced STATS 2020
1  !                                                                 run;
2
3    *options symbolgen;
4    options mprint;
5    Data work.worddata2;
6        set in.gss7218_r3(Keep= Year ID marital wrkstat hrs1 age educ region sex race
7    rincome income occ10 prestg10 indus10 size worda wordB wordc wordd worde wordf wordg wordh
7  ! wordi wordj wordsum wtssall);
8
9    Array worddata (10)$ worda --wordj;  /*wordsum not included because 9 is a value and not
9  ! missin*/
10   Do i= 1 to 10;
11   if worddata(i)in (9,-1)then worddata (i)=.;
12   /*Where year=1988*/
13   end;
14   run;

NOTE: There were 64814 observations read from the data set IN.GSS7218_R3.
NOTE: The data set WORK.WORDDATA2 has 64814 observations and 29 variables.
NOTE: DATA statement used (Total process time):
      real time           3.86 seconds
      cpu time            1.39 seconds


15   ibname in "C:\Users\kim_trevino1\Desktop\Advanced STATS 2020";
     ------
     14
NOTE: Libref IN was successfully assigned as follows:
      Engine:        V9
      Physical Name: C:\Users\kim_trevino1\Desktop\Advanced STATS 2020
WARNING 14-169: Assuming the symbol LIBNAME was misspelled as ibname.

16
17   *options symbolgen;
18   options mprint; run;
19   Data work.worddata2;
20       set in.gss7218_r3(Keep= Year ID marital wrkstat hrs1 age educ region sex race
21   rincome income occ10 prestg10 indus10 size worda wordB wordc wordd worde wordf wordg wordh
21 ! wordi wordj wordsum wtssall);
22
23   Array worddata (10)$ worda --wordj;  /*wordsum not included because 9 is a value and not
23 ! missin*/
24   Do i= 1 to 10;
25   if worddata(i)in (9,-1)then worddata (i)=.;
26   /*Where year=1988*/
27   end;
28   run;

NOTE: There were 64814 observations read from the data set IN.GSS7218_R3.
NOTE: The data set WORK.WORDDATA2 has 64814 observations and 29 variables.
NOTE: DATA statement used (Total process time):
      real time           2.91 seconds
      cpu time            1.07 seconds


29   Proc freq data=work.worddata2;
30   Table year*worda--wordsum;
31   weight wtssall;
32   Run;

NOTE: Writing HTML Body file: sashtml.htm
NOTE: There were 64814 observations read from the data set WORK.WORDDATA2.
NOTE: PROCEDURE FREQ used (Total process time):
      real time           1.09 seconds
      cpu time            0.68 seconds


33
34   Data work.worddatamacro;
35   set work.worddata2;
36   run;

NOTE: There were 64814 observations read from the data set WORK.WORDDATA2.
NOTE: The data set WORK.WORDDATAMACRO has 64814 observations and 29 variables.
NOTE: DATA statement used (Total process time):
      real time           0.02 seconds
      cpu time            0.01 seconds


37
38   %macro wordscore(year);
39   proc sort data=work.worddatamacro; by year; run;
40
41   *read following data;
42   proc freq data=work.worddatamacro;
43       where year=&year.;
44       tables worda--wordsum;
45       title 'Word Score for &year.';
46   run;
47   %mend wordscore;
48
49   data worddata3; set work.worddata2;Run;

NOTE: There were 64814 observations read from the data set WORK.WORDDATA2.
NOTE: The data set WORK.WORDDATA3 has 64814 observations and 29 variables.
NOTE: DATA statement used (Total process time):
      real time           0.01 seconds
      cpu time            0.01 seconds


50
51   %wordscore(1988);
MPRINT(WORDSCORE):   proc sort data=work.worddatamacro;
MPRINT(WORDSCORE):   by year;
MPRINT(WORDSCORE):   run;

NOTE: There were 64814 observations read from the data set WORK.WORDDATAMACRO.
NOTE: The data set WORK.WORDDATAMACRO has 64814 observations and 29 variables.
NOTE: PROCEDURE SORT used (Total process time):
      real time           0.03 seconds
      cpu time            0.03 seconds


MPRINT(WORDSCORE):   *read following data;
MPRINT(WORDSCORE):   proc freq data=work.worddatamacro;
MPRINT(WORDSCORE):   where year=1988;
MPRINT(WORDSCORE):   tables worda--wordsum;
MPRINT(WORDSCORE):   title 'Word Score for &year.';
MPRINT(WORDSCORE):   run;
NOTE: There were 1481 observations read from the data set WORK.WORDDATAMACRO.
      WHERE year=1988;
NOTE: PROCEDURE FREQ used (Total process time):
      real time           0.05 seconds
      cpu time            0.03 seconds


52   Data work.worddatamacro2;
53   set work.worddata3;
54   run;

NOTE: There were 64814 observations read from the data set WORK.WORDDATA3.
NOTE: The data set WORK.WORDDATAMACRO2 has 64814 observations and 29 variables.
NOTE: DATA statement used (Total process time):
      real time           0.01 seconds
      cpu time            0.01 seconds


55   %macro loopyear (year);
56       %Do i=1974 %to 1984 %by 2; %loopyear(year=&i.) %end;
57       %Do i=1987 %to 1994 %by 1; %loopyear(year=&i.) %end;
58       %Do i=1996 %to 2018 %by 2; %loopyear(year=&i.) %end;
59       run;
60
61   %mend loopyear;
62   data worddata4; set work.worddatamacro2;Run;

NOTE: There were 64814 observations read from the data set WORK.WORDDATAMACRO2.
NOTE: The data set WORK.WORDDATA4 has 64814 observations and 29 variables.
NOTE: DATA statement used (Total process time):
      real time           0.01 seconds
      cpu time            0.01 seconds


63   %loopyear (year);

So after this step, part three of the assignment, it does nothing. It just spins its wheels for eternity. 

The data set is the GSS, if that helps, and I'm using his notes and the little sas book to code. 

 

Thank you, Paige, for helping me. I was a little intimidated, reaching out for help. The assignment is over, but I want to make sure I understand how to code a macro correctly. I will be analyzing panel data soon, so it is useful to know that this might not be the best way. Do you mind explaining why macros are inappropriate for this task or pointing me in the direction of a good resource? 

 

Thank you again. 

PaigeMiller
Diamond | Level 26

As I explained, if you want perform the same analysis on each year, virtually every SAS PROC has a BY statement which eliminates the need for macro loops. You use BY YEAR; in the PROC.

--
Paige Miller
kim_trevino1
Fluorite | Level 6

Okay, thank you. 

Tom
Super User Tom
Super User

This part of the code does not look right.

55   %macro loopyear (year);
56       %Do i=1974 %to 1984 %by 2; %loopyear(year=&i.) %end;
57       %Do i=1987 %to 1994 %by 1; %loopyear(year=&i.) %end;
58       %Do i=1996 %to 2018 %by 2; %loopyear(year=&i.) %end;
59       run;
60
61   %mend loopyear;
62   data worddata4; set work.worddatamacro2;Run;

NOTE: There were 64814 observations read from the data set WORK.WORDDATAMACRO2.
NOTE: The data set WORK.WORDDATA4 has 64814 observations and 29 variables.
NOTE: DATA statement used (Total process time):
      real time           0.01 seconds
      cpu time            0.01 seconds


63   %loopyear (year);

First you defined the macro LOOPYEAR to take parameter named YEAR, and when you called it you assigned the YEAR parameter the text string year instead of a real value.  But since the macro is not using the YEAR parameter in any way that actually doesn't matter.

 

Second you are calling your same macro LOOPYEAR recursively.  So it will keep calling itself until SAS runs out of memory.  You need to change the calls to LOOPYEAR inside the definition of the macro LOOPYEAR to call the macro WORDSCORE.

ballardw
Super User

Why do you have two definitions for the same macro? That way lies madness as you may not know which version is running.

 

Defining a macro and calling the same macro inside the macro also seems like a descent into madness would follow.

%macro wordscore (year);
%Do i=1974 %to 1984 %by 2; %wordscore(year=&i.) %end;
%Do i=1987 %to 1994 %by 1; %wordscore(year=&i.) %end;
%Do i=1996 %to 2000 %by 2; %wordscore(year=&i.) %end;
%Do i=2004 %to 2018 %by 2; %wordscore(year=&i.) %end;

%mend wordscore;
kim_trevino1
Fluorite | Level 6

Thank you, Ballardw. The TA helped me write this. I wish I could explain why, but I wasn't aware the texts was defining the same macro twice. 

Could you instruct me on how to write this better? 

%Do i=1974 %to 1984 %by 2; %end;

Is the text above all I need?

 

Tom
Super User Tom
Super User

The professors question and hint are as clear as mud.

You need two macros. One that works for one specific year.

Then a second one that has the %DO loop and then calls the first one.

 

You seemed to create the first one, but then instead of making a second one you replaced the first one.

 

 

%macro one_year(year);
 .... put actual code here ...
%mend ;

%macro mutliple_years(start,end,increment);
%local year;
%do year=&start %to &end %by &increment;
   %one_year(&year)
%end;
%mend multiple_years;

 

 

kim_trevino1
Fluorite | Level 6

Thank you, Tom. I will try this and get back to you. The problem with learning a new language (SAS) is that I know I have questions, but I'm not sure how to ask them clearly.  I'm left asking, "How do I make the thing work?"hahaha. 

Ready to join fellow brilliant minds for the SAS Hackathon?

Build your skills. Make connections. Enjoy creative freedom. Maybe change the world. Registration is now open through August 30th. Visit the SAS Hackathon homepage.

Register today!
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
  • 9 replies
  • 695 views
  • 2 likes
  • 4 in conversation