最近看到一个群友(QQ群:144839730)提的一个问题:将上图中的名为HAVE的数据集转置成名为WANT的数据集。实现的方法有多种,最易懂的方法应该是TRANSPOSE,下面介绍其他几种方法:
- FILENAME:
data have; a_t1=1; b_t1=2; a_t2=3; b_t2=4; a_t3=5; b_t3=6; a_t4=7; b_t4=8; run; filename code temp; data _null_; file code; set have; array vlst{*} _numeric_; do i=1 to dim(vlst) BY 2; N1=vname(vlst{i}); N2=vname(vlst{i+1}); N3=prxchange('s/(\w+?)_(\w+)/\1_\2=\1/', -1, catx(' ', N1, N2)); N4=scan(N1, 2, '_'); put ' SET have(keep=' N1 N2' rename=(' N3 '));' @@; put ' NAME="' N4 '"; output;'; end; run; data want; length NAME $32; %inc code; run;
- CALL EXECUTE:
data temp; set have; array vlst{*} _numeric_; do i=1 to dim(vlst) BY 2; N1=vname(vlst{i}); N2=vname(vlst{i+1}); N3=prxchange('s/(\w+?)_(\w+)/\1_\2=\1/', -1, catx(' ', N1, N2)); N4=scan(N1, 2, '_'); keep N:; output; end; run; data want; set temp end=last; if _n_=1 then call execute('data want; length NAME $32;'); call execute('SET have(keep='||catx(' ', N1, N2)||' rename=('||cats(N3)||')); NAME="' ||cats(N4)||'"; output;'); if last then call execute('run;'); run;
可能大家会觉得上面两种方法代码行数都有点多,那请看下面采用SAS/IML的方法:
proc iml;
use have;
read all var _NUM_ into M1[c=VARNAMES];
close;
NAME1=scan(VARNAMES, 1, '_');
NAME2=scan(VARNAMES, -1, '_');
ROW=unique(NAME1);
NAME=unique(NAME2);
M2=shape(M1, 0, 2);
create want from M2[c=ROW r=NAME];
append from M2[r=NAME];
close;
quit;
注意,上面函数SHAPE中的行数我写成0,这样真正的行数就由列数决定,即重组1行8列的矩阵,转成2列的情况下,行数只能是4了。故在行列很多的情况下把行或列数设为0会简单点,因为不用去算行或列数。