SAS - 通过计数每列中的唯一记录转置所有列

时间:2017-12-08 17:25:58

标签: sas enterprise-guide

我正在尝试找到可以将下面的Test表转换为Final表的高效,类似转码的代码。我在下面的代码适用于此示例,但出于实际目的,拆分数据步骤可以生成一个非常深的表(在我的情况下为1.37亿条记录,而在聚合时为2k)。

我希望有一些我失踪的Proc或Data步骤技巧,可以跳过那个中间步骤并提高效率。

Data test;
    Input f1 $ f2 $ f3 $ f4 $ f5 $ f6 $ f7 $ f8 $;

    DataLines;
a c f h k l o q
a c f h k l o q
a c g h k m o q
b c g h k m o q
b d g i k m o r
b d g i k n o r
b e g j k n o s
b e g j k n p s
    ;

Run;

Data final;
    Input field $ values $ records;

    DataLines;
f1 a 3
f1 b 5
f2 c 4
f2 d 2
f2 e 2
f3 f 2
f3 g 6
f4 h 4
f4 i 2
f4 j 2
f5 k 8
f6 l 2
f6 m 3
f6 n 3
f7 o 7
f7 p 1
f8 q 4
f8 r 2
f8 s 2
    ;

Run;


/*Working solution - could it be done more efficiently?*/
Data split;
    Set test;

    Array f{8} f1-f8;
    Do i=1 To 8;
        field = 'f'||PUT(i,best2.);
        values = f{i};
        Output;
    End;

    Drop i f1-f8;
Run;


Proc SQL;
    Create Table final As
    Select
        field
        ,values
        ,COUNT(*) As records Format=comma8.0
    From split
    Group By 1,2
    Order By 1,2
    ;
Quit;

3 个答案:

答案 0 :(得分:2)

可能最节省时间的解决方案是使用汇总过程。 PROC TABULATE似乎最适合这里。

proc tabulate data=test out=test_c;
  class f1-f8;
  tables (f1-f8),n;
run;
data want;
  set test_c;
  array f f1-f8;
  col = cats(of f[*]);
  which_f = whichc(col,of f[*]);
  var = vname(f[which_f]);
  keep col var n;
run;

最终的datastep非常“便宜”,因为它只在汇总数据集上完成,所以2k大小的数据集。只要你没有大量的列,这应该很简单。

如果您确实拥有大量的列,那么您在上面提供的基于数据步骤的解决方案可能是最好的。通过将中间(拆分)数据步骤放入视图,您可以显着加快速度。

答案 1 :(得分:1)

PROC SUMMARY一样容易。将变量列表用作CLASS变量。您可以使用WAYS语句将其限制为单向分类组。您可以使用CHARTYPE选项轻松转换结果。您可能还需要添加MISSING选项以防止proc摘要消除任何变量缺少值的输入观察。

%let varlist=f1-f8 ;

proc summary data=test chartype missing ;
 class &varlist ;
 ways 1 ;
 output out=result ;
run;

data want ;
  set result ;
  length field $32 value $8 count 8 ;
  array fields &varlist ;
  index=indexc(_type_,'1');
  field=vname(fields(index));
  value=fields(index);
  count=_freq_;
  keep field value count;
run;

您可能想要颠倒变量的顺序,以便它们以原始顺序出现。因此,请使用F8-F1代替F1-F8

请注意,由于数据步骤中的ARRAY语句,所有变量都必须属于同一类型。

答案 2 :(得分:1)

Massar:

频率计数可以在使用suminc:keysum:功能的DATA Step哈希对象中完成:

Data have;
    Input f1 $ f2 $ f3 $ f4 $ f5 $ f6 $ f7 $ f8 $;

    DataLines;
a c f h k l o q
a c f h k l o q
a c g h k m o q
b c g h k m o q
b d g i k m o r
b d g i k n o r
b e g j k n o s
b e g j k n p s
    ;

Run;

data want(keep=field value count);
  length field $32 value $8 count 8;
  one = 1;
  call missing (field, value, count);

  declare hash freq(suminc:'one', keysum:'count', ordered:'a', hashexp:20);
  freq.defineKey('field', 'value');
  freq.defineDone();

  do while ( not end );
    set have end=end;
    array f f1-f8;
    do over f; field = vname(f); value=f; freq.ref(); end;
  end;

  declare hiter iter("freq");
  rc = iter.first();
  do while(rc = 0);
    rc = freq.sum(sum: count);
    output;
    rc = iter.next();
  end;

  stop;
run;