Комплексное соединение в САС - PullRequest
0 голосов
/ 14 декабря 2018

Я пытаюсь объединить следующие два набора данных:

data testA;
input categorical $3. value;
*order = _n_;
datalines;
Dog. 
M  7
F  5
Cat.
M  4
F  2
;
run;

data testA;
set testA;
order=_n_;
run;

data testB;
input categorical $2. value;
datalines;
Dog. 
F  3
Cat.
M  1
F  2
;
run;

proc sql;
create table final as
select a.*,b.* from testA a left join testB b on 
a.categorical=b.categorical
order by order;
quit;

Мой желаемый вывод следующий:

data testA;
input categorical $ value value2;
datalines;
Dog . .
M 7 .
F 5 3
Cat . .
M 4 1
F 2 2
;
run;

Проблемы, с которыми я столкнулся, заключаются в том, что 1)«категорический» идентификатор не сортируется в алфавитном порядке, и я не хочу менять его порядок. 2) Поскольку есть два M и F, я не знаю, как присоединиться без переименования MF, чтобы он был уникальным. 3) Это может быть внутреннее объединение.поскольку то, что может быть в значении, может не быть в значении2

1 Ответ

0 голосов
/ 14 декабря 2018

Если ваши данные имеют значение категории в виде вкрапленной строки, вам необходимо создать третий столбец для хранения этих значений при обнаружении при прохождении набора данных.Для обсуждения назовите этот новый столбец group - он также будет категоричным и иерархически «выше» другого столбца категории.Это «синтетическая» категория, которая необходима для выполнения сложного объединения и будет исключена из окончательного результата.

Объединение want будет простым «черным ящиком», включающим группировку, объединение, скрытую математикуи групповая сумма суммы строк.

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

Пример данных:

data testA;
input categorical $3. value;
datalines;
Dog .   * missing means categorical is really group
M  7
F  5
Cat .
M  4
F  2
Rat .   * B does not have rat
T  5
Bat .   * Bat has two M (repeated category) need to be summed
M  7
M  3
Fly .
M  5
F  6
;
run;

data testB;
input categorical $3. value;
datalines;
Dog .   * only one category
F  3
Cat .
M  1
F  2
Cow .   * A does not have cow
X  7
Bat .   * Bat has two F (repeated category) need to be summed
F  7
F  13
Fly .   * F M order different than A
F  16
M  20
;
run;

Расширенные данные имеют столбец группы и информацию об исходном порядке:

data A2;
  set testA;
  if value = . then do;
    * presume missing is the 'discovery' of when the 
    * group value has to be assigned;
    group = categorical; retain group;
    group_order + 1;  
    value_order = 0;
  end;
  value_order + 1;
  format group_order value_order 4.;
run;

data B2; 
  set testB;
  if value = . then do;
    * presume missing is the 'discovery' of when the 
    * group value has to be assigned;
    group = categorical; retain group; 
    group_order + 1;
    value_order = 0;
  end;
  value_order + 1;
  format group_order value_order 4.;
run;

Операции соединения (просмотр данных)

* this full join shows how data matches up for the answer
* the answer will use grouping, coalescing, summing and adding;
proc sql;
  create table fulljoin_peek as
  select
    coalesce (A.categorical, B.categorical) as want_categorical
  , sum(A.value,B.value) as want_value format=4.
  , A.group as A_group
  , B.group as B_group
  , A.group_order as A_group_order
  , B.group_order as B_group_order
  , A.categorical as A_cat
  , B.categorical as B_cat
  , A.value as A_value
  , B.value as B_value
  , A.value_order as A_value_order
  , B.value_order as B_value_order
  from
    A2 as A
  full join 
    B2 as B
  on 
    A.group = B.group
    and A.categorical = B.categorical
;

Требуется соединение (ответ)

proc sql;
  create table

    want (drop=group_order value_order) as

  select 
    coalesce (A.categorical, B.categorical) as want_categorical
  , min (coalesce (A.group_order-1e6,B.group_order)) as group_order
  , min (coalesce (A.value_order-1e6,B.value_order)) as value_order   %* -1e6 forces A order to have precedence ;
  , sum ( sum (A.value,B.value) ) as value
  from
    A2 as A
  full join 
    B2 as B
  on 
    A.group = B.group
    and A.categorical = B.categorical
  group by 
    A.group, want_categorical
  order by 
    group_order,  value_order
  ;
...