1、在SAS系统中提供了大量的菜单操作,不过它灵活与强大的功能更体现在编程上,本书的实验全部是以程序完成的,所以这里对SAS的菜单操作系统不作介绍,想了解相关内容的读者可以参考其它相关SAS书籍。 在SAS程序中,对数据的分析处理可划分为两大步骤: (1)将数据读入SAS系统建立的SAS数据集,称为数据步(DATA); (2)调用SAS的模块处理和分析数据集中的数据,称为过程步(PROC)。 每一数据步都是以DATA语句开始,以RUN语句结束。而每一过程步则都是以PROC语句开始,以RUN语句结束。当有多个数据步或过程步时,由于后一个DATA或PROC语句可以起到前
2、一步的RUN语句的作用,两步中间的RUN语句也就可以省略。但是最后一个的后面必须有RUN语句,否则不能运行。 SAS还规定,每个语句的后面都要用符号“;”作为这个语句结束的标志。 在编辑SAS程式时,一个语句可以写成多行,多个语句也可以写成一行,可以从一行的开头写起,也可以从一行的任一位置写起。每一行输入完成后,用ENTER键可以使光标移到下一行的开头处,和我们在Windows下进行Word文档编辑相似。 例如: data zhouhm; input name $ sex$ math Chinese; cards; 王家宝
3、 男 82 98 李育萍 女 89 106 张春发 男 86 90 王刚 男 98 109 刘颍 女 80 110 彭亮 男 92 105 ; proc print data = zhouhm; proc means data = zhouhm mean; var math Chinese; run; 绪2.1 data数据步简介 下面介绍SAS系统的data数据步的一般形式、常用语句以及几个常用的功能。 绪2.1.1建立SAS数据集 利用数据
4、步建立SAS数据集,通常有两种方式可以输入数据:一是将数据排列在变量名串之后;二是通过外部数据文件直接读取。 通过程序录入数据的一般语法格式为: DATA<数据集名>; INPUT<变量名1>[$][D] <变量名2>[$][D] … <变量名k>[$][D]; CARDS; S11 S12S1k Sn1 Sn2Snk ; RUN; 说明: 1)DATA语句指定要建立的SAS数据集名,通常也包括逻辑库名, 如:Sasuser.zhouhm,把建立的数据集zhouhm存入逻辑库Sasuser中。如果句中省略逻辑库名,则表明建立的
5、是一个临时库Work中的临时数据表。 2)INPUT语句将下面的数据录入并指定将其赋予给后面定义的每个变量。因此,在INPUT语句中,必须给出有效的SAS变量名和变量类型。可用选项“$”表示该变量为字符型变量,默认则表示为数值型变量,用[D]来指定数据的宽度,用法可以参考后面具体的实验。 3)DATA、INPUT和CARDS三个关键词缺一不可,CARDS后面的是数据行。 4)如果CARDS后面的数据行有重复的域,可以在INPUT语句的末尾增加行停留符“@@”,起到自动换行的功能,以便接着读入后续的数据。 例如: data zhouhm; input number name $ @
6、@; cards; 200641001 zhang 200641002 wang 200641003 gun 200641004 zhu ; run; 直接从外部数据文件中读取的一般语法为: DATA<数据集名>; INFILE’<文件名>’; INPUT<变量名 1><变量名 2>…..<变量名 k>; RUN; 说明:这种方式中用INFILE语句指定了一个外部数据文件,所有需要输入的数据存放在该文件中,从而取代了上一种方式中的CARDS语句及其下列的一连串数据,当数据比较多的时候,用这一种方式可以使程
7、序看上去显得比较简洁,具有一些优越性。这里INFILE语句位置在INPUT语句之前,而在上一种方式中,CARDS语句位置在INPUT语句之后,这些位置是不能随便更换的。 例如: data zhouhm; infile'd:\data\c2006.txt'; input name $ sex $ English Chinese; run; 绪2.1.2 数据集的复制与修改 用SET语句可以把一个已有数据集复制到另一个新数据集,同时还进行修改。当然如果只是复制数据集,用管理器(SAS Explor
8、er)菜单操作完成即可。SET语句的语法格式有两种,有些功能有重复。 格式一的语法形式为: DATA<新数据集名>; SET<数据集名>; [KEPP<计划保留的变量名列表>;] [DROP<计划丢弃的变量名列表>;] [IF<条件>[THEN<语句>];] RUN; 说明:1 )如果后面三个选项都不选,就是将数据集进行简单复制。比如要把临时数据集Work. zhouhm复制为永久逻辑库中的数据集Mylib.liuk,程序如下: data mylib. liuk;
9、 set zhouhm; run; 这个程序中有一个隐含循环过程,SET是读取观测数据的语句,程序在数据步里面反复循环,直到数据集zhouhm最后一个观测数据被读过,循环才结束。SET语句也可以在复制过程的同时给数据集增加一个新的变量: data zhouhm; set zhouhm; meanavg=math*0.4+Chinese/119*100*0.6; run; 2)使用IF….THEN…语句可以在复制的同时对生成的数据集进行有条件的修改。比如可以把超过90分的语文成绩改为90分,程序如下: data zhouhma; set z
10、houhm; if Chinese > 90 then Chinese=90; run; 3)使用KEEP语句可以指定要保留的变量。程序如下: data zhouhmb; set zhouhm; keep name avg; run;/*这样生成的数据集zhouhmb就只包含name和avg两个变量*/ 4)使用DROP语句可以指定要丢弃的变量。如上例程序中的KEEP语句换成下面语句即可: drop name math Chinese;/*用这种方法可以取出数据集的一部分列组成的数据集*/ 5)使用IF语句可以任意指定一个条件,根据这个条件取出数据集中某些
11、行组成新的数据子集。如我们想取出数学分数80分以上,语文分数90分以上的学生的观测值,程序如下:data zhouhm; set zhouhm; if math >= 80 and Chinese >=90; run; /*上面的语句也可以写成if (math>=80)&(Chinese>=90);这样更简洁。*/ 格式二的语法形式为: DATA<新数据集名>; SET<数据集名>[<选项>]; [IF<条件>[THEN<语句>];] RUN; /* SET后面的[<选项>]还可以放在DATA语句
12、之后*/ 语句说明:选项包括KEEP=,表示引入时只要指定的变量;DROP=,表示不引入指定的变量;OBS=,表示读取观测时读到指定的序号为止(注意是以序号为准而不是观测数);FIRSTOBS=,表示从指定序号的观测值开始读取而跳过之前的观测值不读。 绪2.1.3 数据集的拆分 使用SET和OUTPUT语句可以根据某种分类条件把数据行分别存放到不同的数据集中去,其语法格式为: DATA<新数据集 1> <新数据集 2>……; SET<数据集名>[<选项>]; SELECT(<选择表达式>) [WHEN(<
13、条件 1>) OUTPUT<新数据集 1>;] [WHEN(<条件 2>) OUTPUT<新数据集 2>;] … END RUN; 例如,如果想把数据集zhouhm中的所有男生的观测值放在数据集c200601m中,而把其余女生的观测值放到c200601f中,程序如下: data c200601m c200601f; set zhouhm; select(sex); when('男') output c200601m;
14、 when('女') output c200601f; otherwise put sex='wrong'; end; drop sex; run; 在这个程序里有两点需要注意:1)在DATA语句中,我们指定了两个数据集名,而指定数据集名的个数需要根据你拆分的个数保持一致;2)程序中用SET语句引入了一个数据集,如何将这个数据集的观测值分配到两个结果数据集中呢?关键在于SELECT语句和OUTPUT语句。SELECT语句指定变量,而它附带的when 语句确定条件;OUTPUT语句是可执行语句,它执行命令把当前观
15、测值写到语句指定的数据集中去,这样就根据SELECT的结果把不同性别的观测值分别放到两个不同数据集中去了。 绪2.1.4 数据集的合并 数据集的合并根据方向的不同可以分为纵向合并和横向合并,纵向合并一般是多个数据集中的变量是一致的,但观测值的序号数不一致,而横向合并恰好相反,是数据集中观测值的序号数一致但变量是不一致的。 1.纵向合并 如果两个(或多个)数据集中包含了同样的变量,就可以进行数据集的纵向合并。纵向合并的方法相当简单,就是使用SET语句就可以将几个结构相同的数据集上下连接到一起。其一般语法格式如下: DATA<新数据集名>; SET<
16、数据集 1>[(IN=<变量名 1>)] <数据集 2>[(IN=<变量名 2>)]….; [IF<变量名 1>=1 THEN<变量名>=<值 1>;] [IF<变量名 2>=1 THEN<变量名>=<值 2>;] …. RUN; 例如,在前面我们把zhouhm数据集按男、女拆分成200601m和c200601f两个数据集并抛弃了性别变量,可以用如下程序连接两个数据集并恢复性别信息: data new; set c200601m(in=male)c200601f(in=female); if male=1 then
17、sex='男'; if female=1 then sex='女'; run; 注意:在数据步中,如果观测值来自c200601m,则变量male值为1,如果观测值来自c200601f,则变量female值为1,这样可以使用这两个变量的值定义新变量sex。从这个运行的结果我们可以知道,用数据集选项中的IN=指定的变量并不能直接进入结果数据集而只能用于数据步程序运行中。 2.横向合并 两个(或多个)数据集中如果包含了同样的一些观测值的不同变量,且这多个数据集的相同的观测值是按顺序一一对应,就可以用带有MERGE语句的数据步把这些数据集依据那些相同的观测值横向合并到一个数据集中,其一般的语
18、法格式为: DATA<新数据集名>; MERGE<数据集列表>; [BY<变量1>[<变量 2>…]]; RUN; 假如数据集c200601u包含学生的姓名、性别,数据集c200601v包含学生的数学成绩,数据集c200601w包含学生的语文成绩,且各个数据集中的观测值都是按顺序一一对应的,就可以用如下程序把它们横向合并到一个新的数据集Lwh中: data Lwh; merge c200601u c200601v c200601w; run; 语句说明:进行横向合并数据集时要注意到,如果各数据集的
19、观测顺序并不一样时,就会把不同人的成绩合并到一起,这样就会弄乱了整个数据集。所以横向合并数据集时一般要采用按关键字合并的方法,即先把每个数据集按照相同的、能唯一区分各观测值的一个(或几个)变量(BY变量)排序,然后用BY语句和MERGE语句联合使用,这样即使原来观测顺序不一致时也可以保证横向合并的结果不会出错。 绪2.2 PROC过程步简介 介绍了data数据步之后,下面接着来介绍SAS系统的PROC过程步的一般形式、常用语句以及几个常用的过程。 绪2.2.1 PROC过程步的一般形式 SAS过程步的一般形式为: PROC <过程名>[DATA=<输入数据集>][
20、<选项>]; <过程语句>/<选项>; <过程语句>/<选项>; RUN; 绪2.2.2 过程步常用语句 过程步一般伴随着具体的数据分析处理过程进行,所以在过程步的语法格式中重点是“过程语句/选项”,下面就介绍几个常见的具体过程语句,更详细的用法读者可以在以后实验中用到时参考相应的书籍再仔细体会。 (1)VAR语句 VAR语句在大多数过程中都用来指定分析变量,其格式为: VAR<变量名 1><变量名 2>…..<变量名 n>; 例如: var English Chinese; (2)BY语句和
21、CLASS语句 BY语句(CLASS语句)在过程中通常用来指定一个或几个依据分类的变量,根据这些分类变量把观测值分组然后对每一组观测值分别进行本过程指定的分析。其语法格式为: BY<变量名 1><变量名 2>…; 在使用带有BY语句的过程步之前先用SORT过程对数据集排序。如假设已经把zhouhm数据集按sex排序,则下列PRINT过程可以把男、女生分别列出: proc print data=zhouhm; by sex; run; (3)OUTPUT语句 在过程步中经常用OUTPUT语句指定输出结果存
22、放的数据集。不同过程中把输出结果存入数据集的方法各有不同,OUTPUT语句是用得最多的一种,其一般格式为: OUTPUT OUT=<输出数据集名><关键字>=<变量名><关键字>=<变量名>……; 其中用OUT=给出了要生成结果的数据集的名字,用“关键字=变量名”的方式指定了输出那些结果(关键字是如MEANS过程中的MEAN,VAR,STD那样的要输出的结果名),等号后面的变量名指定了这些结果在输出数据集中叫什么名字。例如: proc means data=zhouhm; var English; output out=result
23、n=n means=meanEnglish var=varEnglish; run; proc print data=result; run; (4)WHERE语句 用WHERE语句可以选择输入数据集的一个行子集来进行分析,在WHERE关键字后指定一个条件。其语法格式为: WHERE<条件>; 例如:Where English>=70 and Chinese>=70; 指定只分析英语、语文成绩都上70分的同学。 (5)FORMAT语句 过程步中的FORMAT语句可以为变量输出规定一个输出格式,比如: proc print data=zh
24、ouhm; fromat English 10.1 chinese 10.1; run; 使得列出的语文、英语成绩宽度占10位,带一位小数。 (6)LABEL语句 LABEL语句为变量指定一个临时标签,为方便我们阅读数据集,很多过程都使用这样的标签语句。LABEL语句的一般语法格式为: LABEL<变量名>=’<标签>’ <变量名>=’<标签>’….; 例如: proc print data=zhouhm label; fromat English 10.1 Chinese 10.1
25、 id name; var English Chinese; label name=’姓名’ English =’英语成绩’ chinese=’语文成绩’; run; 1)导入数据(数据来源于2009年10月29日股市交易数据) PROC IMPORT OUT= WORK.sj DATAFILE= "D:\work\example one.xls" DBMS=EXCEL2000 REPLACE; GETNAMES=YES; RUN; 2
26、整理数据 data lwh; set sj; sum=average_price*volume; run;(在数据表sj中增设sum变量形成新的数据表lwh) data lwh; set lwh; if price>0; run; (从数据表lwh剔除那些在2009年10月29日没有交易的股票) 3)练习tabulate过程输出统计量表 proc tabulate data=lwh; class region; var sum price; table region, (sum price)*(
27、mean var); run;(此处是对数据表lwh中深圳和上海的市场的股票分别汇总统计它们的数据) 4)练习gplot过程输出统计图表 proc gplot data=lwh; symbol1 i=join v=+ color=red; symbol2 i=rq v=& color=black; plot speed*low Level_Change*high/overlay; run; proc gplot data=lwh; symbol i=rqcli95 v=* color=blue; plot (Level_
28、Change speed)*(low high); run; 这步的结果如下:图中的实线是两个变量的回归曲线,虚线是它们的置信线。 5)练习gchart过程输出柱状图。 proc gchart data=lwh; vbar price/levels=18 modpoints=5 7 9 11 13 15 17 19 21 23 25 27 29 31 34 38 42 55; run; 这步的结果如下: 图1-4:price的直方图 6)练习univariate过程输出描述性统计量和正态性检验。 proc univar
29、iate data=lwh normal; var Level_Change; histogram Level_Change; probplot Level_Change; run; 这步的结果如下: 表1-1:Level_Change的描述性统计量 表1-2:Level_Change的正态性检验结果 图1-5:Level_Change的直方图 图1-6:Level_Change的QQ图 5、实验方法和操作步骤 1)生成数据 data zt; retain _seed_ 0; mu1=0; mu2=2; sigma1=1; sigma2=
30、4; do _i_=1 to 1000; normal1=mu1+sigma1*rannor(_seed_); normal2=mu2+sigma2*rannor(_seed_); output; end; drop _seed_ _i_ mu1 sigma1 mu2 sigma2; run; 这个步骤用rannor函数生成两个正态分布的变量保存在数据表zt中。 2)运用univariate过程作正态性检验。 proc univariate data=zt normal; var normal1 normal2; histogram normal1 normal2;
31、probplot normal1 normal2;/*正态性假设检验*/ run; 这步的结果如下: 表2-1:normal1的正态性检验结果 图2-1:normal1的直方图 图2-2:normal1的QQ图 分析: 表2-1中的p-value都是大于0.05的,从检验的数量结果显示变量normal1是服从正态分布的,从直方图和QQ图我们也可以看到,直方图是对称的,而QQ图也是一条直线。在程序的结果中还会相应的给出normal2的检验结果。 3)用ttest过程对变量normal1均值假设检验()。 proc ttest data=zt h0=0 alph
32、a=0.01;/*总体均值的假设检验*/ var normal1; run; 这步的结果如下: 表2-2:normal1均值的假设检验 分析: 表2-2中的p-value等于0.5312,远大于0.05的,从检验的数量结果显示变量normal1的均值是被接受的。 4)用pair命令做成配对样本的假设检验 proc ttest data=zt h0=0;/*成配对样本的假设检验*/ pair normal1*normal2; run; 表2-3:normal1均值的假设检验 分析: 表2-2中的p-value小于0.0001,从检验的数量结果显示变
33、量normal1和normal1的均值相等是不被接受的。 5)练习means过程输出price open的基本统计量。 proc means data=lwh; var price open; run; 结果如下: 表2-4:price open的means过程 6)练习npar1way过程对深圳和上海市场的股价假设检验(非参数) proc npar1way data=lwh;/*两独立样本的假设检验(非参数)*/ class region; var price; run; 部分结果如下: 表2-5:深圳和上海市场股价的npar1way过程
34、 分析: 表2-5中的p-value小于0.001,从检验的数量结果显示深圳和上海市场的股价是有显著性的区别的。以上只是挑出npar1way中Wilcoxon检验方法的结果,其它方法的结果可以做相应的分析。 7)对normal2的方差假设检验(非参数) proc means var data=zt; /*总体方差的假设检验*/ var normal2; output out=test var=varex; run; data a(drop=_type_); set test; k=_freq_-1; chisq=k*varex/16; p=1-probchi(chisq
35、k); cil=cinv(0.025,k); ci2=cinv(0.975,k); proc print data=a noobs; run; 结果如下: 表2-6:normal2的方差假设检验 分析: 表2-6中的p-value等于0.93689,从检验的数量结果显示接受normal2的方差等于14.9199。 data lwh; input gdp sr; cards; 5294.7 1212.33 5934.5 1366.95 7171 1642.86 8964.4 2004.82 10202.2 2122.01 11962.5 2199.35 1
36、4928.3 2357.24 16909.2 2664.9 18547.9 2937.1 21617.8 3149.48 26638.1 3483.37 34634.4 4348.95 46759.4 5218.1 58478.1 6242.2 67884.6 7407.99 74462.6 8651.14 78345.2 9875.95 82067.46 11444.08 89442.2 13395.23 95933.3 16386.04 run; 2)作散点图、直观认识gdp*sr的回归关系。 proc gplot data=lwh; plot gdp*
37、sr; symbol i=join v=dot color=red; run; 结果如下: 图3-1:gdp与sr的散点图 3)整理数据(整理出非线性回归需要的指数函数、多项式函数、对数函数、幂函数以及反函数等)。 data zs; set lwh; a=1/gdp; b=1/sr; c=log(gdp); d=log(sr); e=exp(-sr); f=sr**2; g=sr**3; h=sr**4; i=sr**5; j=sr**6; run; 4)相关分析(对上面计算出来的所有的函数) proc corr data=zs; var gdp sr f g
38、 h i j; run; 5)回归分析 proc reg data=zs; model gdp=sr f g h i j; run; proc reg data=zs; model gdp=i j/noint; run; proc reg data=zs; model gdp=sr; model gdp=sr /noint; model a=b /noint; model a=b; model c=d; model c=sr; model c=b; model gdp=d; model gdp=g h i j/noint; run; 6)导入方差
39、分析的数据。 data lwh; input painlevel $ 1.0 codeine 1.0 acupuncture 1.0 relief 2.1@@; datalines; a1100a2105a1206a2212b1103b2106b1207b2213c1104c2108c1208c2216d1104d2107d1209d2215e1106e2110e1215e2219f1109f2114f1216f2223g1110g2118g1217g2221h1112h2117h1216h2224 ; run; 7)单因素方差分析 proc anova; class pai
40、nlevel; model relief=painlevel; means painlevel; means painlevel/t; run; 8)双因素的交互作用检验 proc anova data=lwh; class painlevel codeine acupuncture; model relief=painlevel codeine|acupuncture; run; 模型中”|”这个符号的意义是:A|B=A B A*B, 而A*B代表的是因素A和因素B的交互作用. 结果如下: 表3-6:带交互作用的双因素方差分析 分析: 表3-6中的codeine*acupuncture的p-value等于0.0923,从检验的数量结果显示它们的交互作用是不显著性的。所以接下来要做不带交互作用的双因素方差分析。 9)无交互作用的双因素方差分析 proc anova data=lwh; class painlevel codeine acupuncture; model relief=painlevel codeine acupuncture; means painlevel codeine acupuncture; run;






