SAS - Proc SQL или Merge - Попытка оптимизировать INNER соединение, которое включает поиск строки (индекс) - PullRequest
0 голосов
/ 04 октября 2019

У меня есть элементарный набор навыков SAS, большинство из которых включает "proc sql", поэтому не стесняйтесь оспаривать фундаментальный подход к его использованию.

Я пытаюсь сопоставить один набор личных данных сдругой набор, первый имеет около 400 тыс. строк, а остальные 22 миллиона. Сложность состоит в том, что строки 400 КБ содержат предыдущие имена и почтовые индексы, а также текущие (все в одной строке), поэтому мой подход (код ниже) состоял в том, чтобы объединить все фамилии вместе и все почтовые индексы вместе и найтистрока из второй таблицы (одно имя и почтовый индекс) в соединенных строках с использованием функции индекса (источник, отрывок).

proc sql;
CREATE TABLE R4 AS
SELECT DISTINCT
BS.CUST_ID,
ED.MATCH_ID
FROM T_RECS_WITH_CONCATS BS
INNER JOIN T_RECS_TO_MATCH ED
ON LENGTH(ED.SinglePostcode) > 4
AND index(BS.AllSurnames,ED.SingleSurname) > 0
AND index(BS.AllPostcodes,ED.SinglePostcode) > 0
;
QUIT;

В приведенном выше примере все имена могут содержать до 9 фамилий (разделенных |)и AllPostcodes - до 9 сцепленных почтовых индексов (опять же, разделенных |).

Недостатком этого является, конечно, то, что для его запуска требуется вечность. Есть ли более эффективный способ сделать это, либо на шаге proc sql, либо на шаге реальных данных?

1 Ответ

0 голосов
/ 05 октября 2019

Вот способ использования объектного компонента HASH

Предполагается, что наборы данных имеют имена SHORT_MANY и TALL_ONE. Используйте данные в SHORT_MANY для заполнения хеш-таблицы из нескольких данных, которая может работать как поиск значений, проверяемых в TALL_ONE.

Использование только фамилии и почтового кода в качестве ключа поиска может привести к множеству ложных совпадений.

Пример (с числовой фамилией и почтовым индексом)

data SHORT_MANY;
  do cust_id = 1 to 400;
    array Surnames  surname1-surname9;
    array Postcodes postcode1-postcode9;

    call missing (of surnames(*));
    do index = 1 to dim(surnames);
      surnames(index)  = ceil (100000 * ranuni(123));
      postcodes(index) = ceil ( 99999 * ranuni(123));
      if ranuni(123) < 0.15 then leave;
    end;

    output;
  end;
run;

data TALL_ONE(keep=match_id surname postcode forcemark);
  do match_id = 1 to 22000;

    surname  = ceil(100000 * ranuni(1234));
    postcode = ceil( 99999 * ranuni(1234));
    forcemark = .;


    if ranuni(123) < 0.15 then do;  * randomly ensure some match will occur;
      point = ceil(400*ranuni(123));
      set SHORT_MANY point=point;
      array surnames surname1-surname9;
      array postcodes postcode1-postcode9;
      do until (surname ne .);
        index = ceil(9 * ranuni(123));
        surname = surnames(index);
        postcode = postcodes(index);
      end;
      forcemark = point;
    end;

    output;
  end;

  stop;
run;

data WHEN_TALL_MEETS_SHORT(keep=cust_id match_id index);

  if 0 then set TALL_ONE SHORT_MANY ; * prep pdv (for hash host variables);

  if _n_ = 1 then do;
    length index 8;

    declare hash lookup(multidata: 'yes');
    lookup.defineKey('surname', 'postcode');
    lookup.defineData('cust_id', 'index');
    lookup.defineDone();

    do while (not lookup_filled);
      SET SHORT_MANY end=lookup_filled;

      array Surnames  surname1-surname9;
      array Postcodes postcode1-postcode9;

      do index = 1 to dim(surnames) while (surnames(index) ne .);
        surname = surnames(index);
        postcode = postcodes(index);

        lookup.add();
      end; 
    end;
  end;

  call missing (surname, postcode, cust_id, index);

  set TALL_ONE;
  rc = lookup.find(); * grab just first match -- has_next/find_next to retrieve other lookup matches;
run;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...