data s ;
input subjid $ visit $ visit_num date:ddmmyy. ;
format date date9. ;
cards ;
101 visit1 1 07-01-2018
101 visit2 2 18-01-2018
101 unc 1 09-01-2018
101 visit3 3 26-01-2018
101 unc 3 03-02-2018
102 visit1 1 07-01-2018
102 visit2 2 18-01-2018
102 unc 3 26-01-2018
102 unc 1 08-01-2018
102 unc 4 03-02-2018
;
in above data has some unscheduled visit how to fill up
like see below
subjid | visit | visit_num | date | new_visit |
101 | visit1 | 1 | 07JAN2018 | 1 |
101 | unc | 1 | 09JAN2018 | 1.1 |
101 | visit2 | 2 | 18JAN2018 | 2 |
101 | visit3 | 3 | 26JAN2018 | 3 |
101 | unc | 3 | 03FEB2018 | 3.1 |
102 | visit1 | 1 | 07JAN2018 | 1 |
102 | unc | 1 | 08JAN2018 | 1.1 |
102 | visit2 | 2 | 18JAN2018 | 2 |
102 | unc | 3 | 26JAN2018 | 2.1 |
102 | unc | 4 | 03FEB2018 | 2.2 |
data want;
set have;
if visit^='unc' then new_visit=visit_num;
else if visit='unc' then new_visit+0.1;
run;
You don't say what should happen in there are more than 9 "unc" per visit, this method would fail in that case.
data s ;
input subjid $ visit $ visit_num date:ddmmyy. ;
format date date9. ;
cards ;
101 visit1 1 07-01-2018
101 visit2 2 18-01-2018
101 unc 1 09-01-2018
101 visit3 3 26-01-2018
101 unc 3 03-02-2018
102 visit1 1 07-01-2018
102 visit2 2 18-01-2018
102 unc 3 26-01-2018
102 unc 1 08-01-2018
102 unc 4 03-02-2018
;
proc sort data=s out=temp;
by subjid visit_num;
run;
data temp;
set temp;
by subjid;
if first.subjid then group=0;
if visit=: 'visit' then group+1;
run;
data want;
set temp;
by subjid group;
if first.group then m=-1;
m+1;
if first.visit_num then new_visit=put(visit_num,best8. -l);
else new_visit=catx('.',visit_num,m);
drop m;
run;
data s ;
input subjid $ visit $ visit_num date:ddmmyy. ;
format date date9. ;
cards ;
101 visit1 1 07-01-2018
101 visit2 2 18-01-2018
101 unc 1 09-01-2018
101 visit3 3 26-01-2018
101 unc 3 03-02-2018
102 visit1 1 07-01-2018
102 visit2 2 18-01-2018
102 unc 3 26-01-2018
102 unc 1 08-01-2018
102 unc 4 03-02-2018
;
proc sort data=s out=temp;
by subjid visit_num;
run;
data temp;
set temp;
by subjid;
if first.subjid then group=0;
if visit=: 'visit' then group+1;
run;
data want;
set temp;
by subjid group;
if first.group then m=-1;
m+1;
if first.group then new_visit=put(group,best8. -l);
else new_visit=catx('.',group,m);
drop m group;
run;
data s;
input subjid $ visit $ visit_num date:ddmmyy.;
format date date9.;
cards;
101 visit1 1 07-01-2018
101 visit2 2 18-01-2018
101 unc 1 09-01-2018
101 visit3 3 26-01-2018
101 unc 3 03-02-2018
102 visit1 1 07-01-2018
102 visit2 2 18-01-2018
102 unc 3 26-01-2018
102 unc 1 08-01-2018
102 unc 4 03-02-2018
;
proc sort data=s out=h1;
by subjid date;
run;
data want;
set h1;
retain _base _unit;
if visit=:'visit' then
do;
new_visit=visit_num;
_base=visit_num;
_unit=0;
end;
else
do;
_unit+0.1;
new_visit=_base+_unit;
end;
drop _:;
run;
I'd like to point out that creating NEW_VISIT as a numeric variable involves the risk of numeric representation issues. (I worked on a clinical research project where exactly this had happened.)
Example (SAS log):
1 data bad; 2 new_visit=1.1; 3 new_visit+0.1; 4 if new_visit=1.2; 5 run; NOTE: The data set WORK.BAD has 0 observations and 1 variables.
So, if it must be numeric (e.g. following CDISC recommendations on VISITNUM), precautions should be taken to ensure "clean" values, i.e. standard internal representations of 1.1, 1.2, etc. This can be achieved using the ROUND function, e.g.
new_visit=round(new_visit, 1e-8);
(or apply the ROUND function already when NEW_VISIT is assigned a calculated value).
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.