我正在尝试找到可以将下面的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;
答案 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;