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

SAS - Transpose all colums by unique records in each column with counts

我正试图找到高效的、类似转置的代码,可以将下面的测试 table 转换为最终 table。我有下面的代码适用于这个例子,但出于实际目的,拆分数据步骤可以产生非常深的 table(在我的例子中有 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;

可能最省时的解决方案是使用摘要过程。 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;

最后的数据步骤非常'cheap',因为它只在汇总数据集上完成,所以 2k 大小的数据集。只要您没有大量的列,这应该非常简单。

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

使用 PROC SUMMARY 很容易做到。使用您的变量列表作为 CLASS 变量。您可以使用 WAYS 语句将其限制为单向分类组。您可以使用 CHARTYPE 选项来轻松转换结果。您可能还想添加 MISSING 选项以防止 proc summary 消除对任何变量都有缺失值的输入观察。

%let varlist=f1-f8 ;

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

data want ;
  set result ;
  length field  value  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 语句,所有变量都必须是同一类型。

马萨尔:

可以在使用 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  value  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;