Below is my data in column SUBJ, B and VALUE. I need MINIM column with the min(VALUE) compared to previous observations for same subject. Can Any one help?
SUBJ SEQ VALUE MINIM This is how MIN value is calculated
1004 1 35.58 - - There is no obs previous and should appear blank
1004 2 32.69 35.58 - Only one obs available prior so 35.58 is min
1004 3 26.15 32.69 - Compared to obs 1, 2 value of 32.69 is min
1004 4 21.77 26.15 - Compared to obs 1, 2 and 3 value of 26.15 is min
1004 5 19.47 21.77 - Compared to 1, 2,3 and 4 value of 21.77 is min
1004 6 19.52 19.47 - Compared to 1, 2,3,4 and 5 value of 19.47 is min
1004 7 13.71 19.47 - Compared to 1, 2,3,4,5 and 6 for this subject value of 19.47 is min
1004 8 13.7 13.71
1004 9 13.97 13.7
1004 10 24.28 13.7
1005 1 22.57 - - There is no previous obs for this subject and should appear blank
1005 2 10.21 22.57 - Only one row available previous so 22.57 is min
1005 3 10.35 10.21 - Compared to 1, 2 value of 10.21 is min
1005 4 10.35 10.21 - Compared to 1, 2 and 3 value of 10.21 is min
1005 5 10.35 10.21 - Compared to 1, 2,3 and 4 for this subject value of 21.77 is minimum
1005 6 9.76 10.21
Hi @jksthomas and welcome to the SAS Support Communities!
Here's another DATA step solution:
data want;
do until(last.subj);
set have;
by subj seq;
output;
minim=min(minim,value);
end;
run;
data have;
input SUBJ SEQ VALUE; * MINIM This is how MIN value is calculated;
cards;
1004 1 35.58 - - There is no obs previous and should appear blank
1004 2 32.69 35.58 - Only one obs available prior so 35.58 is min
1004 3 26.15 32.69 - Compared to obs 1, 2 value of 32.69 is min
1004 4 21.77 26.15 - Compared to obs 1, 2 and 3 value of 26.15 is min
1004 5 19.47 21.77 - Compared to 1, 2,3 and 4 value of 21.77 is min
1004 6 19.52 19.47 - Compared to 1, 2,3,4 and 5 value of 19.47 is min
1004 7 13.71 19.47 - Compared to 1, 2,3,4,5 and 6 for this subject value of 19.47 is min
1004 8 13.7 13.71
1004 9 13.97 13.7
1004 10 24.28 13.7
1005 1 22.57 - - There is no previous obs for this subject and should appear blank
1005 2 10.21 22.57 - Only one row available previous so 22.57 is min
1005 3 10.35 10.21 - Compared to 1, 2 value of 10.21 is min
1005 4 10.35 10.21 - Compared to 1, 2 and 3 value of 10.21 is min
1005 5 10.35 10.21 - Compared to 1, 2,3 and 4 for this subject value of 21.77 is minimum
1005 6 9.76 10.21
;
data want;
do _n_=1 by 1 until(last.subj);
set have;
by subj;
array t(99999) _temporary_;
if _n_>1 then min=min(of t(*));
t(_n_)=value;
output;
end;
call missing(of t(*));
run;
And if you want a SQL solution
data have;
input SUBJ SEQ VALUE; * MINIM This is how MIN value is calculated;
cards;
1004 1 35.58 - - There is no obs previous and should appear blank
1004 2 32.69 35.58 - Only one obs available prior so 35.58 is min
1004 3 26.15 32.69 - Compared to obs 1, 2 value of 32.69 is min
1004 4 21.77 26.15 - Compared to obs 1, 2 and 3 value of 26.15 is min
1004 5 19.47 21.77 - Compared to 1, 2,3 and 4 value of 21.77 is min
1004 6 19.52 19.47 - Compared to 1, 2,3,4 and 5 value of 19.47 is min
1004 7 13.71 19.47 - Compared to 1, 2,3,4,5 and 6 for this subject value of 19.47 is min
1004 8 13.7 13.71
1004 9 13.97 13.7
1004 10 24.28 13.7
1005 1 22.57 - - There is no previous obs for this subject and should appear blank
1005 2 10.21 22.57 - Only one row available previous so 22.57 is min
1005 3 10.35 10.21 - Compared to 1, 2 value of 10.21 is min
1005 4 10.35 10.21 - Compared to 1, 2 and 3 value of 10.21 is min
1005 5 10.35 10.21 - Compared to 1, 2,3 and 4 for this subject value of 21.77 is minimum
1005 6 9.76 10.21
;
proc sql;
create table want as
select a.subj,a.seq,a.value,min(b.value) as min
from have a left join have b
on a.subj=b.subj
and b.seq<a.seq
group by a.subj,a.seq,a.value
order by a.subj,a.seq;
quit;
Hi @jksthomas and welcome to the SAS Support Communities!
Here's another DATA step solution:
data want;
do until(last.subj);
set have;
by subj seq;
output;
minim=min(minim,value);
end;
run;
Indeed more efficient and tactfully observed(the values), makes me realise my lethargy. Need to change my coffee brand big time. Kudos!
@novinosrin wrote:Indeed more efficient and tactfully observed(the values), makes me realise my lethargy. Need to change my coffee brand big time. Kudos!
@novinosrin @FreelanceReinh Both of your prog worked well. Thanks a lot.
@jksthomas wrote:
@novinosrin wrote:Indeed more efficient and tactfully observed(the values), makes me realise my lethargy. Need to change my coffee brand big time. Kudos!
@novinosrin @FreelanceReinh Both of your prog worked well. Thanks a lot.
One more question: Can I get one more additonal row to display which seq from the subj is taken as minim?
@jksthomas wrote:
One more question: Can I get one more additonal row to display which seq from the subj is taken as minim?
Sure (assuming you mean: additional column, i.e. variable😞
data want;
do until(last.subj);
set have;
by subj seq;
output;
if value<minim | first.subj then do;
minim=value;
seq_minim=seq;
end;
end;
run;
In the case of tied minimum values, e.g., if in your sample data the observation with SUBJ=1005, SEQ=4 had VALUE=10.21 (instead of 10.35), the above code would store the first SEQ with a VALUE of 10.21 in SEQ_MINIM, i.e., SEQ_MINIM=2 for the last four observations. By replacing the "<" sign in the IF condition with "<=" you could obtain the last SEQ instead, i.e., SEQ_MINIM=4 in the last two observations (and, of course, still SEQ_MINIM=2 in the two preceding observations).
hi,
Thanks again for you help
Sorry i mean to say new variable.
Prog works fine from 3rd row, however, for the second row SEQ_MINIM is blank. Is there a way to display seq = 1 .
SUBJ VALUE SEQ MINIM SEQ_MINIM
1001003 22.57 1
1001003 10.21 2 22.57
1001003 10.35 3 10.21 2
1001003 10.35 4 10.21 2
1001003 10.35 5 10.21 2
1001003 9.76 6 10.21 2
@jksthomas wrote:
Prog works fine from 3rd row, however, for the second row SEQ_MINIM is blank. Is there a way to display seq = 1 .
This does not happen if the input dataset (HAVE) does not already contain the derived variables (MINIM, SEQ_MINIM). So, make sure that you don't run the step, e.g., on the result of a previous run (like data have; set have; ...). If dataset HAVE for some reason contains variables MINIM or SEQ_MINIM, just drop them via a dataset option:
set have(drop=minim seq_minim);
It's finally time to hack! Remember to visit the SAS Hacker's Hub regularly for news and updates.
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.
Ready to level-up your skills? Choose your own adventure.