2024年4月30日发(作者:)

SAS常用函数

一、数学函数

ABS(x) 求x的绝对值。

MAX(x1,x2,…,xn) 求所有自变量中的最大一个。

MIN(x1,x2,…,xn) 求所有自变量中的最小一个。

MOD(x,y) 求x除以y的余数。

SQRT(x) 求x的平方根。

ROUND(x,eps) 求x按照eps指定的精度四舍五入后的结果,比如ROUND(5654.5654,0.01)

结果为5654.57,ROUND(5654.5654,10)结果为5650。

CEIL(x) 求大于等于x的最小整数。当x为整数时就是x本身,否则为x右边最近的整数。

FLOOR(x) 求小于等于x的最大整数。当x为整数时就是x本身,否则为x左边最近的整数。

INT(x) 求x扔掉小数部分后的结果。

FUZZ(x) 当x与其四舍五入整数值相差小于1E-12时取四舍五入。

LOG(x) 求x的自然对数。

LOG10(x) 求x的常用对数。

EXP(x) 指数函数 。

SIN(x), COS(x), TAN(x) 求x的正弦、余弦、正切函数。

ARSIN(y) 计算函数y=sin(x)在区间的反函数,y取[-1,1]间值。

ARCOS(y) 计算函数y=cos(x)在的反函数,y取[-1,1]间值。

ATAN(y) 计算函数y=tan(x)在 的反函数,y取间值。

SINH(x), COSH(x), TANH(x) 双曲正弦、余弦、正切

ERF(x) 误差函数

GAMMA(x) 完全 函数

此外还有符号函数SIGN,函数一阶导数函数DIGAMMA,二阶导数函数TRIGAMMA ,

误差函数余函数ERFC,函数自然对数LGAMMA,ORDINAL函数,AIRY 函数,DAIRY

函数,Bessel函数JBESSEL,修正的Bessel函数IBESSEL,等等。

二、数组函数

数组函数计算数组的维数、上下界,有利于写出可移植的程序。数组函数包括:

DIM(x) 求数组x第一维的元素的个数(注意当下界为1时元素个数与上界相同,否则元素

个数不一定与上界相同)。

DIM k(x) 求数组x第k维的元素的个数。

LBOUND(x) 求数组x第一维的下界。

HBOUND(x) 求数组x第一维的上界。

LBOUND k(x) 求数组x第 k维的下界。

HBOUND k(x) 求数组x第 k维的上界。

三、字符函数

较重要的字符函数有:

TRIM(s) 返回去掉字符串s的尾随空格的结果。

UPCASE(s) 把字符串s中所有小写字母转换为大写字母后的结果。

LOWCASE(s) 把字符串s中所有大写字母转换为小写字母后的结果。

INDEX(s,s1) 查找s1在s中出现的位置。找不到时返回0。

RANK(s) 字符s的ASCII码值。

BYTE(n) 第n个ASCII码值的对应字符。

REPEAT(s,n) 字符表达式s重复n次。

SUBSTR(s,p,n) 从字符串s中的第p个字符开始抽取n个字符长的子串

TRANWRD(s,s1,s2) 从字符串s中把所有字符串s1替换成字符串s2后的结果。

其它字符函数还有COLLATE,COMPRESS,INDEXC,LEFT,LENGTH,REVERSE,RIGHT,

SCAN ,TRANSLATE,VERIFY,COMPBL,DEQUOTE,INDEXW,QUOTE,SOUNDEX,

TRIMN,INDEXW。

四、日期和时间函数

常用日期和时间函数有:

MDY(m,d,yr) 生成yr年m月d日的SAS日期值

YEAR(date) 由SAS日期值date得到年

MONTH(date) 由SAS日期值date得到月

DAY(date) 由SAS日期值date得到日

WEEKDAY(date) 由SAS日期值date得到星期几

QTR(date) 由SAS日期值date得到季度值

HMS(h,m,s) 由小时h、分钟m、秒s生成SAS时间值

DHMS(d,h,m,s) 由SAS日期值d、小时h、分钟m、秒s生成SAS日期时间值

DATEPART(dt) 求SAS日期时间值dt的日期部分

INTNX(interval,from,n) 计算从from开始经过n个in间隔后的SAS日期。其中interval 可

以取'YEAR'、'QTR'、'MONTH'、'WEEK'、'DAY'等。比如,INTNX('MONTH', '16Dec1997'd,

3)结果为1998年3月1日。注意它总是返回一个周期的开始值。

INTCK(interval,from,to) 计算从日期from到日期to中间经过的interval间隔的个数,其中

interval取'MONTH'等。比如,INTCK('YEAR', '31Dec1996'd, '1Jan1998'd)计算1996年12 月

31日到1998年1月1日经过的年间隔的个数,结果得2,尽管这两个日期之间实际只隔1

年。

其它日期和时间函数还有DATE、TODAY、DATETIME、DATEJUL、JULDATE、HOUR、

MINUTE、SECOND 、TIME、TIMEPART等。详见《SAS系统-Base SAS软件使用手册》、

《SAS系统-SAS/ETS软件使用手册》。

五、分布密度函数、分布函数

作为一个统计计算语言,SAS提供了多种概率分布的有关函数。分布密度、概率、累积分

布函数等可以通过几种统一的格式调用,格式为

分布函数值 = CDF(' 分布', x <, 参数表>);

密度值 = PDF(' 分布', x <, 参数表>);

概率值 = PMF(' 分布', x <, 参数表>);

对数密度值 = LOGPDF(' 分布', x <, 参数表>);

对数概率值 = LOGPMF(' 分布', x <, 参数表>);

CDF计算由'分布'指定的分布的分布函数, PDF计算分布密度函数值,PMF计算离散分布

的分布概率,LOGPDF为PDF的自然对数,LOGPMF为PMF的自然对数。函数在自变量 x

处计算,<, 参数表>表示可选的参数表。

分布类型取值可以为: BERNOULLI, BETA, BINOMIAL, CAUCHY, CHISQUARED,

EXPONENTIAL, F, GAMMA, GEOMETRIC, HYPERGEOMETRIC, LAPLACE, LOGISTIC,

LOGNORMAL, NEGBINOMIAL, NORMAL 或 GAUSSIAN, PARETO, POISSON, T,

UNIFORM, WALD 或 IGAUSS, and WEIBULL。可以只写前四个字母。

例如,PDF('NORMAL', 1.96)计算标准正态分布在1.96处的密度值(0.05844),

CDF('NORMAL', 1.96)计算标准正态分布在1.96处的分布函数值(0.975)。PMF对连续型

分布即PDF。

除了用上述统一的格式调用外,SAS还单独提供了常用的分布的密度、分布函数。

PROBNORM(x) 标准正态分布函数

PROBT(x,df<,nc>) 自由度为df的t分布函数。可选参数nc为非中心参数。

PROBCHI(x,df<,nc>) 自由度为df的卡方分布函数。可选参数nc为非中心参数。

PROBF(x,ndf,ddf<,nc>) F(ndf,ddf)分布的分布函数。可选参数nc为非中心参数。

PROBBNML(p,n,m) 设随机变量Y服从二项分布B(n,p),此函数计算P(Y m)。

POISSON((lambda,n) 参数为lambda的Poisson分布Y n的概率。

PROBNEGB(p,n,m) 参数为(n,p)的负二项分布Y m的概率。

PROBHYPR(N,K,n,x<,r>) 超几何分布的分布函数。设N个产品中有K个不合格品,抽取n

个样品,其中不合格品数小于等于x的概率为此函数值。可选参数r是不匀率,缺省为1 ,

r代表抽到不合格品的概率是抽到合格品概率的多少倍。

PROBBETA(x,a,b) 参数为(a,b)的Beta分布的分布函数。

PROBGAM(x,a) 参数为a的Gamma分布的分布函数。

PROBMC 计算多组均值的多重比较检验的概率值和临界值。

PROBBNRM(x,y,r) 标准二元正态分布的分布函数,r为相关系数。

六、分位数函数

分位数函数是概率分布函数的反函数。其自变量在0到1之间取值。分位数函数计算的是分

布的左侧分位数。SAS提供了六种常见连续型分布的分位数函数。

PROBIT(p) 标准正态分布左侧p分位数。结果在-5到5之间。

TINV(p, df <,nc>) 自由度为df的t分布的左侧p分位数。可选参数nc为非中心参数。

CINV(p,df<,nc>) 自由度为df的卡方分布的左侧p分位数。可选参数nc为非中心参数。

FINV(p,ndf,ddf<,nc>) F(ndf,ddf)分布的左侧p分位数。可选参数nc为非中心参数。

GAMINV(p,a) 参数为a的伽马分布的左侧p分位数。

BETAINV(p,a,b) 参数为(a,b)的贝塔分布的左侧p分位数。

七、随机数函数

SAS可以用来进行随机模拟。它提供了常见分布的伪随机数生成函数。

1.均匀分布随机数

有两个均匀分布随机数函数:UNIFORM(seed),seed必须是常数,为0,或5位、6位、7

位的奇数。RANUNI(seed),seed为小于2**31-1的任意常数。在同一个数据步中对同一个

随机数函数的多次调用将得到不同的结果,但不同数据步中从同一种子出发将得到相同的随

机数序列。随机数种子如果取0或者负数则种子采用系统日期时间。

2.正态分布随机数

有两种,NORMAL(seed),seed为0,或5位、6位、7位的奇数。RANNOR(seed),seed为

任意数值常数。

3.指数分布随机数

RANEXP(seed),seed为任意数值,产生参数为1的指数分布的随机数。参数为lambda的指

数分布可以用RANEXP(seed)/lambda得到。

另外若Y=alpha-beta*LOG(RANEXP(seed)),则Y为位置参数为alpha,尺度参数为beta的

极值分布。若Y=FLOOR(-RANEXP(seed)/LOG(p)),那么Y是具有参数p的几何分布变量。

4.伽马分布随机数

RANGAM(seed, alpha),seed为任意数值常数,alpha>0,得到参数为alpha的伽马分布。设

X=RANGAM(seed, alpha),则Y=beta*X是形状参数为alpha,尺度参数为beta的GAMMA

分布随机数。如果alpha是整数,则Y=2*X是自由度为2*alpha的卡方分布随机数。

如果alpha是正整数,则Y=beta*X是Erlang分布随机数,为alpha个独立的均值为beta的

指数分布变量的和。

如果Y1=RANGAM(seed,alpha),Y2=RANGAM(seed,beta),在Y=Y1/(Y1+Y2)是参数为

(alpha,beta )的贝塔分布随机数。

5.三角分布随机数

RANTRI(seed,h),seed为任意数值常数,0

为2x/h,在h到1之间为2(1-x)/(1-h)。

6.柯西分布随机数

RANCAU(seed),seed为任意数值常数。产生位置参数为0,尺度参数为1的标准柯西分布

随机数。Y=alpha+beta*RANCAU(seed)为位置参数为alpha,尺度参数为beta的一般柯西分

布随机数。

7.二项分布随机数

RANBIN(seed,n,p)产生参数为(n,p)的二项分布随机数,seed为任意数值。

8.泊松分布随机数

RANPOI(seed,lambda)产生参数为lambda>0的泊松分布随机数,seed为任意数值。

9.一般离散分布随机数

RANTBL(seed, p1, …, pn)生成取1,2,…,n的概率分别为p1,…,pn的离散分布随机数。

八、样本统计函数

样本统计函数把输入的自变量作为一组样本,计算样本统计量。其调用格式为“函数名

(自变量1,自变量2,…,自变量n)”或者“函数名(OF 变量名列表)”。比如SUM是求

和函数,如果要求x1,x2,x3的和,可以用SUM(x1,x2,x3),也可以用SUM(OF x1-x3)。这

些样本统计函数只对自变量中的非缺失值进行计算,比如求平均时把缺失值不计入内。

各样本统计函数为:

MEAN 均值

MAX 最大值

MIN 最小值

N 非缺失数据的个数

NMISS 缺失数值的个数。

SUM 求和

VAR 方差

STD 标准差

STDERR 均值估计的标准误差,用STD/SQRT(N)计算。

CV 变异系数

RANGE 极差

CSS 离差平方和

USS 平方和

SKEWNESS 偏度

KURTOSIS 峰度

注意:数据集的存储一般是每行为一个个体的观测值,每列是个体的一个属性(变量),所

以统计一般应该对列进行,而不是象这里对行进行,把各变量作为一个样本的各个观测处理。

这里提供的函数主要用于进行一些自编程的计算。

SAS实用程序编写技巧(1)

SAS软件包是一个大型的统计分析系统,其核心是多个用于实现统计分析的实用过程。统计

分析离不开操作的数据对象, SAS采用的办法是建立SAS数据集。而实现上述的一切都需要

编制SAS引导程序,简称SAS程序。

SAS程序由一系列符合SAS语言语法规则的语句组成, 正如用任何一门计算机语言编制

的程序一样。SAS语言不仅提供了一般程序设计语言拥有的语句(如循环控制,条件判断,赋

值,输入输出等),而且,其丰富的概率函数、分位数函数、样本统计量函数以及随机数函数更

是其他语言无法比拟的。SAS程序的基本组成是: 若干SAS语句组成数据步(DATA步),若干

SAS语句组成过程步(PROC步),若干DATA步和若干PROC步组成一个完整的SAS程序,

其中,DATA步通常产生SAS数据集, 而PROC步则对SAS数据集内的数据进行处理并输出

结果或产生新数据集。

本章主要介绍如何产生数据集,而且由于数据集大部分由数据步完成,我们把精力也主要

集中于数据步上。

第1节 数据步流程

[例1.5.1] 某小学10名9岁男学生6个项目的智力测验得分资料列于下表中。

表1.5.1 某小学10名9岁男学生6项智力测验得分结果

1. 变量和观测

这是SAS数据集的2个基本概念。可以这样看待它们的关系,SAS对各变量的操作都是

在各观测内进行的。从每一个观测对象身上观测到n个变量的具体取值,在SAS中, 把这n

个数值写在一行上,称为1个观测。如表1.5.1,共有10个观测,每个观测包含7个变量(含编号)

的取值。

2. 建立SAS数据集方法(先看下面的第1个程序)

data a;

input id x1-x6;

cards;

1 14 13 28 14 22 39

2 10 14 15 14 34 35

3 11 12 19 13 24 39

4 7 7 7 9 20 23

5 13 12 24 12 26 38

6 19 14 22 16 23 37

7 20 16 26 21 38 69

8 9 10 14 9 31 46

9 9 8 15 13 14 46

10 9 9 12 10 23 46

;

run;

[说明]DATA语句指明我们要建立一个名字为A的数据集;INPUT语句指明了将要建立的

SAS数据集包含的变量,其中,ID代编号,X1—X6分别代表常识、算术、理解、填图、积木、

和译码这6个方面的得分。 值得注意的是:象X1-X6这样的简写的列表能够被SAS系统接

受, 为SAS程序的书写提供了极大的方便,程序也显得十分简洁;CARDS语句表明下面是用

于建立SAS数据集的数据流,数据流以另起一行的一个分号为结束;RUN语句标志着一个

DATA步或PROC步的结束, SAS系 统一遇到它,即开始建立SAS数据集或调用过程分析数

据。

(5)在程序运行的过程中,我们可以在LOG窗口看到这样的信息:

NOTE:The data set work.a has 10 observations and 7 variables.

它告诉我们,数据集A包含10个观测和7个变量。

(6)每个语句以分号为结束。

下面我们再来看看数据步具体是怎样工作的(数据步流程):

每个DATA步开头的DATA语句总是标志这一步的开始,余下的语句被SAS转换为计

算机的机器语句,而且每次通过DATA步执行它们──通常对输入数据中的每个观测执行一

次。

在DATA步中所有被提到的变量在SAS内部都被变成当前向量的一部分, 也称为

PROGRAM DATA VECTOR(程序数据向量)。即来自输入数据的变量同程序语句产生的变量

一起,都在程序数据向量里,而且可以通过程序语句对它们进行操作。如: INPUT X; Y=X+1;

先通过INPUT语句从数据流中获得变量X的值,接着通过赋值语句产生一个新变量Y,

它的当前值是X的当前值加1,X和Y都在程序数据向量中。如果不特意指定,DATA步产生

的数据集将包含程序数据向量中的所有变量。

用INPUT语句读入或用编程语句产生的变量的初始值,在这个DATA步每执行一次之前

置为缺失,除非用RETAIN语句指明,在后面的应用中我们将会看到RETAIN语句将会起什么

作用。用SET,MERGE或UPDATE语句读入的变量的初始值自动置为保留。

当SAS执行DATA步的最后一个语句时(或让返回到这一步的开头处理新观测的

RETURN语句时),它按常规把程序数据向量的当前值输出到正被创建的SAS数据集中。然

后SAS返回到DATA语句之后的第一个语句, 在程序数据向量中初始值不被保留的变量置

为缺失。接着开始执行语句来建立下一个观测。如果要在DATA步的一次执行中输出多个

观测, 那矩须使用OUTPUT语句。

当SAS已经读完来自输入文件的所有数据时,它继续下一个DATA步或PROC步。

SAS通过DATA步的这些语句处理读入的每个观测,虽然每个语句仅出现一次,但SAS

对每个观测都执行这些语句。不包含INPUT,SET,MERGE或UPDATE语句的DATA步只执

行一次,否则DATA步中的语句被重复执行直到输入的原始数据执行完了,或直到STOP或

ABORT语句被执行。程序语句还可能含有让DATA步中的某些语句执行很多次的语句,如

DO循环等。

SAS变量_N_是SAS为每个DATA步自动设置的,它在某时刻的取值表示这个DATA步

已经执行的次数。在DATA步中可以引用这个变量,但它不会加到正创建的数据集中。

以上这些原则就是我们编制程序的基础。

[]显然是一个最基本的DATA步程序,这里DATA步一共执行了10次, _N_ 的

值从1变到10,但这并非最佳的方法。容易看出,在10个观测中,变量ID的值正好从1到10,

每增加一个观测, ID值增1。于是我们至少还可以写出3个SAS程序使得CARDS语句后的

数据流中不含[]中数据的第1列。

程序二:

DATA a;

DO id=1 TO 10;

INPUT x1-x6;

output;

END;

CARDS;

数据流;run;

程序三:

DATA a;

id+1 ;

INPUT x1-x6;

CARDS;

数据流;run;

程序四:

DATA a;

id=_N_;

INPUT x1-x6;

CARDS;

数据流;run;

统计学

统计学专业英语词汇(1)

/yuanpeng1981/blog/item/

统计学专业英语词汇(2)

/yuanpeng1981/blog/item/

统计学专业英语词汇(3)

/yuanpeng1981/blog/item/

统计学专业英语词汇(4)

/yuanpeng1981/blog/item/

统计学专业英语词汇(5)

/yuanpeng1981/blog/item/

统计学专业英语词汇(6)

/yuanpeng1981/blog/item/

统计学专业英语词汇(7)

/yuanpeng1981/blog/item/

SAS中的函數

/yuanpeng1981/blog/item/

[转]SAS实用程序编写技巧(1)(未完待续)

/yuanpeng1981/blog/item/

蒙特卡罗方法学习类中文书籍目录

/yuanpeng1981/blog/item/

蒙特卡罗(Monte Carlo)方法

/yuanpeng1981/blog/item/

sas使用技巧(2)

[程序二说明] ①DO语句是SAS程序中使用频繁的循环控制语句, SAS规定DO语句必

须和END语句配合使用,DO和END之间的语句构成1个DO组。本例中, DO组内的语句

被执行10次。ID称为下标变量,如果ID值每次递曰是1,而是别的值,如2,则DO语句写成:

DO ID=1 TO 10 BY 2; DO组内语句执行5次。

②本程序中DATA步只执行了一次,_N_的值始终保持为1, 在循环内部使用了OUTPUT语

句,故共输出10个观测,程序中创建的变量一起被输出。

[程序三说明] 累加语句ID+1产生这样的效果,DATA步执行第1次时,先对ID赋初值

0,然后对ID值加1;DATA步执行第2次时,上次执行结束时保留下来的ID值加1,……,如此

往复,也就是说,DATA步第1次执行时ID=1,第2次ID=2,第3次ID=3,……,这正是我们想要

达到的目的。

[程序四说明] 显然,程序三和四中DATA步都执行了10次, 程序四中还充分利用了

_N_的值。以上4个程序我们都可以加上如下的两条语句: PROC PRINT DATA=A;

RUN;

它们调用SAS的打印过程,输出数据集A,都得到下面的结果。

OBS ID X1 X2 X3 X4 X5 X6 OBS ID X1 X2 X3 X4

X5 X6

1 1 14 13 28 14 22 39 6 6 19 14 22 16 23

37

2 2 10 14 15 14 34 35 7 7 20 16 26 21 38

69

3 3 11 12 19 13 24 39 8 8 9 10 14 9 31

46

4 4 7 7 7 9 20 23 9 9 9 8 15 13 14

46

5 5 13 12 24 12 26 38 10 10 9 9 12 10 23

46

(输出结果的第1部分) (输出结果的第2部分)

[说明] 通过这个简单的例子我们可以看到:正确理解数据步流程, 合理运用SAS语句

将为我们带来不少方便,使编出来的程序简洁明了。

第2节 创建数据集的途径

SAS 数据集中数据的来源大致有以下几种方式。

1. 将数据行直接写在CARDS语句后

上一节中我们采用的就是这种办法。

2. 从外部文件(文本文件)读取数据

沿用[例1.5.1],如果事先将数据输入计算机并做成文本文件, 取名为,数据格

式和上节中程序二、三、四的相同,那么建立数据集的程序将更加简洁,即:

DATA a; INFILE ''; id+1; INPUT x1-x6; RUN;

[说明] INFILE语句将当前目录下的数据文件调入。 INFILE语句有

很多选择项,其中很有用的两项是:LRECL=n定义逻辑记录长度,n的值从1至32767;

RECFM=N把整个文件作为一个大记录处理。例如,如果中的数据都写在同一行

上, 那么上面程序中的第2句可改写成:infile '' lrecl=200; 或infile ''

recfm=n; 同时第4句改写成input x1-x6 @@;(从一行读入多个观测)。

3. 利用已经创建的数据集产生所需的新数据集

前面已经创建了数据集A,包含7个变量,如果还想增加1个变量,它的值是x1-x6之和,

可利用已创建的数据集A,重新建立一个数据集,程序如下:

DATA b; SET a; ss=SUM(OF x1-x6); RUN;

[说明] SET语句告诉SAS系统从1个或几个数据集中读取观测值,SUM是1个SAS

函数,作用是对变量求和,它的一般写法是SUM(X1,X2),即变量间用逗号隔开, 但当自变量是

相继的一些变量时,有如上的简略写法。类似SUM这样的样本统计量函数很多, 如MAX(最

大值)、MEAN(均值)、STD(标准差),这种近乎自然英语的写法为程序的书写带来了极大的方

便,可以说这也是SAS的一大特色。

4. 其他软件产生的标准格式文件与SAS数据集之间的互相转换

SAS提供了2个过程,即DBF和DIF,分别用于dBASE数据库和SAS数据集、DIF文件

和SAS数据集之间的相互转换。此处仅以DBF过程说明如下:

假设我们已经用dBASEⅢ或FOXBASE做好了一个DBF文件,它包含[例

1.4.1]中的所有信息,并且,存在当前目录下,则下面的程序可将它转换成SAS数据集。

FILENAME exam ''; PROC DBF DB3=exam OUT=a; RUN;

这里,exam称为文件关联名。运行结束后,新产生的SAS数据集A便在内存之中, 只要

在某个过程名之后写上DATA=A,就可调用。如: PROC PRINT DATA=A; RUN;

反之,如果事先做好了SAS数据集,下面的程序可将它转换成DBF文件。

PROC DBF DB3=exam DATA=a; RUN;

运行结束后,在SAS子目录下自动生成1个名为的dBASEⅢ文件。

[说明] FILENAME语句用于建立1个文件名标记, 在一次SAS作业中一旦建立了1

个标记,它在本次作业中均有效,直到退出本次作业为止。要引用某文件,只需引用其文件名标

记。

5. 某些SAS过程自动产生数据集

很多过程都可以产生新的数据集,有利于数据的再分析。如下面的程序就产生1个包含

x1-x6的均值mx1-mx6的数据集M。

PROC MEANS DATA=a; VAR x1-x6; OUTPUT OUT=m MEAN=mx1-mx6; RUN;

第3节 建立数据集的技巧

SAS软件包的功能十分强大,不仅仅表现在它用于统计分析的各个过程, 还在于它内容

丰富的SAS语言,为灵活地加工处理数据提供了极大的方便。要掌握SAS语言,当然需要花

一些时r间,但正确理解以下几点,也许是关键所在。

1. 含有相同变量集合的两个数据集的纵向(即前后)联接

沿用[例1.5.1],在已建立了数据集A的基础上,如果逾了几名学生的智力得分, 做成数

据文件,要把它添加到A中,程序如下。

DATA a; RETURN;

IF last=0 THEN DO; END;

SET a END=last; INFILE '';

OUTPUT; INPUT id x1-x6; RUN;

(程序的第1部分) (程序的第2部分)

[说明] ①END=是SET语句的选择项,跟在它后面的LAST是任选的1个SAS变量名,

它的值一开始被置为0,直到SET语句读完输入数据集(1个或多个)的最后1个观测时, 其值

为1。变量

LAST不包含在新创建的数据集中。

②SAS从数据集A中读入1个观测并重新输入A后,本来应该顺序执行下面的INFILE和

INPUT语句,但它执行完OUTPUT语句后又遇到一个RETURN语句,RETURN语句的作用就

是让SAS重新回到DATA步的开始,于是重新判断LAST是否为0,由于A中还有观测,LAST

为0,故又读入A中一个观测并输出,遇到RETURN语句又返回,直到读完A中所有观测,LAST

为1,才跳到INFILE语句, 读入外部文件中数据。

③SET语句的选择项还有POINT=,NOBS=,前者是输入数据集中想要处理的观测序号, 后者

是输入数据集的观测总数,用方法与END=类似,限于篇幅,不再赘述。

2. 含有观测数目相同的2个数据集的横向(即左右)联接

沿用[例1.5.1],如果对10名学生又增加了两项智力测验,其变量名为x7,x8, 将得分做成

文件,要把它添加到A中,程序如下。

DATA a; SET a; INFILE ''; INPUT x7 x8; RUN;

运行上面2个程序可分别得到不同的数据集,但它们的共同的特点是数据都来自2个地

方,其一是已经创建的数据集;其二是外部数据文件。这可以说是第2节中创建数据集的不同

方法的混合使用。理解了数据步流程,这样的程序也就不难理解了,而且可以根据需要任意组

合。

3. 将1个大数据集拆成几个小数据集

有时需将1个大数据集按特定的条拣成几个小数据集。沿用[例1.5.1], 假定要由数据集

A拆成2个数据集,分别包含编号为奇数亨号为偶数的学生的结果,可用如下的程序实现。

DATA b; IF k=INT(k) THEN OUTPUT a1;

SET a; ELSE OUTPUT a2;

k=id/2; RUN;

(程序的第1部分) (程序的第2部分)

[说明] INT( )为取整函数,当id为偶数时,k=id/2的结果与对它取整的结果一致, 满足此

条件的所有观测一一输出到数据集a1中去, 与id为奇数对应的所有观测便输出到数据集a2

中去。

4. 运用数组语句和控制语句产生所需的数据集

数组当然是任何一门程序设计语言都缺少不了的一个概念。比较特别的是SAS 的数组

分为2类:一类是普通的,每1个数组元素代表1个变量;另一类是临时的, 数组元素不代表任

何变量,当然也就不能出现在输出数据集上,优点是计算速度快, 占用内存少。定义临时数组

只需加上_TEMPORARY_选择项,如: ARRAY x(10)_TEMPORARY_;便是定义了1个含10个

元素的临时数组x。

控制语句包括DO,END,SELECT,IF,GOTO,LINK,RETURN等,最常用的是DO,END和IF

语句, 有些语句的作用可被其他语句的组合所代替。下面举例说明。

如果要把在第1节建立的数据集A中的10个观测变成1个观测,而且信息不丢失, 那么

新建立的数据集当然需要60个变量(为简单起见,数据集中不再保留变量ID)。实现的程序如

下。

DATA b; DO i=1 TO 6;

SET a; y(_N_,i)=x(i);

ARRAY x(6) x1-x6; END;

ARRAY y(10,6); IF _N_=10;

RETAIN y1-y60; KEEP y1-y60; RUN;

(程序的第1部分) (程序的第2部分)

[说明] ①程序中定义了2个数组,前一个数组为一维数组,不但给出了数组名,而且给出

了数组元素对应的变量x1-x6,事实上这里可以省略;第2个数组为二维数组,省略了变量名,按

规定缺省值为y1-y60。

②RETAIN语句的作用是使变量的值在处理后面观测时得到保留,因为这里数据步执行一次,

只对数组Y中6个元素赋值,于是只有到数据步第10次执行时,60个元素才全部赋值完毕; 加

上一个子集IF语句,表明当数据步第10次执行时才输出当前的程序数据向量的数据到新数

据集b中去;KEEP语句的作用是使新数据集中只保留y1-y60这60个变量。

反之,要从数据集B重新得到A,只需在循环中用OUTPUT语句强制输出观测即可,程序

如下:

DATA a; DO id=1 TO 10;

SET b; DO j=1 TO 6;

ARRAY x(6); x(j)=y(id,j);

ARRAY y(10,6); END;

(程序的第1部分) (程序的第2部分)

OUTPUT;

END;

DROP j y1-y60;

RUN;

(程序的第3部分)

[例1.5.2] 在培养钩端螺旋体时,除已固定若干因素外,拟研究以下4个因素不同水平的

效应,求其最佳组合。A:血清种类─兔、胎盘;B:血清浓度─5%、8%; C:基础液─缓冲剂、

蒸馏水、自来水;D:维生素─加、未加。

表1.5.2 2×2×3×2析因试验的钩端螺旋体计数结果

────────────────────────────────────

A与B 钩端螺旋体计数

(血清种类 ──────────────────────────────

与血清浓度) C与D: 缓冲剂(加 未加) 蒸馏水(加 未加) 自来水(加 未加)

────────────────────────────────────

兔血清: 5% 1426 648 684 1763 1182 580

… … … … … …

8% 1260 1144 875 1447 1220 1789

… … … … … …

胎盘血清: 5% 604 830 867 920 1243 1126

… … … … … …

8% 1108 578 1115 933 1283 685

… … … … … …

────────────────────────────────────

把上面表格中的数据做成文本文件存放于当前目录下,数据格式如下。

[] [SAS程序]

1426 648 684 1763 1182 580 DATA anova;

1183 1264 1430 1241 1512 1026 INFILE '';

2000 1398 1165 1381 1450 1026 DO a=1 TO 2;

1621 909 2022 2421 1385 830 DO b=1 TO 2;

1260 1144 875 1447 1220 1789 DO n=1 TO 4;

1599 1877 2250 1883 1095 1215 DO c=1 TO 3;

1410 1671 1871 1896 1700 1434 DO D=1 TO 2;

2416 1845 1962 1926 2372 1651 INPUT x @@;

604 830 867 920 1243 1126 OUTPUT;

1081 853 771 709 1115 1176 END;

487 441 403 848 416 1280 END;

624 1030 370 574 533 1212 END;

1108 578 1115 933 1283 685 END;

886 669 698 1024 1142 546 END;

831 643 791 1092 677 595 RUN;

1159 1002 559 742 534 566

这样做的好处是显而易见的。首先数据格式保持了与原来表格中的一致,其次,可用任何

编辑软件来建立这样的数据文件,还可以在DATA步中以不同的方式来读外部数据文件,用来

建立不同的SAS数据集,以适应对同一批数据用不同方法进行分析。

运行右边的程序可得到所需的数据集,调用SAS中的ANOVA或GLM过程可实现方差

分析。

[说明] 在SAS的方差分析过程中, 试验的每个因素的不同水平都在用于分析的SAS

数据集中以一个变量的不同取值来表示, 这种变量在方差分析中被称为分组变量。例如从表

中任取一个数据867,它是血清种类为胎盘血清,血清浓度为5%,基础液为蒸馏水,维生素加上

时得到的钩端螺旋体计数,即A=2,B=1,C=2,D=1条件下的观测结果。为对每个数据的分组变

量都赋以正确的值,我们在数据步中采用循环嵌套的办法,这样一共形成2×2×4×3×2=96个观

测, 其中4为每种组合下的重复试验次数。在循环嵌套中,外层下标变量的值变化慢, 内层下

标变量的值变化快。容易看出,DATA步执行完后得到的数据集有如下结构:

OBS A B N C D X

1 1 1 1 1 1 1426

2 1 1 1 1 2 648

3 1 1 1 2 1 684

……………………………………

94 2 2 4 2 2 742

95 2 2 4 3 1 534

96 2 2 4 3 2 566

(数据集的第1部分) (数据集的第2部分)

第4节 宏处理简介

1. 宏变量

宏变量(有时也称符号变量)属于SAS宏语言的范畴,和数据步中的变量的概念是不一样

的。除了数据行外,你可以在SAS程序的任何地方定义和使用宏变量。数据步变量是和数据

集相联系的,而宏变量是独立于数据集的。数据集变量的值取决于正在处理的观测,而一个宏

变量的值总是保郴变,直到被明确改变。定义一个宏变量的最简单的办法是使用宏语句%LET,

如%let dsn=Newdata; DSN就是宏变量的名字,Newdata是它的值。宏变量命名遵从一般的

SAS命名规则,宏变量的值是一个字符串。

要引用宏变量的值,在宏变量的前面放“&”,如title "Display of Data Set &dsn";

宏处理器用DSN的值去代替&dsn,结果得到TITLE "Display of Data Set Newdata";

值得注意的是这里的标题必须用双引号括起来,而不能用单引号,因为宏处理器只对双引

号中引用的宏变量进行这种处理,而把单引号中的所有字符都看作是标题的内容。

在一个SAS程序中,你可以根据需要引用宏变量任意次, 在你改变它之前它的值一直保

持不变。下面的程序就引用了DSN2次。

DATA temp; SET &dsn; IF age>=20;

PROC PRINT; TITLE "Subset of Data Set &dsn"; RUN;

每次&dsn一出现,宏处理器就用Newdata代替它,SAS实际执行的语句是DATA TEMP;

SET NEWDATA; IF AGE>=20;

PROC PRINT; TITLE "Subset of Data Set Newdata"; RUN;

你也可以创建一个包含SAS语句的宏变量,如:

%LET plot=%str( 这种情况下,宏变量的值都作为函数%STR的实参, 于是

PROC PLOT; 号成为宏变量值的一部分,而不会被当做%LET语句的结束。

PLOT income*age; 要改变宏变量的值,只需用%LET语句重定义, 宏变量也

RUN; 以赋空值,如:

) %LET dsn=Nextdata; %LET plot=;

第1个语句对DSN重新赋值Nextdata,第2个语句对PLOT赋空值。宏变量也可以嵌套

引用:

%LET dsn=Olddata; DATA temp;

%LET yvar=Income; SET &dsn;

%LET xvar=Age; IF age>=20;

%LET plot=%str( &plot

PROC PLOT; PROC PRINT;

PLOT &yvar*&xvar; TITLE "Subset of Data Set &dsn";

RUN; RUN;

)

(程序的第1部分) (程序的第2部分)

SAS实际执行的是如下的语句:

DATA TEMP; SET OLDDATA; IF AGE>=20;

PROC PLOT; PLOT YVAR*XVAR; RUN;

PORC PRINT; TITLE "Subset of Data Set Olddata"; RUN;

2. 宏

宏就是存贮的1个文本,最简单的宏工作起来很象1个宏变量,但是复杂的宏可以做许多

宏变量无法完成的事。下面是1个最简单的宏定义。

%MACRO dsn; Newdata %MEND dsn;

宏定义总是由%MACRO语句开始,而且必须包含1个宏名。宏名遵从一般的SAS命名

规则,这里的宏名叫DSN。Newdata是宏的内容, %MEND作为宏定义的结束语句;这里

的 %MEND语句为了清晰还重复了宏名。要调用1个宏,只需放1个百分号%在宏名的前面,

如:

TITLE "Display of Data Set %dsn";

宏处理器执行宏展开,用宏内容去代替%dsn,TITLE语句成为:

TITLE "Display of Data Set Newdata"; 同样,标题必须用双引号括起来。

一个SAS程序可以包含多个宏,一个宏也可以被多次调用,要改变一个象DSN这样简单

的宏的内容,只需新重定义宏,对简单的文本代换,用宏变量比定义一个宏效率要高,但是当任

务比较复杂的时侯,宏救宏变量要优越得多了。下面的程序创建一个包含整段SAS程序的

宏。%MACRO plot; PROC PLOT; PLOT income*age; RUN; %MEND plot;

以后调用宏如下: SAS实际执行的语句是:

DATA temp; DATA TEMP;

SET olddata; SET OLDDATA;

IF age>=20; IF AGE>=20;

%plot PROC PLOT;

PROC PRINT; PLOT INCOME*AGE;

RUN; RUN;

PROC PRINT; RUN;

假设在PROC PLOT中的绘图变量可以改变,你就可以用宏变量引用去替换PLOT语句

中的变量名,然后在调用宏之前用%LET语句给宏变量赋值。

%MACRO plot; SAS 实际执行的是如下的语句:

PROC PLOT; DATA TEMP;

PLOT &yvar*&xvar; SET OLDDATA;

RUN; IF AGE>=20;

%MEND plot; PROC PLOT;

DATA temp; PLOT INCOME*AGE;

SET olddata; RUN;

IF age>=20; PROC PLOT;

%LET yvar=income; PLOT INCOME*YRS_EDUC;

%LET xvar=age; RUN;

%plot PROC PRINT;

%LET xvar=yrs_educ; RUN;

%plot

PROC RRINT;

RUN;

宏变量和宏结合起来使用,为灵活设计提供了极大的方便。当程序较长的时侯,就象上面

的程序一样,总是使用%LET语句就显得不那么方便了,这时可以使用宏参数, 即定义宏变量

作为%MACRO语句的一部分。

%MACRO plot(yvar,xvar); PROC PLOT; PLOT &yvar*&xvar;

RUN; %MEND; %MACRO语句的括号中定义的宏变量就是宏参数,当调用宏的时侯,

需将值传递给宏参数, 如: %plot(income,age)

宏处理器把第1个值和第1个宏变量匹配,第2个值和第2个宏变量匹配……因此,这些

参数叫做位置参数,于是产生下面语句:

PROC PLOT; PLOT INCOME*AGE; RUN;

假设你经常创建数据集TEMP和绘制PLOT图,你可以将数据步做成一个宏,而过程步做

成另一个宏,然后在第3个宏里调用它们。注意最好加上注释说明你要做什么。

%MACRO create; %MACRO analyze(yvar,xvar);

Data temp; %*Create the Data Set;

SET olddata; %create

IF age>=20; %*Plot the Variable Selected;

%MEND create; %plot

%MACRO plot; %MEND analyze;

PROC plot;

PLOT &yvar*&xvar;

RUN;

%MEND plot; (右边的程序是左边程序的继续)

在宏ANALYZE中,由“%*”开始的语句是宏注释语句, 它们用于对宏内做的事情作注解。

当宏较长的时侯,是很必要的。当你定义完这些宏后,就可以通过调用宏来运行程序。

%analyze(income,age)

如果你想改变CREATE,重新定义它,则:

%MACRO create;

DATA temp2; SET olddata(obs=100); IF age>=20;

%MEND create;

然后调用ANALYZE,方法是: %analyze(income,age)

当然,你也可以把整个程序段都放入ANALYZE,而不去调用其他宏,但是,定义CREATE

和PLOT的优点是你可以在调用ANALYZE之前分别重新定义和调试它们,在规模较大的宏

中, 模块结构是很重要的。

当你使用宏ANALYZE时,假设有时你需要执行宏CREATE中的DATA步,而有时又可

直接从PROCPLOT开始,重新定义ANALYZE,使用%IF-%THEN语句。

%MACRO analyze(getdata,yvar,xvar);

%IF &getdata=yes %THEN %create; %plot

%MEND analyze;

如下调用ANALYZE,方法为:

%analyze(yes,income,age) %analyze(no,income,yrs_educ) 产生:

DATA TEMP; SET OLDDATA; IF AGE>=20; PROC PLOT; PLOT

INCOME*AGE; RUN;

PROC PLOT; PLOT INCOME*YRS_EDUC; RUN;

如果在%THEN从句中有多个语句, 如果我们调用ANALYZE,方法

如下:

使用%DO-%END组,如: %analyze(YES,income,age)

%MACRO analyze(getdata,yvar,xvar); 那么产生的语句是:

TITLE; PROC PLOT;

%IF &getdata=yes %THEN %DO; PLOT INCOME*AGE;

%create RUN;

TITLE3 "Data Set Created for This Plot";

%END;

%plot

%MEND analyze;

宏处理器并没有调用宏CREATE去创建一个数据集, 因为宏处理器在把宏展开时并不

把小写字母转换为大写。于是%IF语句作的比较是YES=yes,当然为假,事与愿违。为了在调

用时不管大小写都正确,应该修改ANALYZE如下:

%MACRO analyze(getdata,yvar,xvar);

%IF %UPCASE(&getdata)=YES %THEN %create;

%plot

%MEND analyze;

其中宏函数%UPCASE把小写转换为大写。

假设你想创建一系列名字用于SAS语句, 如DATA或VAR语句,可以借助宏来实现。

%MACRO names(name,number)

%DO n=1 %TO &number; &name&n %END;

%MEND names;

宏NAMES把参数NAME的值和宏变量的值连接起来形成一系列名字,参数NUMBER

的值是宏变量N的终止值。于是在DATA步中调用NAMES,方法如下:

DATA %names(dsn,5); 产生语句: DATA DSN1 DSN2 DSN3 DSN4 DSN5;

3. 数据步中的宏变量

假设你想把一个数据集的观测数放进一个FOOTNOTE语句中,首先定义一个宏,如:

%MACRO create;

DATA temp;

SET olddata END=final; IF age>=20 THEN DO; n+1; OUTPUT; END;

IF final THEN CALL SYMPUT('number',n); RUN;

%MEND create;

以后一旦调用CREATE,则CALL SYMPUT语句将计数变量N的值传递给宏变量

NUMBER,NUMBER可以是以前创建的宏变量,也可以是当前的DATA步创建。

这个宏变量以后可以直接引用, 也可以在DATA步用SYMGET函数引用。从而实匣同

的数

据步中的值传递,如:

x=SYMGET('number'); 数据步变量X的值就是数据集TEMP中的观测个数。

第5节 SAS实用程序举例

1. 方差分析前如何实现正态性检验和方差齐性检验

用于方差分析的资料要求满足正态性和方差齐性的假设,但用于作方差分析的SAS过程

并没有提供这样的检验。下面的程序可用在对数据作方差分析之前, 检查数据是否符合条件。

若符合,直接调用方差分析过程;若不符合,看是否能对数据作某种数据变换,使数据近似满足

要求;若实在难以办到,只好考虑别的办法,如非参数法。

[SAS程序] []

DATA a2;

PROC SORT DATA=anova; SET a1;

BY a b c d; RUN; v=n-1;

PROC UNIVARIATE DATA=anova NORMAL; _type_=1;

VAR x; BY a b c d; RUN; buf=2*v*LOG(s);

u=1/v;

RUN;

PROC MEANS DATA=a2 NOPRINT;

PROC MEANS DATA=anova NOPRINT; VAR _type_ ss v buf u;

VAR x; BY a b c d; OUTPUT OUT=a3 SUM=k t_ss t_v t1 t2;

OUTPUT OUT=a1 N=n CSS=ss STD=s; RUN;

RUN;

(程序的第1部分) (程序的第2部分)

DATA _NULL_;

FILE PRINT;

SET a3;

chi_sqr=LOG(t_ss/t_v)*t_v-t1;

adjusted=chi_sqr/(1+1/3/(k-1)*(t2-1/t_v));

p=1-PROBCHI(adjusted,k-1);

PUT @12 'Chi Square' @30 'Adjusted Chi Square' @55 'Prob>Chi'

#3@****************************@55p7.4;

RUN;

(程序的第3部分)

[修改指导] ①本程序直接调用本章第3节中已建立的SAS数据集

ANOVA。②先用SORT过程对该数据集按A,B,C,D进行排序,BY语句中出现的变量,排在前

面的变化慢,后面的变化快。例如,假设只有2个变量出现在BY语句中,X在前,Y在后,即'BY

X Y;', X有2个值1和2,Y有2个值5和6,则在排完序的数据集中,X=1且Y=5的观测排在

最前面,其次是X=1,Y=6,再其次是X=2,Y=5,最后是X=2,Y=6。

③对排完序以后的数据集调用UNIVARIATE过程进行单变量分析,加上选择项NORMAL,

表示要进行正态性检验;VAR指定要进行分析的变量;BY语句指明要分组进行分析, 即对

A,B,C,D的各种组合都分别进行一次单变量分析。

④[输出结果之一]只是A,B,C,D的24种水平组合产生的24个输出的第1部分,限于篇幅,未

全部列出。其中“W:Normal 0.987761 Prob

果,它采用的是W检验,0.9245就是P值,P值越大,一般表明正态性越好。

⑤进行Bartlette方差齐性检验,首先使用了1个MEANS过程。这个过程可以输出许多常用

的统计量,如均值、总和、标准差等。NOPRINT表明不产生打印输出, 一般该过程要产生一

些输出结果。OUTPUT语句用选择项OUT=规定1个输出数据集名A1,该数据集包含代表观

测数的变量N,代表偏差平和的变量SS,代标准差的变量S。在这个OUTPUT语句中,OUT=,N=,

CSS=和STD=都是关键词,A1,N,SS和S是自己规定的数据集名轰量名。BY语句指明分组变

量。

⑥根据Bartlette法,MEANS过程后紧跟着一个DATA步,里面使用了自然对数函数

LOG(),SAS还提供了以10为底的常用对数LOG10()和以2为底的对数函数LOG2()。

⑦DATA步之后再跟1个MEANS过程,输出1个数据集A3,它包含数据集A2中变量

_TYPE_,SS,V,BUF和U的总和K,T_SS,T_V,T1和T2。

⑧最后1个DATA步使用空数据集名_NULL_,表明该数据步中不产生数据集, 这样可以节省

资源也节省时间,因为在该步中只想产生一些输出。首先用FILE语句指明输出的设备,FILE

后面可以跟着1个外部文件名(建立1个外部文件),也可以跟'PRN:'(输出到打印机),或跟1个

文件名标记(作用同跟着文件名一样),本例中跟PRINT, 表示要输出到OUTPUT窗口。与

FILE语句配合使用的是PUT语句,PUT语句指明要输出的内容,这些内容输出到PUT语句前

面最近的1个FILE语句指明的设备。@为列指针,#为行指针,整个PUT语句的意思是说,先

把指针移到12列, 输出字符串Chi Square, 接着把指针移到30列,输出字符串Adjusted Chi

Square, 再到55列, 输出Prob>Chi,然后把指针移到第3行第12列, 输出变量CHI_SQR的

值,输出格式为10.4,再到30列,输出ADJUSTED的值,格式10.4,最后到55列,输出P值,格式

7.4。格式W.D的含义是:最多有W位(包括负号和小数点),其中小数部分有D位。

⑨程序还使用了概率函数PROBCHI,本例中,K-1为自由度,ADJUSTED为代表校正的卡方值

的变量。由于PROBCHI的返回值为小于卡方值的概率, 但我们需要的却是大于等于该卡方

值的概率,故还要经过一次转换。下面给晨分输出结果:

[输出结果之一]

------------------------------ A=1 B=1 C=1 D=1 -------------------------------

Variable=X

Moments

N 4 Sum Wgts 4

Mean 1557.5 Sum 6230

Std Dev 345.1478 Variance 119127

Skewness 0.520517 Kurtosis 0.199882

USS 10060606 CSS 357381

CV 22.16037 Std Mean 172.5739

T:Mean=0 9.025119 Prob>|T| 0.0029

Sgn Rank 5 Prob>|S| 0.1250

Num ^= 0 4

W:Normal 0.987761 Prob

[输出结果之二]

Chi square Adjusted chi square Prob>chi

40.4205 36.2275 0.0391

[输出结果的解释] 因P=0.0391<0.05,在α=0.05的水平上拒绝方差相等的无效假设,故此

需先对此资料作数据变换后方可进行方差分析或采用相应的非参数法分析。

sas使用技巧(接上3)

2. 灵活地产生频数表

在实际工作中,频数表的使用是很广泛的。获得一批数据之后,绘制一个频数表, 可以获

得对数据的总体的大致印象,对正确选用统计方法进行分析资料是很有好处的。

[SAS程序] []

%LET n=120; m=1;

DO UNTIL (last<=start+m*s);

DATA _NULL_; m=m+1;

ARRAY f(15) _TEMPORARY_; END;

ARRAY sf(15) _TEMPORARY_;

ARRAY percen(15) _TEMPORARY_; n=SYMGET('n')+0;

ARRAY x(&n); DO i=1 TO n;

FILE PRINT; k=m;

INPUT x1-x&n; DO j=1 TO m;

DO i=1 TO 15; IF (start+(j-1)*s)

f(i)=0; (start+j*s) THEN DO;

sf(i)=0; f(j)=f(j)+1;

END; sf(j)=sf(j)+1;

min_x=MIN(OF x1-x&n); k=j;

max_x=MAX(OF x1-x&n); END;

s=ROUND((max_x-min_x)/10,1); IF j>k THEN sf(j)=sf(j)+1;

start=min_x-1; END;

last=max_x+1; END;

(程序的第1部分) (程序的第2部分)

PUT @2

'______________________________________________________________________'

#2 @4 'Groups' @13 'Frequency' @27 'Cumulative Frequency'

@51 'Cumulative Percent'

#3 @2 '______________________________________________________________________';

DO j=1 TO m;

percen(j)=sf(j)/n*100; buf=start+(j-1)*s;

PUT #(j+3) @2 buf 6. '-' @16 f(j) 3. @37 sf(j) 4. @58 percen(j) 5.1;

END;

PUT #(m+4) @2

'______________________________________________________________________'

#(m+5) @2 'The Largest Value' @19 max_x 6.

@35 'The Smallest Value' @53 min_x 6.;

CARDS;

86 83 77 81 81 80 79 82 82 81 81 87 82 78 80 81 87 81 77 78 77 78 77 77

77 71 95 78 81 79 80 77 76 82 80 82 84 79 90 82 79 82 79 86 76 78 83 75

82 78 73 83 81 81 83 89 81 86 82 82 78 84 84 84 81 81 74 78 78 80 74 78

75 79 85 75 74 71 88 82 76 85 73 78 81 79 77 78 81 87 83 65 64 78 75 82

80 80 77 81 75 83 90 80 85 81 77 78 82 84 85 84 82 85 84 82 85 84 78 78

;

RUN;

(程序的第3部分)

[修改指导] ①数据集名用_NULL_,120个观测数据按一维数组的形式读

入,SAS系统把它们作为1个观测中的120个变量来处理,这样就可以运用程序设计的许多方

法来编程,因为在只有1个观测的情形下,SAS语言吼的计算机语言是非常相似的。

②我们的算法是:准备将数据分成10组左右, 为此先调用MAX和MIN函数计算最大和最小

值;然后计算组距S(注:统计书中组距通常用H或i表示);为了形式上的美观,将S取为整数,

使用ROUND函数;再对最小值减1,作为第1组的下限值,然后判断实际需要的组数M; 最后

计算我们感兴趣的各组的频数、累计频数和累计百分率,以一种比较直观的形式输出。

③ROUND函数的作用是按要求的精度四舍五入,如:

ROUND(10.78,0.1)=10.8; ROUND(10.48,1)=10。

④本程序一般只需在加注释语句的地方(第1个语句处)对数据进行适当的修改,就可用于别

的数据。如只有100个样本观测值,只需将120改成100即可。这是因为我们在程序一开始

就定义了宏变量N,在后面的程序中多次引用,从这里我们可以看出宏变量的作用。

[输出结果]

表 1.5.3 巧用SAS语言编制的频数表之输出结果

______________________________________________________________________

Groups Frequency Cumulative Frequency Cumulative Percent

______________________________________________________________________

63- 2 2 1.7

66- 0 2 1.7

69- 2 4 3.3

72- 10 14 11.7

75- 29 43 35.8

78- 31 74 61.7

81- 29 103 85.8

84- 12 115 95.8

87- 4 119 99.2

90- 0 119 99.2

93- 1 120 100.0

______________________________________________________________________

The Largest Value 95 The Smallest Value 64

3. R×C表等级资料的Kruskal-Wallis检验、RIDIT分析和CPD分析

Kruskal-Wallis检验(即H检验)是一种经典的非参数统计方法,RIDIT分析为在H检验基

础上发展起来,CPD分析为王广仪教授首创,并在他的专著中对3种方法有精彩的论述。下面

是一个同时给出Kruskal-Wallis检验、RIDIT 分析和CPD分析结果的程序。

[例1.5.3] 某作者收集了厌色性垂体腺瘤患者手术治疗后视力变化情况资料,见下表。

表1.5.4 厌色性垂体腺瘤患者治疗后视力变化

────────────────────────────────────

例 数

疗 效 ──────────────────────────────

术前视力: 1级 2级 3级 4~5级 合计

────────────────────────────────────

恢复正常 2 3 1

进 步 51 70 60

不 变 15 38 27

恶 化 1 2 2

0

45

53

3

6

226

133

8

────────────────────────────

合计 69 113 90 101 373

────────────────────────────────────

注:术前视力为实验分组指标,疗效为指标分组指标。

[SAS程序] []

%let group=4;

%let rank=4;

%let col_row=%(&group*&rank);

(程序的第1部分)

DATA _NULL_; n=n+tcol(j);

row=&rank; END;

col=&group; buf3=n;

ARRAY num(&rank,&group); DO i=1 TO row;

ARRAY cpd(&group); trow(i)=0;

ARRAY ridit(&group); DO j=1 TO col;

ARRAY trow(&rank); trow(i)=trow(i)+num(i,j);

ARRAY tcol(&group); END;

ARRAY y(&rank); buf4=buf4+trow(i)*trow(i)*trow(i);

ARRAY ucpd(&group); buf2=trow(i);

ARRAY uridit(&group); y(i)=buf3-buf1-buf2;

ARRAY t(&group); buf3=y(i);

FILE PRINT; buf1=trow(i);

n=0; buf1=0; END;

buf4=0; buf5=0; DO j=1 TO col;

INPUT num1-num&col_row; cpd(j)=0;

DO j=1 TO col; DO i=1 TO row;

tcol(j)=0; cpd(j)=cpd(j)+num(i,j)*y(i);

DO i=1 TO row; END;

tcol(j)=tcol(j)+num(i,j); ridit(j)=0.5-cpd(j)/(2*tcol(j)*n);

END; t(j)=tcol(j)*(n+1)/2-cpd(j)/2;

(程序的第2部分) (程序的第3部分)

ucpd(j)=cpd(j)/sqrt(tcol(j)*(n-tcol(j))*(n*n*n-buf4)/(3*n*(n-1)));

uridit(j)=(0.5-ridit(j))/sqrt((n*n*n-buf4)/(12*n*n*(n-1)*tcol(j)));

buf5=buf5+t(j)*t(j)/tcol(j); END;

Hc=(12/(n*(n+1))*buf5-3*(n+1))/(1-(buf4-n)/(n*(n*n-1)));

prob_Hc=1-PROBCHI(Hc,col-1);

PUT @27 "Kruskal-Wallis's Test"

#3 @19 'Adjusted Chi-Square(Hc)' @49 'Prob>Hc'

#**********@50prob_Hc6.4;

PUT #7 @25 'Result of CPD and RIDIT Analysis'

#9 @6 'CPD Values' @20 "CPD's U-Values"

@40 'RIDIT Values' @60 "RIDIT's U-Values";

DO j=1 TO col;

PUT #(j+9) @6 cpd(j) 7. @22 ucpd(j) 8.4

@43 ridit(j) 7.4 @62 uridit(j) 8.4;

END;

buf1=probit(0.05/2/col); buf2=-buf1;

buf3=probit(0.05/2); buf4=-buf3;

PUT #(col+10) @6 "ALPHA= 0.05 CPD's Critical U-Values"

@*******************;

PUT #(col+11) @6 " RIDIT's Critical U-Values"

@*******************;

buf1=probit(0.01/2/col); buf2=-buf1;

buf3=probit(0.01/2); buf4=-buf3;

PUT #(col+12) @6 "ALPHA= 0.01 CPD's Critical U-values"

@*******************;

PUT #(col+13) @6 " RIDIT's Critical U-Values"

@*******************;

CARDS;

2 3 1 0

51 70 60 45

15 38 27 53

1 2 2 3

;

RUN; (程序的第4部分)

[修改指导] ①程序中数据输入方式是:横向为指标分组,纵向为实验分

组。

②由于3种方法在本质上是一致的,按其中某种方法计算出结果,通过一些公式的联系,其他方

法的结果也就随即得到。本程序以CPD分析的算法进行计算,利用王广仪教授书中的公式算

出RIDIT分析和Kruskal-Wallis检验的结果。

③程序中再次定义了宏变量,第1个宏变量的值代表分组数,第2个代表等级数, 对其他资料

引用该程序时,只需修改这两个地方即可。

[输出结果] Kruskal-Wallis's Test

Adjusted Chi-Square(Hc) Prob>Hc

21.6427 0.0001

Result of CPD and RIDIT Analysis

CPD Values CPD's U-Values RIDIT Values RIDIT's U-Values 等 级

3894 2.8141 0.4244 2.5405 1

1309 0.7993 0.4845 0.6673 2

1689 1.1077 0.4748 0.9648 3

-6892 -4.3521 0.5915 -3.7165 4

ALPHA= 0.05 CPD's Critical U-Values -2.4977 2.4977

RIDIT's Critical U-Values -1.9600 1.9600

ALPHA= 0.01 CPD's Critical U-Values -3.0233 3.0233

RIDIT's Critical U-Values -2.5758 2.5758

[输出结果的解释和专业结论] 3种方法得到的结果是一致的。Kruskal_Wallis 检验输

出1个卡方值=21.6427和1个P值<0.0001,表明术前视力是影响手术疗效的重要因素, 而

RIDIT分析和CPD都对术前视力和疗效的关系作出具体的评价, CPD值从3894到-6892和

RIDIT值从0.4244到0.5915分别代表用这两种检验法算得的检验统计量的值, 它们分别反

映术前视力从1级到4级的疗效,在α=0.05的水平下,按疗效不同,把术前视力划分为3类, 术

前视力为1级的疗效最好(因2.8141>2.4977或2.5405>1.9600), 2级和3级没有明显的区别(因

0.7993与 1.1077都介与-2.4977~2.4977之间或0.6673与0.9643都介与-1.9600~1.9600之

间),4~5级的疗效最差(因-4.3521<-2.4977或-3.7165<-1.9600)。

摘自以下网站

/managesoft/2008/0303/