如何将SAS中组合的观察分组

时间:2018-01-29 15:57:37

标签: sas combinations

一个例子是数据集:

data have;
input observations $;
datalines;
'a-b-c'
'b-c-a'
'c-a-b'
'd-e'
'e-d'
'a-b'
'a-b-c-d'
'b-a-d-c'
'a-b-c-e'
;
run;

我不确定如何将所有彼此组合的观察结果映射到某种类型的combo_id。所需数据的示例:

'a-b-c'    combo_1
'b-c-a'    combo_1
'c-a-b'    combo_1
'd-e'      combo_2
'e-d'      combo_2
'a-b'      combo_3
'a-b-c-d'  combo_4
'b-a-d-c'  combo_4
'a-b-c-e'  combo_5

此时我可以通过sql中的combo_id进行分组...

3 个答案:

答案 0 :(得分:1)

以下是我将如何解决这个问题:

首先,获取组中的最大元素数。

proc sql noprint;
select max(countw(observations,"-"))
    into :max trimmed
    from have;
quit;

然后使用数据步骤对每个观察中的元素进行排序。

data have;
set have;
format v1-v&max $8.
       observation_new $32.;
array v[&max];

/*remove ' and count the number in the group*/
observations = strip(tranwrd(observations,"'",""));
n = countw(observations,"-");

/*Split the elements into the array*/
do i=1 to n;
    v[i] = scan(observations,i,"-");
end;

/*Sort the array*/
call sortc(of v[*]);

/*Build a new observations record with the sorted values*/
observation_new = "";
do i=1 to &max;
    if v[i] ^= "" then
        observation_new = strip(catx("-",observation_new,v[i]));
end;

drop i n v:;
run;

现在对新观察进行排序,并使用数据步骤分配组合ID

proc sort data=have;
by observation_new;
run;

data want;
set have;
by observation_new;
retain combo_id 0;

if first.observation_new then
    combo_id = combo_id +1;
run;

这会给你:

observations    observation_new                     combo_id

  a-b           a-b                                     1
  a-b-c         a-b-c                                   2
  b-c-a         a-b-c                                   2
  c-a-b         a-b-c                                   2
  a-b-c-d       a-b-c-d                                 3
  b-a-d-c       a-b-c-d                                 3
  a-b-c-e       a-b-c-e                                 4
  d-e           d-e                                     5
  e-d           d-e                                     5

答案 1 :(得分:0)

方式1

在组合基础上使用N apriori已知元素,您可以创建所有可能组合排列的查找表。查询表中的项目数在8之后升级,其中有109,600(由Wolfram Alpha计算。)

好处是组合id可以通过在数据的单次传递中查找来应用。没有额外操纵所需的observation值。对于干净的大容量数据,这种方法可能是最好的。

%macro all_combo_perm(items=, out=, delim=-);

  %local i j N;

  data _null_;
    count = 0;
    do v = &items;
      count + 1;
    end;
    call symputx('N', count);
  run;

  data &out;
    array items(&N) $32 ( &items );

    %do i = 1 %to &N;
      array items_subset&i items1-items&i;
    %end;

    do i = 1 to &N;
      do j = 1 to comb(&N, i);
        call allcomb(j, i, of items(*));
        combo_id + 1;
        length combo_perm $100;

        do p = 1 to fact(i);
          select (i);
          %do i = 1 %to &N;
            when (&i) do; 
              call allperm(p, of items_subset&i(*));
              combo_perm = catx("&delim", of items_subset&i(*));
            end;
          %end;
          otherwise;
          end;

          output;
        end;

        if i > 1 then do; x=items[1]; items[1]=items[2]; items[2]=x; end;
      end;
    end;

    keep combo_id combo_perm;
  run;

%mend;

options mprint;

%all_combo_perm(items=%str('a','b','c','d','e'), out=combo_perms);

id通过哈希查找应用

data want;
  if _n_ = 1 then do;
    if 0 then set combo_perms;
    declare hash lookup(dataset:'combo_perms', hashexp:10);
    lookup.defineKey('combo_perm');
    lookup.defineData('combo_id');
    lookup.defineDone();
  end;

  set have;
  if lookup.find(key:observation) ne 0 then combo_id = -1;

  drop combo_perm;
run;

方式2

  • 两次通过。
  • 第一遍确定存在的不同observation值,并计算拥有的组合ID。
  • 第二遍通过查找或合并来应用组合ID。

DomPazz的回答就是这样的。

好处是它适用于手头的数据,不需要aprioris。对于大容量数据,两次传递可能会更慢。

方式3

在传递期间构建动态查找。

使用Dom的split和sort方法构造查找键,并将其存储在单次传递期间维护的查找哈希中。不利的是,用于构建每行数据的密钥的时间资源在大容量数据中可能会变得非常重要。

需要理解的是,call missing要重置部分,要catx('-', of parts(*))来构建密钥。

data want_3;
  set have;

  if _n_ = 1 then do;
    length combo_id 8;
    declare hash lookup(hashexp:10);
    lookup.defineKey('observation_key');
    lookup.defineData('combo_id');
    lookup.defineDone();
    call missing (combo_id);
    observation_key = observation; * prep pdv;
  end;

  array parts (99) $32 _temporary_;  * 99 is reasonable never to be exceeded bound;
  call missing (of parts(*));

  do i = 1 to dim(parts);
    parts(i) = scan(observation,i,"-");
    if missing(parts(i)) then leave;
  end;

  if i = dim(parts) then do;
    put 'ERROR: need more part slots!';
    stop;
  end;

  call sortc(of parts[*]);
  observation_key = catx('-', of parts(*)); * catx will not concatenate missing values;

  if lookup.find() ne 0 then do;
    combo_id = lookup.num_items + 1;
    lookup.add();
  end;

  drop i observation_key;
run;

答案 2 :(得分:-1)

data have;
input x $20.;
cards;
a-b-c
b-c-a
c-a-b
d-e
e-d
a-b
a-b-c-d
b-a-d-c
a-b-c-e
;
run;


data want;
   set have;
   retain string grp num;
   if countw(x) ^=num then do;
        grp+1;
        string=x;
   end;
   else do;
      array var [5] $1 _temporary_;
      call missing (of var(*));
      do i=1 to countw(x);
         var(i)=scan(x,i);
      end;
   call sortc(of var(*));
   _string=catx('-',of var(*));
   if _string^=string then grp=grp+1;
   end;
   group=cats('Comb_',grp);
   num=countw(x);
   if not missing (_string) then string=_string;
   else string=x; 
   keep x group;
run;