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. | Cycle | Weight | Weight_digit |
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 |
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;
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% ****
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
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
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;
Available on demand!
Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.
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.