У меня есть набор данных на уровне идентификатора с некоторыми перекрывающимися датами. Все, что мне нужно, чтобы найти эти строки и добавить идентификатор для подсчета количества перекрывающихся записей.
Data:
ID ITEM StrDate EndDate
1001 A121 02/01/2022 02/15/2022
1001 B121 03/10/2022 03/10/2022
1002 C121 02/01/2022 02/10/2022
1002 D121 02/05/2022 02/15/2022
1003 E121 03/10/2022 03/21/2022
1003 F121 03/12/2022 03/21/2022
1004 G121 01/12/2022 01/14/2022
Ниже приведен результат, который я ожидаю
Want:
ID ITEM StrDate EndDate Indicator
1001 A121 02/01/2022 02/15/2022 N
1001 B121 03/10/2022 03/10/2022 N
1002 C121 02/01/2022 02/10/2022 Y
1002 D121 02/05/2022 02/15/2022 Y
1003 E121 03/10/2022 03/21/2022 Y
1003 F121 03/12/2022 03/21/2022 Y
1004 G121 01/12/2022 01/14/2022 N
Сначала я попытался отсортировать данные по StrDate
и EndDate
.
Proc sort data=Data; by ID StrDate EndDate;run;
Затем я попытался использовать функцию lag
, чтобы найти тот же идентификатор и вычесть даты, но решил, что это неправильный способ.
Я ценю вашу помощь здесь. Спасибо
Значения даты SAS — это целые числа, которые можно использовать в качестве индекса в массиве отслеживания. Этот метод называется поиском по прямому индексу.
Пример:
Двойное решение DOW может быть закодировано для поиска перекрывающихся записей. Первый цикл помечает используемые даты, а второй цикл оценивает диапазон на предмет перекрытия, находя флаг с помощью прямого индекса.
data have;
input ID ITEM $ StrDate EndDate;
attrib strdate enddate format=mmddyy10. informat=mmddyy10.;
datalines;
1001 A121 02/01/2022 02/15/2022
1001 B121 03/10/2022 03/10/2022
1002 C121 02/01/2022 02/10/2022
1002 D121 02/05/2022 02/15/2022
1003 E121 03/10/2022 03/21/2022
1003 F121 03/12/2022 03/21/2022
1004 G121 01/12/2022 01/14/2022
;
data want;
array tracker(100000) _temporary_ ;
do _n_ = 1 by 1 until (last.id);
set have;
by id;
do _i_ = strdate to enddate;
tracker(_i_) + 1; /* flag date using direct-index */
end;
end;
do _n_ = 1 to _n_;
set have;
/* no overlap would mean no dates in range would find a flag set */
/* and loop would exit with _i_ > enddate */
do _i_ = strdate to enddate while (tracker(_i_) = 1);
end;
length overlap_indicator $1;
overlap_indicator = ifc (_i_ > enddate, 'N', 'Y');
output;
end;
call missing (of tracker(*));
drop _: ;
run;
Расширь, посчитай и снова сольйся, вот моя мысль.
*An extra observation added to ID 1002;
data have;
input ID $ ITEM $ StrDate mmddyy10. +1 EndDate mmddyy10.;
format StrDate EndDate mmddyy10.;
cards;
1001 A121 02/01/2022 02/15/2022
1001 B121 03/10/2022 03/10/2022
1002 C121 02/01/2022 02/10/2022
1002 D121 02/05/2022 02/15/2022
1002 D121 03/05/2022 03/15/2022
1003 E121 03/10/2022 03/21/2022
1003 F121 03/12/2022 03/21/2022
1004 G121 01/12/2022 01/14/2022
;
run;
*Extend;
data middle;
set have;
do date=StrDate to EndDate;
output;
end;
run;
*Count and remerge;
proc sql noprint;
create table want as
select distinct a.*, ifc(b.count and a.StrDate<=b.date<=a.EndDate,'Y','N') as Indicator
from have as a
left join (
select id, date, count(date) as count from middle
group by id, date
having count>1
) as b on a.id=b.id
;
quit;
Кстати, если не все записи совпадают по датам одного идентификатора, но вы хотите пометить их все, вам нужно изменить условие поиска в таблице, удалив a.StrDate<=b.date<=a.EndDate
.
Простая логика перекрытия:
proc sql;
create table want as
select
a.*,
/* simple overlap logic */
case
when a.strdate <= b.strdate & a.enddate >= b.strdate then 'Y'
when b.strdate < a.strdate & b.enddate >= a.strdate then 'Y'
else 'N'
end as overlap
from
have a
left join
have b
on a.id = b.id /* join on same ids */
and a.item <> b.item /* but not the same item */
;
quit;
Результат:
ID ITEM StrDate EndDate overlap
1001 B121 03/10/2022 03/10/2022 N
1001 A121 02/01/2022 02/15/2022 N
1002 D121 02/05/2022 02/15/2022 Y
1002 C121 02/01/2022 02/10/2022 Y
1003 E121 03/10/2022 03/21/2022 Y
1003 F121 03/12/2022 03/21/2022 Y
1004 G121 01/12/2022 01/14/2022 N
Перекрытие происходит, если StartA <= StartB, когда:
StartA EndA>=StartB
|-------------|
|---------
StartB
Очень впечатляющий способ!