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

Lets say I have a table called: pg2. savings looking like this: 

 

ObsNameAmount
1James250
2Linda300
3Mary275
4Robert350

 

If I now run the code: 

data YearSavings;
	set pg2.savings;
	*savings = 0; *This will solve the problem of question 1 below.;
		do Month=1 to 12;
			Savings+Amount;
			Savings+(Savings*0.02/12);
		end;
	format Savings comma12.2;
	*Month = Month-1; *Related to question 2; 
run;
I get the following output: 
 
ObsNameAmountMonthSavings
1James250133,032.70
2Linda300136,733.15
3Mary2751310,205.03
4Robert3501314,656.79
 
Notice how the Savings column clearly is wrong (for example, Mary saves less than Linda but still ends up with more savings). 

The explanation for this is: 

"Notice that the Savings value keeps increasing for each row. This is because the value of Savings is automatically retained because it's part of a sum statement. So each time we start a new iteration of the data step, reading a new person, the value of Savings is retained, but it represents the savings from the previous person."

I have though about it but do not understand it. 

The solution is to un-comment the row: 
*savings = 0; *This will solve the problem of question 1 below.;

So my questions is:

1. Any explanations of why the problem occurs? I do not understand this nor the explanation given above. 
2. Despite running 12 months in the iterations, it shows up as 13 which is pretty uggly. One solution would be to un-comment  the row: 
*Month = Month-1;
Is there any best practices for this? 

Thanks. 
 
 
 
1 ACCEPTED SOLUTION

Accepted Solutions
FreelanceReinh
Jade | Level 19

Hello @SasStatistics,


@SasStatistics wrote:
2. Despite running 12 months in the iterations, it shows up as 13 which is pretty uggly. One solution would be to un-comment  the row: 
*Month = Month-1;
Is there any best practices for this? 

It is this additional incrementation of the index variable beyond the stop value (here: 12) which causes the loop to stop iterating. Sometimes this can be useful, e.g., because the final value of the index variable shows that the loop did not stop during the last iteration or earlier (example).

 

There are several reasons why in practice those "ugly" values are rarely an issue (that requires a statement like Month = Month-1):

  1. The index variables of many if not most iterative DO loops (of the form DO variable=start TO stop) are only used within the loop and not written to any output dataset. In these cases their names (typically i, j, etc.) often occur in DROP statements or DROP= dataset options:
    data ...(drop=i);
    ...
    do i=1 to ...;
      ...
    end;
    ...
    run;
  2. In many cases where the value of the index variable is written to the output dataset, this is done by an OUTPUT statement within the loop. This, in turn, overrides the implicit OUTPUT at the end of the DATA step iteration, so that the "ugly" last value is automatically left out. Insert an OUTPUT statement into your DO loop and you'll get 4*12=48 observations from your sample data and the assignment statement for Month can be deleted.
  3. Other common types of DO loops use UNTIL or WHILE conditions (or a LEAVE statement) preventing the index variable (if any) from being incremented beyond the stop value. In your example you could change the DO statement to either of the following forms and again omit the final assignment statement for Month.
    do Month=1 by 1 until(Month=12);
    do Month=1 by 1 while(Month<=12);

View solution in original post

3 REPLIES 3
SasStatistics
Pyrite | Level 9
Regarding question 1 I now understand it...

From the line "set pg2.savings;" a new row is read after each loop and after that we need to put savings = 0; .

So question 1 is Done!
FreelanceReinh
Jade | Level 19

Hello @SasStatistics,


@SasStatistics wrote:
2. Despite running 12 months in the iterations, it shows up as 13 which is pretty uggly. One solution would be to un-comment  the row: 
*Month = Month-1;
Is there any best practices for this? 

It is this additional incrementation of the index variable beyond the stop value (here: 12) which causes the loop to stop iterating. Sometimes this can be useful, e.g., because the final value of the index variable shows that the loop did not stop during the last iteration or earlier (example).

 

There are several reasons why in practice those "ugly" values are rarely an issue (that requires a statement like Month = Month-1):

  1. The index variables of many if not most iterative DO loops (of the form DO variable=start TO stop) are only used within the loop and not written to any output dataset. In these cases their names (typically i, j, etc.) often occur in DROP statements or DROP= dataset options:
    data ...(drop=i);
    ...
    do i=1 to ...;
      ...
    end;
    ...
    run;
  2. In many cases where the value of the index variable is written to the output dataset, this is done by an OUTPUT statement within the loop. This, in turn, overrides the implicit OUTPUT at the end of the DATA step iteration, so that the "ugly" last value is automatically left out. Insert an OUTPUT statement into your DO loop and you'll get 4*12=48 observations from your sample data and the assignment statement for Month can be deleted.
  3. Other common types of DO loops use UNTIL or WHILE conditions (or a LEAVE statement) preventing the index variable (if any) from being incremented beyond the stop value. In your example you could change the DO statement to either of the following forms and again omit the final assignment statement for Month.
    do Month=1 by 1 until(Month=12);
    do Month=1 by 1 while(Month<=12);
Tom
Super User Tom
Super User

If you really want to keep MONTH to indicate how many months ahead the calculated amount represents then use a different variable for the loop counter.

months=12 ;
do i=1 to months ;
  ....
end;
drop i;

 

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