BookmarkSubscribeRSS Feed
santoshmatta89
Calcite | Level 5

Hi All,

I'm trying to do the below steps to complete one of the requirements.

1. Take the first observation weight value and assign it to a macro variable.
2.From the next row compare the weight with macro variable and check if the change in weight is more than 10% .
3. If the change in weight is greater than 10% then update the macro variable with the current row weight value.
4. Continue the above steps.

 

I've used the below code but Step 3 in the above seems to be failing. Could you please advise on the steps to achieve this or any other alternate solutions?

 

%macro process;
data a;
set outdata.dummy_weights(firstobs = 1 obs = 1);
%global ref;
call symput('ref', weight_digit);
run;

data dosing4;
set outdata.dummy_weights;
if cycle eq "Cycles 1" then weight_baseline = weight_digit; 
						       
if cycle ne "Cycles 1" then
	if (((weight_digit - %sysevalf(&ref)) / (%sysevalf(&ref))) * 100) > 10 then 
		  do; 
		  weight_baseline = weight_digit;
		  call symput('ref', weight_baseline);
		  %put &ref;
		  end;
	else
			weight_baseline = symget('ref');
run;

/*%put &ref;*/
%mend;

%process;

Sample Data set:

SR. No.CycleWeightWeight_digit
1Cycles 180KG80
2Cycle 280KG80
3Cycle2.180KG80
4Cycle2.280KG80
5Cycle 389KG89
6Cycle 489KG89
7Cycle 592KG92
8Cycle 695KG95
9Cycle 799KG99
5 REPLIES 5
Tom
Super User Tom
Super User

Seems like a silly assignment.  Why are you doing this?  Why are you changing the macro variable value in the middle of data step?  Just use a dataset variable for things you need to modify during a data step.

 

Changing the value of a macro variable in the middle of data step will not change the value that the macro processor used when it generated the code for the data step.  If you want to retrieve the current value for a macro variable that might have changed since your data step started running you can use the SYMGET() or SYMGETN() function.

 

So this line is NOT changed during the execution:

	if (((weight_digit - %sysevalf(&ref)) / (%sysevalf(&ref))) * 100) > 10 then 

And this line runs BEFORE the data step begins executing.

%put &ref;
Tom
Super User Tom
Super User

I don't understand the algorithm.  Are you asking to change the denominator used to calculate the % change when the change is more than 10% ?  Is that for both increases and decreases?  

So if the series is 100,105,120,131,140 do you want something like this? 

 

WT BASE CHANGE%
100 100  0%
105 100  5%
120 100 20%    ****
131 120  9.17% 
140 120 16.7%  ****

 

 

santoshmatta89
Calcite | Level 5

Thanks for the response. 

Yes, this is the output that I'm expecting and It's for increasing order of weights.

I was under a thought that checking if the % change is greater than 10 and updating the macro variable for the next iterations would do the job but as you said macro variable does not get updated during the middle of the execution. 

Any inputs here please?

 

Thanks

Tom
Super User Tom
Super User

You just need to retain your new variable that has the base weight.  To make the output dataset look more reasonable change the base weight AFTER writing the current observation.

data have; 
  infile cards dsd dlm='|' truncover;
  subject = '001';
  input sr Cycle :$20. Weight :$20. Weight_digit ;
cards;
1|Cycles 1|80KG|80
2|Cycle 2|80KG|80
3|Cycle2.1|80KG|80
4|Cycle2.2|80KG|80
5|Cycle 3|89KG|89
6|Cycle 4|89KG|89
7|Cycle 5|92KG|92
8|Cycle 6|95KG|95
9|Cycle 7|99KG|99
;

data want;
  set have ;
  if cycle='Cycles 1' then base=weight_digit ;
  change = weight_digit - base;
  percent_change = 100*change/base;
  output;
  if abs(percent_change) > 10 then base=weight_digit;
  retain base;
run;

proc print;
run;
                                              Weight_                      percent_
Obs    subject    sr     Cycle      Weight     digit     base    change     change

 1       001       1    Cycles 1     80KG        80       80        0        0.0000
 2       001       2    Cycle 2      80KG        80       80        0        0.0000
 3       001       3    Cycle2.1     80KG        80       80        0        0.0000
 4       001       4    Cycle2.2     80KG        80       80        0        0.0000
 5       001       5    Cycle 3      89KG        89       80        9       11.2500
 6       001       6    Cycle 4      89KG        89       89        0        0.0000
 7       001       7    Cycle 5      92KG        92       89        3        3.3708
 8       001       8    Cycle 6      95KG        95       89        6        6.7416
 9       001       9    Cycle 7      99KG        99       89       10       11.2360

 

Tom
Super User Tom
Super User

If you really did want to try to use a macro variable to store the base weight (not a good idea since macro variable as strings and so could lose precision on the values) you just need to make sure to reference the value using SYMGET() or in this case since you want to treat the string as a number use SYMGETN().

data silly;
  set have ;
  if cycle eq "Cycles 1" then call symputx('ref',weight_digit);
  change = weight_digit - symgetn('ref');
  percent_change = 100*change/symgetn('ref');
  if abs(percent_change) > 10 then call symputx('ref',weight_digit);
run;

%put &=ref;

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
  • 392 views
  • 0 likes
  • 2 in conversation