SAS学习笔记

SAS学习笔记 宏变量赋值

2023-02-10  本文已影响0人  RSP小白之路

SAS给宏变量赋值大体来说其实就3种方式:%let语句、data步中的call symput语句proc sql过程中into语句
这里根据变量和观测的数量分情况进行如下讨论,即:


单变量单观测变单宏变量

提出问题如下:

/*problem1:将组名信息赋值给宏变量group,各组之间\分割,单变量一观测变一宏变量*/

数据集如下:

data example1;
    group  = "太极组\围棋组\古筝组\书法组";
run;
example1数据集

分别使用如下3种方法进行宏变量赋值:

/*method1: let statement*/

%let group1 = 太极组\围棋组\古筝组\书法组;

%put &group1.;
日志信息
/*method2:data步 call symput statement*/
data _null_;
    set example1;
    call symput("group2",group);
run;

%put &group2.;

日志信息

/*method3:proc sql statement*/

proc sql;
     select group  into: group3
     from example1 
     ;
quit;

%put &group3.;
日志信息
proc sql;
/*    create table macros as*/
    select *
    from dictionary.macros
    ;
quit;

上述语句是获得环境中macros变量信息的语句,很实用。

在单变量赋值单宏变量时,%let语句相比其他两种要简单,不必基于数据集;而proc sql语句则必须基于数据集中的变量产生;call symput则均可以实现。


单变量单观测变多宏变量

/*problem2:将组名信息分别依次赋值给宏变量term1,term2,...,单变量一观测变多宏变量*/
data example2;
    group  = "太极组\围棋组\古筝组\书法组";
run;
xample2数据集

分别使用如下3种方法进行宏变量赋值:

/*method1: let statement*/
%let term1_1 = 太极组;
%let term1_2 = 围棋组;
%let term1_3 = 古筝组;
%let term1_4 = 书法组;

%macro batch;
%do i = 1 %to 4;
    %let _term1_&i. = %qscan("太极组\围棋组\古筝组\书法组" , &i. , "\");
%end;

proc sql;
/*    create table macros as*/
    select *
    from dictionary.macros
    where scope = "BATCH"
    ;
quit;
%mend;
%batch;
batch宏批量处理后打印结果
/*method2:data步 call symput statement*/

data _null_;
   set example2
    do i = 1 to 4;
        call symput(cats("term2_", put(i , best.)) , scan(group , i, "\") );
    end;
run;
打印结果
/*method3:proc sql statement*/
data m3;
   set example2
    array term (4) $ term1 - term4;
    do i =1 to 4;
        term(i) = scan(group , i, "\") ;
    end;
run;

proc sql;
     select  term1, term2, term3, term4  into :term3_1  ,:term3_2 ,:term3_3,:term3_4
     from m3
     ;
quit;

proc sql;
/*    create table macros as*/
    select *
    from dictionary.macros
    ;
quit;
打印结果
  1. 这种情况就可以看出 %let语句的劣势了,无法批量操作,为了批量操作我写了个简单宏才实现;
  2. call symput语句的实现则很简单,这是因为只涉及到单个变量的操作,是data步的优势所在,代码量很少;
  3. proc sql给宏变量赋值的优势在这里体现的不明显,但是也可以看出它针对数据集层面,批量化宏变量赋值操作的便捷性。

单变量多观测变多宏变量

/*problem3:将分组变量中组名观测依次赋值给宏变量term1,term2,...,单变量多观测变多宏变量*/
data example3;
    length group $200.;
    input group;
cards;
太极组
围棋组
古筝组
书法组
;
proc print;
run;

example3打印结果

/*method1:%let statement*/

proc transpose data= example3 out=_out3;
    var group;
run;

%macro m1;
    data test;
        set _out3;
        call symput("group" ,catx("\", of col1 - col4) );
    run;
    %do i = 1 %to 4;
       %let _1term_&i. = %qscan( "&group.", &i.,"\");
    %end;
    proc sql;
        create table macros as
        select *
        from dictionary.macros
        where scope = "M1"
        ;
    quit;
%mend;
%m1;
_out3输出 复制后宏变量结果输出

使用%let解决这个问题,需要先转置,使问题变为基于变量,也就是列,弥补基础语句基于观测处理问题能力偏弱的短板
然后构建宏,在宏里还要再把数据集里的多个变量赋值为单个宏变量,这是因为%let是在变量层面解决问题的,数据集无处下爪;
之后使用循环,弥补%let批量处理问题的短板。


/*method2:call symput statement*/
proc transpose data= example3 out=_out3;
    var group;
run;

data M2;
    set _out3;
    array terms(4) col1 -col4;
    do i = 1 to 4;
        call symput(cats("_2term_", put(i , best.)),terms(i) );
    end;
run;

proc sql;
    select *
    from dictionary.macros
    ;
quit;
打印结果

可以看到,使用call symput解决这个问题,同样需要经历转置步骤转变为处理变量的问题;然后在data步使用数组循环,还是比较繁琐的。


/*method3:proc sql statement*/
/*单变量多观测变多个宏变量*/
proc sql;
     select  group  into :_3term1 -: _3term99
     from example3
     ;
quit;

/*单变量多观测变一宏变量*/
proc sql;
     select  group  into :_3term separated by " "
     from example3
     ;
quit;

proc sql;
/*    create table macros as*/
    select *
    from dictionary.macros
    ;
quit;
打印结果
  1. 这种情况%let的实现一样要借助于宏,并且因为涉及到了数据集层面的操作,%let就更加不太擅长了;
  2. 同时,call symput的实现也不太容易,SAS data长于变量操作弱于观测操作的弊端便体现出来了。
  3. 在这种情况下,proc sql的批量化和观测层面操作的优势便体现出来了,如果是有多变量多观测赋值多宏变量的情况,那proc sql的优势就会更加明显了;

proc sql给宏变量赋值的情况大致可以分为如下几种情况

  1. 单变量单个观测值赋值给单个宏变量:proc sql; select var into :mvar from dtin ; quit;,这种情况用proc sql不具有优势;

  1. 多变量单观测值赋值给多个宏变量:proc sql; select var1, var2, var3, var4 into :mvar1, mvar2, mvar3, mvar4 from dtin ; quit;

  1. 单变量多观测赋值给多个宏变量:proc sql; select var1into :mvar1 -:mvar99 from dtin ; quit;,其中,mvar99中的数值设置的较大值,是在未知观测值数量时的简便做法;

  1. 单变量多观测赋值给单个宏变量:proc sql; select var1into :mvar separated by "sep" from dtin ; quit;,其中,sep是分隔符;

  1. 多变量多观测值赋值给多个宏变量:proc sql; select var1, var2, var3, var4 into :var1m1 -:var1m99, var2m1 -:var2m99, var3m1 -:var3m99, var4m1 -:var4m99 from dtin ; quit;,其中的4个变量均有多个观测值;
proc sql;
    select name, weight, height into :name1 -:name99,
     :weight1 -:weight99, 
     :height1 -: height99
    from sashelp.class(where = (sex = "女"))
    ;
quit;
情况5 结果输出
  1. 多变量多观测值赋值给多个宏变量,但变量内观测值拼接:proc sql; select var1, var2, var3, var4 into :var1m1 -:var1m99, var2m1 -:var2m99, var3m1 -:var3m99, var4m1 -:var4m99 from dtin ; quit;,其中的4个变量均有多个观测值;
proc sql;
    select name, weight, height into :name separated by " ", :weight separated by " " ,:height separated by " "
    from sashelp.class(where = (sex = "女"))
    ;
quit;
情况6 举例输出

总结

不涉及数据集的单变量的宏变量赋值%let很实用;
基于数据集且多在变量层面操作call symputproc sql均适用;
基于数据集且涉及多个变量和观测层面的操作proc sql比较有优势,其他两种实现起来就需要更多的代码量;

上一篇 下一篇

猜你喜欢

热点阅读