/**************************************************************************** * Macro name : sccs * * Version : 12.04 * * Author : Bart Spiessens * * Date : 20DEC2004 * * ------------------------------------------------------------------------ * * Revisions : Versions Date Author * * * * 12.00 20DEC2004 Bart Spiessens * * Creation of the macro * * 12.01 02FEB2005 Bart Spiessens * * Remove errors: 'pid' replaced by '&pid' at some places * * Changed the end of the risk period when there is * * overlapping intervals (endva&i.&j = vac&i1+&risk1-1 * * instead of endva&i.&j = vac&i1-1) * * Add overlap parameter to allow overlapping intervals * * 12.02 02MAR2005 Bart Spiessens * * Agerange is expressed in days instead of years * * endobs = min(&endst,&dob_raw + &maxage-1)-&dob_raw; * * changed to * * endobs = min(&endst,&dob_raw + &maxage)-&dob_raw; * * 12.03 31MAR2005 Bart Spiessens * * Allow empty values for age and season * * 12.04 01APR2005 Bart Spiessens * * Include semi-parametric analysis * * ------------------------------------------------------------------------ * * Description : Macro to create dataset for case series analysis * * ------------------------------------------------------------------------ * * INPUT - parameters * * * * data : Input dataset * * pid : subject ID number * * dob_raw : Date of birth * * events : Dates for events * * vacc : Dates for vaccinations * * startst : Study start * * endst : Study end * * covars : Covariates to be put in output dataset * * overlap : Allow overlapping risk intervals (Default=N) * * * * INPUT - macros variables (other than standards) * * * * agerange : e.g., 0 730 (in days) * * risk : risk periods after vaccination, e.g., 0 6 7 14 * * (first period from 0 to 6 days * * and a second period from 7 to 14 days) * * age : age cutpoints for age covariates in model, * * e.g., 90 180 270 360 * * season : season cutpoints for season covariates in model, * * e.g., 31MAR 30JUN 30SEP 31DEC * * * * INPUT - datasets from lib_data * * * * * * INPUT - datasets from work * * * * ------------------------------------------------------------------------ * * OUTPUT - macros variables * * * * * * OUTPUT datasets in work * * * * wk_sccs * * This dataset contains a class variable for age and indicator variables* * for the different risk periods: * * RISK = 1 if the interval lies in a risk period * * RISKVi = 1 if the interval lies in a risk period after dose i * * RISKRj = 1 if the interval lies in the jth risk period over all * * doses * * RISKk = 1 if the interval lies in the kth risk period (each risk * * period after each dose has a separate indicator variable) * * When overlap=Y, overlapping intervals are possible and these * * variables should be used with caution * * ------------------------------------------------------------------------ * * UPDATE - table * * * ****************************************************************************/ %MACRO sccs(data=, pid=pid, dob_raw=, events=, vacc=, startst=, endst=, covars=, overlap=N, outdata=) /* / STORE DES='Create dataset for SCCS' */; %GLOBAL nb_risk nb_vacc; %LET semi = %UPCASE(&semi); %LET overlap = %UPCASE(&overlap); %element(lstvar=&vacc , pref = vacc); %element(lstvar=&events , pref = evt); %element(lstvar=&risk , pref = risk); %LET nb_risk = %EVAL(&nb_risk/2); %IF &semi=Y %THEN %DO; DATA _events; SET &data; ARRAY x(*) &events; DO i=1 TO dim(x); IF x[i] NE . THEN DO; y = x[i]; OUTPUT; END; END; RUN; PROC SQL NOPRINT; SELECT DISTINCT y INTO :age SEPARATED BY ' ' FROM _events; QUIT; %PUT &age; %END; %IF &age = %THEN %DO; %LET age = -1; %END; %element(lstvar=&age , pref = age); %IF &season = %THEN %DO; %LET season = 31DEC; %END; %element(lstvar=&season , pref = season); %IF &agerange NE %THEN %DO; %LET minage = %SCAN(&agerange,1,' '); %LET maxage = %SCAN(&agerange,2,' '); %END; PROC SQL NOPRINT; SELECT min(put(&startst,year4.)) INTO :year1 FROM &data; SELECT max(put(&endst,year4.)) INTO :year2 FROM &data; QUIT; /* %PUT &year1; %PUT &year2; */ DATA wk_sccs; SET &data; %IF &dob_raw= %THEN %DO; %LET dob_raw=_dob; _dob=0; %END; *KEEP &pid &dob_raw &events &vacc &startst &endst &covars; **setting the season cut-points; %DO i=&year1 %TO &year2; %DO j=1 %TO &nb_season; ss&i.&j = (input("&&season&j"||"&i",date9.)-&dob_raw); %END; %END; RUN; DATA wk_sccs; SET wk_sccs; %IF &agerange NE %THEN %DO; **observation period for each subject will start at the beginning of the study period or date of the minimum eligible age in the age range, whichever is later; startobs = max(&startst,&dob_raw + &minage)-&dob_raw; **age at start of obs period; **observation period was going to end at the end of the study period or the day specified in maxage, whichever is earlier; endobs = min(&endst,&dob_raw + &maxage)-&dob_raw; **age at end of obs period; %END; %ELSE %DO; startobs = &startst-&dob_raw; endobs = &endst-&dob_raw; %END; **setting the vaccination cut-points; %DO i = 1 %TO &nb_vacc; vac&i = &&vacc&i-&dob_raw; %END; **setting the IS (event) cut-points; %DO i = 1 %TO &nb_evt; event&i = &&evt&i-&dob_raw; %END; RUN; ** The observation period will be chopped up into intervals at each event (i.e. start of obs period, vaccine doses, age cut points, end of obs period). These intervals will not include the lower value and will include the upper value. Therefore, the following code re-sets the lower value of each interval to the original lower value minus 1, so that the original value will be the first value included in the interval. The following code also sets the risk periods after each vaccination...if the next dose is not given or the next dose falls after the risk period for the current dose is over, then the end of the risk period for the current dose is the start of the interval for the current vaccine dose plus the length of the risk period. If the next dose is given and it falls within the risk period of the current dose, then the end of the risk period for the current dose should be the day before the next dose. ; DATA wk_sccs; SET wk_sccs; begin = startobs-1; **begin=start of 1st interval; %DO i=1 %TO &nb_vacc; %DO j=1 %TO &nb_risk; %LET i1 = %EVAL(&i+1); %LET jb = %EVAL(&j*2-1); %LET je = %EVAL(&j*2); %IF &overlap = N %THEN %DO; IF vac&i1 = . OR (vac&i1+&risk1 > vac&i+&&risk&je) THEN DO; st_va&i.&j = vac&i+&&risk&jb-1; **startva1=start of interval for vaccine dose 1; endva&i.&j = (vac&i + &&risk&je); END; ELSE IF (vac&i1+&risk1 > vac&i+&&risk&jb) THEN DO; st_va&i.&j = vac&i+&&risk&jb-1; /* endva&i.&j = vac&i1-1; */ /* this is wrong, the risk period should go over the vaccination if the risk period does not start at vaccination (&risk1 = 0) */ endva&i.&j = vac&i1+&risk1-1; END; ELSE DO; st_va&i.&j = .; endva&i.&j = .; END; %END; %ELSE %IF &overlap = Y %THEN %DO; st_va&i.&j = vac&i+&&risk&jb-1; **startva1=start of interval for vaccine dose 1; endva&i.&j = (vac&i + &&risk&je); %END; %END; %END; * DROP start; RUN; /* Creating a dataset of 1 record per interval...setting a variable 'stop' to be equal to each 'cut point' if that cut point is within the observation period. */ DATA wk_sccs; SET wk_sccs; %DO i=1 %TO &nb_age; age&i = &&age&i; %END; %DO i=1 %TO &nb_season; season&i = input("&&season&i"||"2000",date9.)-input("01JAN2000",date9.)+1; %END; ARRAY x(*) begin endobs %DO i=1 %TO &nb_age; age&i %END; %DO i=1 %TO &nb_vacc; %DO j=1 %TO &nb_risk; st_va&i.&j endva&i.&j %END; %END; %DO i=&year1 %TO &year2; %DO j=1 %TO &nb_season; ss&i.&j %END; %END; ; FORMAT stopdate date9.; DO i=1 TO DIM(x); IF x[i] NE . AND x[i] >= begin AND x[i] <= endobs THEN DO; stop = x[i]; stopdate = x[i] + &dob_raw; dayyear = stopdate-input("01JAN"||trim(left(year(stopdate))),date9.)+1; age = 0 %DO i=1 %TO &nb_age; + (stop > age&i) %END; ; season = 0 %DO i=1 %TO &nb_season; + (dayyear > season&i) %END; ; IF season = &nb_season THEN season = 0; OUTPUT; END; END; RUN; /*sort by pid and date order of cut points*/ PROC SORT DATA=wk_sccs; BY &pid stop; RUN; /* In the dataset of 1 record per interval...setting a variable 'start' to be equal to the 'cut point' ('stop' value) of the interval before. If it's the first interval for the pid, then 'start' will be the start of the obs period (the variable begin). The offset variable is created to equal the length of each interval. */ DATA wk_sccs; RETAIN &pid &dob_raw start stop nevt offset &covars age season risk %DO i=1 %TO &nb_risk; riskR&i %END; %DO i=1 %TO &nb_vacc; riskV&i %END; %DO i=1 %TO %EVAL(&nb_vacc*&nb_risk); risk&i %END; ; SET wk_sccs; BY &pid; start = lag(stop); IF first.&pid THEN start = begin; IF stop=start THEN DELETE; **deleting intervals of no length; offset = (stop-start); **offset=length of each interval; l_off = log(offset); **l_off=ln(offset); nevt = 0; %DO i=1 %TO &nb_evt; nevt = nevt + (start < event&i <= stop); **=1 if IS in interval, =0 if not; %END; **risk=1 if the interval falls within any of the vaccination risk periods; %DO i=1 %TO &nb_vacc; %DO j=1 %TO &nb_risk; %LET l = %EVAL((&i-1)*&nb_risk+&j); risk&l = (st_va&i.&j <= start AND stop <= endva&i.&j); %END; %END; %DO j=1 %TO &nb_risk; riskR&j = (0=1) %DO i=1 %TO &nb_vacc; OR (st_va&i.&j <= start AND stop <= endva&i.&j) %END; ; %END; %DO i=1 %TO &nb_vacc; riskV&i = (0=1) %DO j=1 %TO &nb_risk; OR (st_va&i.&j <= start AND stop <= endva&i.&j) %END; ; %END; risk = 0 %DO i=1 %TO &nb_risk; + riskR&i %END; ; int = 1; RUN; %IF &outdata= %THEN %DO; %LET outdata=wk_sccs; %END; DATA &outdata; SET wk_sccs; KEEP &pid &dob_raw start stop offset l_off int &covars age nevt season risk %DO i=1 %TO &nb_risk; riskR&i %END; %DO i=1 %TO &nb_vacc; riskV&i %END; %DO i=1 %TO %EVAL(&nb_vacc*&nb_risk); risk&i %END; ; **this is the end of the KEEP statement; RUN; %IF &semi=Y %THEN %DO; DATA &outdata; SET &outdata; IF stop IN (&age); DROP start offset l_off; RUN; %END; %MEND sccs;