SAS中文论坛

标题: About Set Statement [打印本页]

作者: slash    时间: 2014-2-22 20:37
标题: About Set Statement
跟大家分享一下DATA步中SET语句的一些用法。SET语句在编程中的使用频率是非常高的,可以说几乎没有一段数据处理程序是不用它的,因此很有必要了解它。今天所说的东西大多数人可能都知道,但还有人是不了解的,因此如果你都了解就当作复习吧!


1. 语法介绍

首先了解一下Set语句的语法:
SET <SAS-data-set(s) <(data-set-options(s) )> > <options>;
这里需要注意的就是data-set options是需要用括号括起来,而set语句的options直接跟在数据集名后面,用空格分开即可。常用的data-set options有keep=, drop=, rename=, where=, obs=等。这些option都是非常有用的,而且还会提高程序的运行效率。


SET语句常用的option有end=、nobs=、point=等,这些选项的使用会在后续的实际例子中进行介绍。SET语句可以使用一个数据集或者多个数据集,例如:
set a; set a b; set a1-a10; set a:;


2. END=与NOBS=的使用
END=variable创建一个标志变量,当前观测为数据集的最后一条观测时该变量被赋值1,其他时候都为0;NOBS=variable创建一个变量,其值为当前数据集的总观测数。下面是一个简单的统计程序:
  1. data null_;
  2.      file print;
  3.      set sashelp.class end=last nobs=tot;
  4.      if age lt 15 then cnt1+1;
  5.      else cnt2+1;
  6.      if last then do;
  7.            pct1=cnt1/tot;
  8.            pct2=cnt2/tot;
  9.            put "小于15岁的人数:" cnt1 ",占总人数的:" pct1 percent8.2;
  10.            put "大于等于15岁的人数:" cnt2 ",占总人数的:" pct2 percent8.2;
  11.      end;
  12. run;
复制代码


输出结果
[attach]6[/attach]

3.POINT=选项的使用
Point=variable指定一个变量,该变量的值决定了现在要读入第几条观测,下面是一个例子程序:

有一数据test,其形式如下:(该数据的生成程序见最后附录)
[attach]7[/attach]

该数据有18条观测,从1到18,每一个数字都对应了一个flag。变量i对应数据sashelp.class中的变量age,现在要做的工作就是通过变量age匹配flag的值。当然这个工作可以用PROC SQL轻松实现,也可以用merge语句实现,但现在要用SET语句加POINT=选项来实现,程序如下:

  1. data work.test2;
  2.      set sashelp.class;
  3.      temp=age;
  4.      set work.test point=temp;
  5. run;
复制代码

程序是不是非常简单,比起PROC SQL效率会高很多。尤其在匹配几千万条数据时,PROC SQL的效率是非常低的,因为PROC SQL的运行机制决定了其效率。PROC SQL在做匹配时是先生成两个数据的笛卡尔积存到一个临时表,然后再做匹配。想一想两个一千万数据的笛卡儿积是多么庞大。数据集test2的结果:
[attach]8[/attach]



4.BY语句的使用

BY语句也是经常用会用到的,尤其在按照某个变量进行分组处理数据时,与其一起使用的是FIRST.variable与LAST.variable。需要注意的是在使用by语句时要保证该数据已经按BY变量排序了,否则会报错。现将sashelp.class数据按照性别、年龄统计身高均值,程序如下:(当然用PROC MEAN是更简单)

  1. proc sort data=sashelp.class out=test3;
  2.      by sex age;
  3. run;
  4. data test4;
  5.      set test3;
  6.      by sex age;
  7.      if first.age then do;
  8.            cnt=0;
  9.            cum_height=0;
  10.      end;
  11.      cnt+1;
  12.      cum_height+height;
  13.      if last.age then do;
  14.            avg_height=cum_height/cnt;
  15.            output;
  16.      end;
  17.      keep sex age cnt avg_height;
  18. run;
复制代码
数据集test4

[attach]12[/attach]


此外,SET+BY也可以对数据集进行排序。数据集data1data2如下所示:
[attach]9[/attach]


如果只有SET语句,则结果是这样的:
  1. data data3;
  2.      set data1 data2;
  3. run;
复制代码
[attach]10[/attach]

如果是SET+BY,结果就会是这样:
  1. data data4;
  2.      set data1 data2;
  3.      by a;
  4. run;
复制代码
[attach]11[/attach]

数据集data4已按照变量a进行了排序。注:这样使用的前提是data1data2已经按照变量a排序了,否则会报错


5.DO循环加SET语句
利用DO循环和SET语句可以对数据进行取子集,类似于抽样的效果,程序如下所示:
  1. data test5;
  2.    do i=1 to tot by 3;
  3.       set sashelp.class nobs=tot point=i;
  4.       output;
  5.    end;
  6.    stop;
  7. run;
复制代码
sashelp.class数据中抽取了7条观测,结果如下所示:
[attach]13[/attach]

注:程序中的stop语句是非常重要的,如果没有stop语句则程序会陷入死循环,程序不断地往数据集test5输出数据,直到test5撑爆你的硬盘,系统便提示已没有足够空间。

因为使用了point=选项,SAS无法识别哪一条观测是最后一条,如果没有stop语句,DATA步会一直循环。(理解这段程度的关键在于:搞清楚DATA步自身循环与DO循环,DO循环相当于嵌套在DATA步循环中,好好理解。)


为什么前面在介绍point=选项时的那段程序没有stop语句,也不会引起死循环,这个问题留给你们自己想想吧。。。

两个set语句的使用有时候是非常有效的,即set a; set b;这种形式,加上其他的语句像循环、判断之类的,还有POINT=选项,大家可以多做尝试。



--------------我是分割线----------------

附:test数据集生成程序:
  1. data work.test;
  2.      do i=1 to 18;
  3.            flag=input(put(64+i,hex2.),$hex2.);
  4.            output;
  5.      end;
  6. run;
复制代码



作者: berry_li    时间: 2014-12-12 16:21
非常好的东东啊!




欢迎光临 SAS中文论坛 (http://mysas.net/forum/) Powered by Discuz! X3.2