BookmarkSubscribeRSS Feed
capam
Pyrite | Level 9

I have the following script which has a logic for _n_ within a macro. I wish to reset _n_ each  time the macro is called. 

Can you show me how _n_ is reset according to the new value of num?

 

Thanks.

%macro dostuff(num);

	data want;
		if _n_=1 then
			do j=1 to 3;
				set have;
				total + var;

				if j=1 then
					firstvar = var;

				if j=3 then
					varavg = total / 3;
			end;

		retain varavg firstvar;
		set have;
		vardif = var - firstvar;
		vardif2 = var - varavg;
		drop j;
	run;

	more stuff
%mend dostuff;
14 REPLIES 14
Quentin
Super User

Your meaning isn't clear.  _n_ is a counter for the number of times the DATA step loop has iterated.  You say you want to reset it according the value of num, but there is no variable num.

 

Maybe you should describe the big picture of what you are trying to do.  It looks like you're using something like a DoW loop to compute the average of a variable and the value of the variable in the first record? 

 

 

The Boston Area SAS Users Group is hosting free webinars!
Next up: Joe Madden & Joseph Henry present Putting Power into the Hands of the Programmer with SAS Viya Workbench on Wednesday Nov 6.
Register now at https://www.basug.org/events.
capam
Pyrite | Level 9
Hi Quentin,
The usage of &num is within 'more stuff'. I would like to have a mechanism to revisit the logic to get a new firstvar and varavg for each new 'num'.

You're right to ask because 'var' is modified each '&num'.

Regards,
capam
Pyrite | Level 9
'var' is modified within 'more stuff'.
PaigeMiller
Diamond | Level 26

@capam wrote:
'var' is modified within 'more stuff'.

But we don't know what this means.

 

What 'more stuff'???

 

If you don't show us the code, how can we help?

 

And please explain to us the overall end goal of this macro(s), because there may be much simpler ways to achieve the end goal.

 

Also, I agree with @Quentin, you can't really modify _n_ anyway, it is a counter, controlled by the data step.

--
Paige Miller
capam
Pyrite | Level 9
%macro dostuff(num);

	data want;
		if _n_=1 then
			do j=1 to 3;
				set have;
				total + var;

				if j=1 then
					firstvar = var;

				if j=3 then
					varavg = total / 3;
			end;

		retain varavg firstvar;
		set have;
		vardif = var - firstvar;
		vardif2 = var - varavg;
		drop j;
	run;

	proc sgplot data=have ;
		where unit = "&num";
		scatter x=Time y=vardif;
		scatter x=Time y=vardif2;
	run;

%mend dostuff;

The output is based on a simple plot routine. Hope this clarifies it.

The vardif and vardif2 are derived from the 'unit' that is changed each iteration.

 

Quentin
Super User
Could you perhaps add say 10 records of your have dataset, as an example. And also describe the desired output (i.e. how it differs from the output you are getting). Is it that your data has multiple records for each unit, and you want to compute vardif and vardif2 using by unit (so to speak)?
The Boston Area SAS Users Group is hosting free webinars!
Next up: Joe Madden & Joseph Henry present Putting Power into the Hands of the Programmer with SAS Viya Workbench on Wednesday Nov 6.
Register now at https://www.basug.org/events.
capam
Pyrite | Level 9

A matrix below describes the input and desired output vs actual output. Thanks for your help.

 

unitTimevardesired vardifdesired vardif2actual vardifactual vardif3
280003JAN2014:05:11:4841.10-0.50-0.5
280009JAN2014:16:59:3841.10-0.50-0.5
280011JAN2014:20:31:4042.61.511.51
280016JAN2014:07:40:1542.61.511.51
280020JAN2014:14:53:0842.61.511.51
280103JAN2014:05:11:484100-0.1-0.6
280109JAN2014:16:59:384100-0.1-0.6
280111JAN2014:20:31:404100-0.1-0.6
280116JAN2014:07:40:1542.51.51.51.40.9
280120JAN2014:14:53:0842.51.51.51.40.9
Reeza
Super User

What are the rules for your groups, they seem to differ in the number of records so I'm assuming weekly or a window of some sort?

How big is the data? Otherwise, SQL may be an easy solution. 

 


@capam wrote:

A matrix below describes the input and desired output vs actual output. Thanks for your help.

 

unit Time var desired vardif desired vardif2 actual vardif actual vardif3
2800 03JAN2014:05:11:48 41.1 0 -0.5 0 -0.5
2800 09JAN2014:16:59:38 41.1 0 -0.5 0 -0.5
2800 11JAN2014:20:31:40 42.6 1.5 1 1.5 1
2800 16JAN2014:07:40:15 42.6 1.5 1 1.5 1
2800 20JAN2014:14:53:08 42.6 1.5 1 1.5 1
2801 03JAN2014:05:11:48 41 0 0 -0.1 -0.6
2801 09JAN2014:16:59:38 41 0 0 -0.1 -0.6
2801 11JAN2014:20:31:40 41 0 0 -0.1 -0.6
2801 16JAN2014:07:40:15 42.5 1.5 1.5 1.4 0.9
2801 20JAN2014:14:53:08 42.5 1.5 1.5 1.4 0.9

 

Quentin
Super User

I would approach this with a "DoW loop", that is explicitly loop through each by group once to compute the total and first record, then a second time to compute the differences and output records.  This is similar to the approach you were trying, but it allows you compute the total of the first three records in each by-group.

 

Note that with the DOW loop approach, you don't RETAIN variables, because the DATA step loop only iterates once for each by-group. COUNT and TOTAL are automatically reset to missing before the start of each by-group.

 

data have ;
input unit Time $18. var ;
cards ;
2800 03JAN2014:05:11:48 41.1 
2800 09JAN2014:16:59:38 41.1 
2800 11JAN2014:20:31:40 42.6 
2800 16JAN2014:07:40:15 42.6 
2800 20JAN2014:14:53:08 42.6 
2801 03JAN2014:05:11:48 41 0 
2801 09JAN2014:16:59:38 41 0 
2801 11JAN2014:20:31:40 41 0 
2801 16JAN2014:07:40:15 42.5 
2801 20JAN2014:14:53:08 42.5 
;

data want ;
  do until(last.unit) ;
    set have ;
    by unit ;
    count=sum(count,1) ;
    if count=1 then firstvar=var ;
    if count<=3 then do ;
      total=sum(total,var) ;
    end ;
  end ;
  average=total/3 ;
  do until(last.unit) ;
    set have ;
    by unit ;
    vardif=var-firstvar ;
    vardif2=var-average ;
    output ;
  end ;
run ;
The Boston Area SAS Users Group is hosting free webinars!
Next up: Joe Madden & Joseph Henry present Putting Power into the Hands of the Programmer with SAS Viya Workbench on Wednesday Nov 6.
Register now at https://www.basug.org/events.
capam
Pyrite | Level 9
Thanks Quentin for your time and effort. However, vardif and vardif2 don't reset for each unit. Whatever is used for the counter should cause the firstvar and average to reset for each unit change.
Quentin
Super User

I don't understand.  When I run my code, you get different values for firstvar and average for each by-group (each unit).  And the computed values of vardif and vardif2 match your desired values.  Don't they?  If not, can you explain what is wrong with the below printout of the WANT created by my sample code:

 

 unit          Time           var   count   firstvar   total   average   vardif   vardif2

 2800   03JAN2014:05:11:48   41.1     5       41.1     124.8     41.6      0.0      -0.5
 2800   09JAN2014:16:59:38   41.1     5       41.1     124.8     41.6      0.0      -0.5
 2800   11JAN2014:20:31:40   42.6     5       41.1     124.8     41.6      1.5       1.0
 2800   16JAN2014:07:40:15   42.6     5       41.1     124.8     41.6      1.5       1.0
 2800   20JAN2014:14:53:08   42.6     5       41.1     124.8     41.6      1.5       1.0
 2801   03JAN2014:05:11:48   41.0     5       41.0     123.0     41.0      0.0       0.0
 2801   09JAN2014:16:59:38   41.0     5       41.0     123.0     41.0      0.0       0.0
 2801   11JAN2014:20:31:40   41.0     5       41.0     123.0     41.0      0.0       0.0
 2801   16JAN2014:07:40:15   42.5     5       41.0     123.0     41.0      1.5       1.5
 2801   20JAN2014:14:53:08   42.5     5       41.0     123.0     41.0      1.5       1.5
The Boston Area SAS Users Group is hosting free webinars!
Next up: Joe Madden & Joseph Henry present Putting Power into the Hands of the Programmer with SAS Viya Workbench on Wednesday Nov 6.
Register now at https://www.basug.org/events.
Reeza
Super User

_n_ is an automatic variable, I wouldn't reset it and it automatically will reset for each macro call/data step.

 

However, I suspect you're really looking for BY group functionality and something along the lines of the FIRST. logic.

Are you using this approach to try and get efficiency or because someone recommended this approach? It seems like it would be easier to do two data steps.

WarrenKuhfeld
Ammonite | Level 13

If you want a variable that is similar to _n_ but deviates in some way, simply make it your self and forget about resetting _n_.  For example, this increments a new variable by one for every observation except 'Mary'.

 

 

 

data subset;
   set sashelp.class;
   my_n_ + name ne 'Mary'; * Note the implicit retain and initialization to 0;
run;

proc print; run;

 

Astounding
PROC Star

If the intent is to control which observations to use to compute TOTAL and FIRSTVAR, you wouldn't re-set _n_ to get what you need. Consider changing the first SET statement:

 

do j=1 to 3;

   set have (firstobs=&num);

SAS Innovate 2025: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 14 replies
  • 2630 views
  • 0 likes
  • 6 in conversation