SAS находит перекрывающиеся даты и добавляет флаг

У меня есть набор данных на уровне идентификатора с некоторыми перекрывающимися датами. Все, что мне нужно, чтобы найти эти строки и добавить идентификатор для подсчета количества перекрывающихся записей.

   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, чтобы найти тот же идентификатор и вычесть даты, но решил, что это неправильный способ.

Я ценю вашу помощь здесь. Спасибо

Работа с датами и временем в языке Java
Работа с датами и временем в языке Java
Работа с датами и временем в языке Java была сильно переработана начиная с версии Java 8 и далее с появлением библиотеки java.time.
1
0
52
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Значения даты 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;

Очень впечатляющий способ!

whymath 08.02.2023 06:57

Расширь, посчитай и снова сольйся, вот моя мысль.

*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

Другие вопросы по теме