SAS矩阵重组

Shape

最近看到一个群友(QQ群:144839730)提的一个问题:将上图中的名为HAVE的数据集转置成名为WANT的数据集。实现的方法有多种,最易懂的方法应该是TRANSPOSE,下面介绍其他几种方法:

  1. 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;
    
  2. 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会简单点,因为不用去算行或列数。

曾宪华 /
本文采用 署名-非商业性使用-相同方式共享 3.0许可协议 属于 程序人生 分类, 被贴了 FILENAME CALL EXECUTE PRXCHANGE SAS/IML SHAPE 书签

上一篇 SAS求子集
下一篇 SAS统计一篇文章中各字母的出现频率