如何用数组水平排序变量和使用调用sortc



sasprofessionals.net上的一个用户遇到了一个问题,即无法通过几个变量对他的数据集进行分组,其中变量值在观察中是可互换的,因为它们具有相同的含义。

在示例数据集中,观测2、3和7是相同的,因为它们的Stat1到Stat3的值都是A14、A14和A10,只是顺序不同。这些应该按计数分组。观察结果5和6形成了另一组,应该用计数来总结。

示例数据集:

Obs Stat1 Stat2 Stat3 Count
1   A14   A14   A14   53090
2   A14   A14   A10   6744
3   A14   A10   A14   5916
4   A01   A01   A01   4222
5   A10   A10   A10   3085
6   A10   A10   A10   2731
7   A10   A14   A14   2399

期望输出:

Obs Stat1 Stat2 Stat3 Count
1   A14   A14   A14   53090
4   A01   A01   A01   4222
6   A10   A10   A10   5816
7   A10   A14   A14   15059

实际的数据集更大更复杂。我不知道用户是否尝试了任何方法来解决这个问题。

这个问题最初发布在sasprofessionals.net上,为了社区的利益,它被复制到StackOverflow。它被改变以满足StackOverflow Q&A标准

这就是我解决用户问题的答案。一般来说,我将Stat1-Stat3加载到一个数组中,使用sortc调用函数对数组进行排序,然后通过一个临时ID对其进行汇总,该ID是由排序后的Stat1-Stat3数组构造的。

/* Loading the data into SAS dataset */ 
/* Loading Stat1-Stat3 into an array */
/* Sorting stat1-stat3 creating a new ID */
data have; 
input obs stat1 $ stat2 $ stat3 $ count; 
array stat{3} stat1-stat3;
call sortc(of stat1-stat3); 
ID = CATX("/",stat1,stat2,stat3);
datalines; 
1 A14 A14 A14 53090
2 A14 A14 A10 6744
3 A14 A10 A14 5916
4 A01 A01 A01 4222
5 A10 A10 A10 3085
6 A10 A10 A10 2731
7 A10 A14 A14 2399
; 

/* sorting the data set in preparation for data step with by statement*/
PROC SORT data=have; 
BY ID OBS; 
RUN; 
/* Summarising the dataset and outputing into final dataset*/
DATA summed (drop=ID count); 
set sorted_arrays; 
by ID; 
retain sum 0; 
if first.ID then sum = 0; 
sum + count; 
if last.ID then output; 
RUN; 
/* Sorting it back into original order */
PROC SORT data=summed out=want; 
BY OBS; 
RUN; 

由于我一直在给自己做散列练习,我决定通过散列来尝试。Paul Dorfman有几篇论文讨论了使用哈希表对数组进行排序,例如Black Belt Hashigana。

下面,我使用一个哈希表进行水平排序,然后使用另一个哈希表按ID求和计数。数据只需要读取一次,但是考虑到数据的大小,我当然不会声称在这种情况下有效率上的好处。我没有将数据返回到原始排序顺序。

欢迎编辑/问题/建议,因为这是我哈希学习曲线的一部分。:)
data have; 
input stat1 $ stat2 $ stat3 $ count; 
datalines; 
A14 A14 A14 53090
A14 A14 A10 6744
A14 A10 A14 5916
A01 A01 A01 4222
A10 A10 A10 3085
A10 A10 A10 2731
A10 A14 A14 2399
; 
data want;
  length _stat $3;
  if _n_=1 then do;
    declare hash  hstat(multidata:"y", ordered:"y");
    declare hiter hstatiter ("hstat" ) ;      
    hstat.definekey('_stat');
    hstat.definedata('_stat'); 
    hstat.definedone();
    call missing(_stat);
    declare hash  hsum(suminc: "count", ordered: "y");
    declare hiter hsumiter ("hsum" ) ;      
    hsum.definekey("stat1","stat2","stat3");
    hsum.definedone();
  end;
  set have end=last;
  array stat{3};
  *load the array values into htable hstat to sort them;
  *then iterate over the hash, returning the values to array in sorted order;
  do _i=1 to dim(stat);  
    hstat.add(key:stat{_i},data:stat{_i});
  end;
  do _i=1 to dim(stat);
    hstatiter.next();
    stat{_i}=_stat;
  end;
  _rc=hstatiter.next(); *hack- there is no next, this releases hiter lock so can clear hstat;
  hstat.clear();
  *now that the stat keys have been sorted, can use them as key in hash table hsum;
  *as data are loaded into/checked against the hash table, counts are summed;
  *Then if last, iterate over hsum writing it to output dataset;
  hsum.ref(); *This sums count as records are loaded/checked;
  if last then do;
    _rc = hsumiter.next();
    do while(_rc = 0);
      _rc = hsum.sum(sum: count);
      output ;
      _rc = hsumiter.next();
    end;
  end;
  drop _: ;
run;

最新更新