Условное слияние в SAS - PullRequest
       10

Условное слияние в SAS

0 голосов
/ 12 апреля 2020

Привет всем, у меня есть два следующих набора данных, в которых мне нужно сопоставить Date1 с Date2 в диапазоне (+/- 7) дней в пределах идентификатора.

    Data set1;
    input ID  Date1 ddmmyy8.;
    Format Date1 Date11.;
    Datalines;
    001 02-08-15
    001 04-08-15
    001 06-08-15
    002 11-09-15
    002 14-09-15
    002 17-09-15
    ;
    run;

    Data set2;
    input ID TYPE $ Date2 ddmmyy8.;
    Format Date2 Date11.;
    Datalines;
    001 TYPE1 02-08-15
    001 TYPE2 11-08-15
    001 TYPE3 06-08-15
    002 TYPE1 07-09-15
    002 TYPE2 04-09-15
    002 TYPE3 09-08-15
    ;
    run;


    Proc sql;
create table out as select a.ID, a.Date1, b.Date2,
intck('days', Date1, Date2) as Diff
from set1 as a full join set2 as b
on a.ID = b.ID and (Date1 + 7 >= Date2 >= Date1 - 7)
group by a.ID, Date1 having diff = min(diff);
quit;

Я получаю следующий вывод enter image description here

мне нужен вывод enter image description here

Ожидаемый вывод

enter image description here

*** Вывод, который я получаю, выделяется желтым цветом, когда я отображаю с помощью мин. разл. но вывод, который мне нужен, выделен зеленым цветом, потому что я должен поддерживать значения в Date2 как отличные и не повторяться.

(т.е.), потому что 02-август-2015 уже сопоставлен с 02-август- 2015, а также 09 августа 2015 года, сопоставленный с 09 августа 2015 года Date1 Мне нужно, чтобы 04 августа 2015 года Date1 был сопоставлен с оставшимися 11 августа 2015 года ***

1 Ответ

0 голосов
/ 14 апреля 2020

Таким образом, судя по комментариям выше, правила довольно сложны: * объединение на основе идентификатора * Абсолютная разница между датой 1 и датой 2 должна быть меньше 7 * Предпочтение при сопоставлении дат следует отдавать равным датам * В случае даты не равны, решение должно быть таким, чтобы как можно больше возвращалось комбинаций * Date1 & Date2 должны быть уникальными

Я не уверен, что решение может быть выполнено в одном про c sql шаг. Вы не можете просто работать с простым правилом, так как это не всегда результат с наименьшей разницей между датами, которые необходимо вернуть. Кроме того, вам нужно отсортировать «запоминать», какие даты для каждого идентификатора вы выбрали для выходных данных, поскольку вы больше не можете их выбирать.

Сначала я сделал внутреннее соединение по идентификатору, где разница в датах было <= 7. Это дает все возможные действительные комбинации. Затем я поместил все даты, где разница в датах была 0, в макропеременную, чтобы я мог составить таблицу всех возможных комбинаций, кроме дат, находящихся в макропеременной. На последнем шаге вы хотите, чтобы решение возвращало наиболее возможные комбинации даты1 - даты2, где оба различны. </p>

 Data set1;
 input ID  Date1 ddmmyy8.;
 Format Date1 Date11.;
 Datalines;
 001 02-08-15
 001 04-08-15
 001 06-08-15
 002 11-09-15
 002 14-09-15
 002 17-09-15
 ;
 run;

Data set2;
input ID TYPE $ Date2 ddmmyy8.;
Format Date2 Date11.;
Datalines;
001 TYPE1 02-08-15
001 TYPE2 11-08-15
001 TYPE3 06-08-15
002 TYPE1 07-09-15
002 TYPE2 04-09-15
002 TYPE3 09-08-15
;
run;

Proc sql noprint;
/*Create a macro variable with all the dates for which the difference between date1 
and date2 = 0 */
select distinct put(Date1,yymmddn8.) into: dates seperated by ','
from set1 as a inner join set2 as b
on a.ID = b.ID and abs(intck('days', Date1, Date2)) = 0;

/*Create table with all lines where difference <= 7 but date is not in the ones with 
difference = 0 */
create table out as select a.ID, a.Date1, b.Date2,
intck('days', Date1, Date2) as Diff
from set1 as a inner join set2 as b
on a.ID = b.ID where abs(intck('days', Date1, Date2)) <= 7 and 
find("&dates.",put(Date1,yymmddn8.)) = 0 and find("&dates.",put(Date2,yymmddn8.)) = 0;

/* Check the number of possible combinations */
create table out as
select a.*,
       b.cnt1 + c.cnt2 as combos
from out a left join (select distinct id,
                                  date1,
                                  count(*) as cnt1
                      from out
                      group by id, date1) b on a.date1 = b.date1 and a.id = b.id
           left join (select distinct id,
                                   date2,
                                   count(*) as cnt2
                      from out
                      group by id, date2) c on a.date2 = c.date2 and a.id = c.id
          order by id, combos;
 quit;

/* Select unique dates per date1, date2 */
data out(keep = id date1 date2);
   retain mem1 mem2;
   length mem1 mem2 $100.;

 set out;

 by id combos;

  if first.id then do;
      mem1 = "0";
      mem2 = "0";
  end;

  date10 = put(date1,yymmddn8.);
  date20 = put(date2,yymmddn8.);

  if find(mem1,date10) = 0 and find(mem2,date20) = 0 then do;
      mem1 = catx(',',mem1,date10);
      mem2 = catx(',',mem2,date20);
      output;
  end;      
run;

/* Create a union between lines with no difference in date and lines with difference 
in date*/
proc sql;
    create table final as
    select * from out
    union
    select a.ID, a.Date1, b.Date2 
    from set1 as a inner join set2 as b
    on a.ID = b.ID and abs(intck('days', Date1, Date2)) = 0;
quit;

Так что получается таблица типа:

Финальный стол

...