Obsidian | Level 7

## Altering a do loop to make unequal intervals

Hello All,

I am using SAS 9.4.

I worked with a more SAS savvy person than myself on this code and I need to make a few changes to the do loop. I am having a problem changing the %do loop in blue in the following code.

I want to change the incident variable in %do loop.

Currently, incident = 1 if an event occurs within a specific 365.25 period after visitdate.

incident=(%eval(&i-1)*365.25<=(&outcome-visitdate)<&i*365.25); where i=1 to 10

I need to change this to only do

incident=(0*365.25<=(&outcome-visitdate)<4*365.25);

incident=(4*365.25<=(&outcome-visitdate)<7*365.25);

incident=(7*365.25<=(&outcome-visitdate)<10*365.25);

__________________________________

%let outcome=event;  /*date variable*/

/*transpose data set from wide to long*/

%macro outcome;

data second;

set first;

array fox {*} fox1 fox2 fox3 fox4;

array rabbit {*} rabbit1 rabbit2 rabbit3 rabbit4;

array dog {*} dog1 dog2 dog3 dog4;

array date{*} date1 date2 date3 date4;

do i=1 to dim(fox);

visit=i+2;

foxvar=fox(i);

rabbitvar=rabbit(i);

dogvar=dog(i);

visitdate=date(i);

if ^(&outcome=.) then output;

end;

run;

%do i=1 %to 10;

/* INCIDENT=0 prior to the event, */

/* 1 at the event, missing otherwise(after event occurred) */

data second;

set second;

by id visit;

drop switch;

retain switch;

if first. id then switch=0;

if switch=1 then incident=.;

if ^missing(&outcome) and ^missing(&outcome) and switch=0 then do;

incident=(%eval(&i-1)*365.25<=(&outcome-visitdate)<&i*365.25);

end;

if incident=1 then switch=1;

run;

%end;

...

%mend;

%outcome;

There is more to the macro code as it drops the ID in the following period after it has had the event in the current interval.

________________________________________

I have tried without success the following 2 strategies

...

%do i=1 %to 9;

data second;

set second;

...

when i = 1 do;

incident=0*365.25<=(&outcome-visitdate)<4*365.25);

end;

when i=4 do;

incident=4*365.25<=(&outcome-visitdate)<7*365.25);

end;

when i=7 do;

incident=7*365.25<=(&outcome-visitdate)<9*365.25);

end;

when i=2 or i=3 or i=5 or i=6 or i=8 or i=9 do incident = 0;

and also

...

%do i={0,4 7};

%do j={4 7 9};

data second;

set second;

...

incident=(%eval(&i)*365.25<=(&outcome-visitdate)<(&j)*365.25);

__________

Any help would be appreciated!!

3 REPLIES 3
Tourmaline | Level 20

## Re: Altering a do loop to make unequal intervals

Like this?

%do i=1 %to 3;
/* INCIDENT=0 prior to the event, */
/* 1 at the event, missing otherwise(after event occurred) */
data second;
set second;
by id visit;
drop switch;
retain switch;
if first. id then switch=0;
if switch=1 then incident=.;
if ^missing(&outcome) and switch=0 then do;
if &i=1 then incident=(0*365.25<=(&outcome-visitdate)<4*365.25);
if &i=2 then incident=(4*365.25<=(&outcome-visitdate)<7*365.25);
if &i=3 then incident=(7*365.25<=(&outcome-visitdate)<10*365.25);
end;
if incident=1 then switch=1;
run;
%end;

Obsidian | Level 7

## Re: Altering a do loop to make unequal intervals

I tried this and incident only has 1 level (0 and missing). which is odd because there are instances where incident should be 1.

Super User

## Re: Altering a do loop to make unequal intervals

Why are you running the same DATA step inside a macro %DO loop?

What is the purpose?

Why do you want to change

incident=(0*365.25<=(&outcome-visitdate)<1*365.25);
incident=(1*365.25<=(&outcome-visitdate)<2*365.25);
incident=(2*365.25<=(&outcome-visitdate)<3*365.25);

to

incident=(0*365.25<=(&outcome-visitdate)<4*365.25);
incident=(4*365.25<=(&outcome-visitdate)<7*365.25);
incident=(7*365.25<=(&outcome-visitdate)<10*365.25);

Why is the first interval 4 years and the others only 3? Shouldn't that be:

incident=(0*365.25<=(&outcome-visitdate)<3*365.25);
incident=(3*365.25<=(&outcome-visitdate)<6*365.25);
incident=(6*365.25<=(&outcome-visitdate)<9*365.25);

If so then use:

incident=(3*(&i-1)*365.25<=(&outcome-visitdate)<3*&i*365.25);

To implement arbitrary boundaries you could just use a list of the cut points.  Just pull the boundaries for the current iteration.

%let cuts=0 4 7 10;
%do i=1 %to %sysfunc(countw(&cuts))-1;
....
incident=(3*%scan(&cuts,&i-1)*365.25<=(&outcome-visitdate)<3*%scan(&cuts,&i)*365.25);
....
%end;
Discussion stats
• 3 replies
• 531 views
• 0 likes
• 3 in conversation