第二章 建立SAS数据集
前面我们介绍了关于SAS系统的一些基本概念以及基本的操作过程。我们知道SAS是以数据为中心的一个应用软件系统,一般来说,一个SAS的程序的运行,离不开SAS的数据集,数据必须以SAS数据集的格式存放才能被许多SAS程序处理。本章我们介绍建立SAS数据集的两种基本方法。
一.利用窗口输入数据
首先我们介绍一种比较直观,也比较简单的方法来建立SAS数据集,就是利用SAS/FSP模块中的过程FSEDIT 和FSVIEW来进行。
1. The FSEDIT and FSVIEW Procedures(FSEDIT 和FSVIEW过程)
SAS/FSP模块对SAS数据的输入、编辑等提供了非常方便的用户截面,它由以下一些过程组成:
过程名 |
用途 |
FSBROWSE |
显示SAS数据文件的内容 |
FSEDIT |
显示、输入、修改SAS数据文件的内容 建立新的SAS数据集 |
FSLETTER |
建立、编辑、打印格式化的信件和报告 |
FSLIST |
浏览外部(非SAS)文件 |
FSVIEW |
以表格方式显示、输入、修改SAS数据文件的内容 建立新的SAS数据集 |
我们将介绍其中可用于建立SAS数据集的FSEDIT 和FSVIEW过程。
1) 如果使用FSEDIT过程输入或修改SAS数据集的内容,它每次显示一个观测(observation)中的内容。
2) 如果使用FSVIEW过程输入或修改SAS数据集的内容,你可以同时看到多个观测(observations)中的内容。
例:用FSEDIT 和FSVIEW过程修改SAS数据集时分别会显示
FSEDIT |
Obs 1 |
|
FSVIEW |
|
|
|
|
|
|
OBS |
NAME |
DEPT |
ROOM |
NAME |
Joe Wise |
|
1 |
Joe Wise |
Sales |
G-320 |
DEPT |
Sales |
|
2 |
Sam Chow |
Mkt |
F-110 |
ROOM |
G-320 |
|
3 |
Sue Hart |
CBT |
A-309 |
INDATE |
03/24/79 |
|
4 |
Jan Grime |
QC |
X-180 |
使用FSEDIT 或FSVIEW过程建立SAS数据集的步骤:
1) 提交一个过程步,指明要创建的数据集,FSEDIT 或FSVIEW过程的运行会打开FSEDIT NEW或FSVIEW NEW窗口
2) 在FSEDIT NEW或FSVIEWNEW窗口指定变量的特征信息
3) 关闭FSEDIT NEW或FSVIEWNEW窗口,进入FSEDIT 或FSVIEW窗口,创建观测并输入数据。注意:一旦离开NEW窗口,就无法再回去了。
4) 结束该过程,并保存数据集。
2. Creating a New Data Set(建立新的数据集)
现在,我们假设你要建立一个永久的数据集,也就是说,你要建立的数据集将防在一个永久的SAS数据库中。因此,在建立你的数据集之前,先要用LIBNAME语句给你的数据库指定一个标记(libref),用法:
LIBNAME libref 'SAS-data-library';
然后,调用FSEDIT 或FSVIEW过程创建新的数据集,用法:
PROCFSEDIT NEW=sas-date-set;
或 PROC FSVIEW NEW=sas-date-set;
例:在程序编辑器中输入以下程序:
libname students 'd:\hu\data1';
proc fsedit new=students.f97;
run;
然后,选择 LocalsàSubmit 提交这段程序,就会出现FSEDIT NEW窗口。在这个窗口中,你就可以设定数据集students.f97中有多少变量及各变量的属性。
3. Specifying Variable Attributes(设定变量的属性)
在FSEDIT NEW或FSVIEW NEW窗口中,每一行代表一个变量,每一列表示变量的一种属性,你可以在表中填写来设定新数据集中的变量。这些属性包括:
1)变量名(Name):要创建的变量的名字,要符合SAS的命名规则。
2)类型(Type):变量的类型,字符用$或C表示,数字用N或空格表示,缺省为数字。
3)长度(Length):变量的长度,字符型变量不超过200,缺省为8字节。注意,对数字型变量,长度为2-8,是指储存该变量的字节数,而非数字(或小数点)位数。
4)标记(Label):用于说明该变量,长度为1-40的字符串。
5)格式(Format):变量的输出格式。
6)输入格式(Informat):变量的输入格式。
其中,属性1)2)3)是每一个变量所必须有的。
注意:窗口中只出现Format和Informat其中之一,可选择用 LocalsàFormat/Informat进行来回切换。
完成数据集中所有变量的设定以后,仔细检查一遍,然后选择
Viewà End
退出NEW窗口,你便会进入FSEDIT或FSVIEW的窗口,输入你的观测数据。
4. Creating a Data Set Like an ExistingOne(创建有同样结构的数据集)
如果你要创建的新数据集与某一已有的数据集有相同或相近的结构的话,就是说两者中的变量数及其属性都一样或只有很少不同的话,你可以利用FSEDIT或FSVIEW过程的LIKE选项来提高创建新数据集的效率。
例如:在程序编辑器中输入以下程序:
proc fsview new=students.f97 like=students.f96;
run;
然后,提交这段程序,就会出现FSVIEWNEW窗口。在这个窗口中,对数据集students.f97已预先设定好与students.f96完全相同的变量结构,你可在此基础上进行修改,或全盘接受,然后退出FSVIEWNEW窗口,进入FSVIEW的窗口,输入观测数据。
5. Editing Commands(编辑命令)
你可以分别用以下的操作命令来输入或修改你创建的数据集中的数据
1)在FSEDIT中
操作命令 |
功能 |
Edit à Add new record |
创建并显示一个新的空的观测 |
Edit à Delete record |
删除当前显示的观测 |
Edit à Duplicate record |
复制当前显示的观测,并显示该新观测供编辑 |
在窗口上方会显示是第几个观测,用“PageUp”和“Page Down”键可在已有的观测之间移动。
2)在FSVIEW中
操作命令 |
功能 |
Edit à Autoadd |
自动在最后创建并显示一个新的空的观测 |
Edit à Delete … |
删除当前显示中的某一个或几个观测 |
Edit à Duplicate … |
复制当前显示中的某一个或几个观测 |
可用“Tab”键是光标在不同的变量之间移动,输入或修改完最后一个观测中的变量后,按“Enter”可进入自动在最后创建的新观测。
二.利用数据步读取数据
1. Introductionto DATA Step(数据步简介)
SAS的数据步由一组SAS语句组成,它由DATA语句作为开始。在执行过程中,DATA语句使系统开始建立一个数据集,并指明该数据集的名字。系统会检查数据步的语法,如果语法正确,数据步中的语句就会被执行,数据集就会建立起来。
1)数据步的一般语法
利用数据步建立SAS数据集,有两种方式可以输入数据:一是将数据数据排列在变量名串之后;二是数据的出处,也就是指定一个外部数据文件供读取。
第一种方式的一般语法为:
DATAsas-data-set-name;
INPUT var1var2;
CARDS;
d11 d12
d21 d22
d31 d32
d41 d42
;
RUN;
例:
DATAstudent.f96;
INPUT numbername $;
CARDS;
9641001 zhao
9641002 qian
9641003 shun
9641004 li
;
RUN;
其中,DATA、INPUT和CARDS三个关键词缺一不可,注意数据集名和变量名要符合SAS命名规则。
第二种方式的一般语法为:
DATAsas-data-set-name;
INFILE 'input-file-name';
INPUTvar1 var2;
RUN;
例:
DATAstudent.f96;
INFILE'd:\student\f96.txt';
INPUT numbername $;
RUN;
第二种方式中用INFILE语句指定了一个外部数据文件,所有需要输入的数据存放在该文件中,从而取代了第一种方式中的CARD语句及其下列的一连串数据,当数据比较多的时候,用第二种方式可以使程序看上去显得比较简洁。注意,这里,INFILE语句在INPUT语句之前,而在第一种方式中,CARD语句在INPUT语句之后。下面,我们主要以第二种方式为例来进行介绍。
2)指定数据集的名字
DATA语句指定了我们要建立的SAS数据集的名字。一个SAS数据集也是一个SAS文件,SAS系统通过一个二级名来识别一个SAS文件,二级名的组成为: libref.filename。其中,libref为库标记,filename为文件名,当libref=work时,库标记可省略。
3)指定外部数据文件
INFILE语句用于指定一个包含原始数据的外部文件,它必须在INPUT语句之前执行。该语句的一般形式为:
INFILE'file-name' options;
file-name即为该外部文件名,包含其路径,两边用单引号。如果该文件名包括其路径比较长,或在程序中会不止一次用到的话,可在程序开始用FILENAME语句给它设定一个文件标记(fileref),文件标记的性质可类比与数据库标记(libref)。
利用INFILE语句中的选项(options)可以有选择地读取外部文件中的记录:
A. FIRSTOBS=n1表示从第n1条记录开始读取
B.OBS=n2表示共读取n2条记录
4)指定变量名及其属性
INPUT语句要指定如何读取数据并将之赋予每个变量。因此,在INPUT语句中,你必须给出:
A. 有效的SAS变量名
B. 变量的类型和长度
INPUT语句的一般形式为(采用列模式时):
INPUT variable $ startcol-endcol;
5)检查数据集内容
当你成功地建立了一个数据集以后,你可能很想看一下这个数据集中的内容,检查一下是否有差错。你可以用FSVIEW过程或PRINT过程来显示所生成的数据集。用法分别为:
PROCFSVIEW DATA=sas-data-set-name; run;
或 PROC PRINT DATA==sas-data-set-name;run;
FSVIEW过程在FSVIEW窗口中显示数据集内容;而PRINT过程在OUTPUT窗口中显示数据集内容。
6)例子
下面我们看一个数据步的例子:
libname student 'd:\users\hu\sas\tudents'; 指定数据库标记
filename f97data 'd:\users\hu\data\student\f97.dat' 指定外部数据文件标记
data student.f97; 指定创建的数据集名
infile f97data; 指定用于读取数据的外部文件
input number 1-7name $ 9-16 score 18-20 指定数据集变量及属性
proc print data=student; 检查数据集内容
run; 使以上程序步运行
2. ReadingData in Fixed Fields(按固定列读取数据)
1)固定域数据
在文件中,原始数据可以按照列,或者固定的域来组织,比如:
----+----1----+----2----+
BIRDFEEDER |LG088| 3|20
6 GLASS MUGS|SB082| 6|12
GLASSTRAY |BQ049|12| 6
PADDEDHANGRS|MN256|15|20
JEWELRYBOX |AJ498|23| 0
REDAPRON |AQ072| 9|12
对于这种按固定域排列的原始数据,SAS提供两种数据读入方式:列模式和格式化模式。
列模式输入及其优点
按列模式输入,对每一个域都设定其开始和结束的列,字符变量用$号表示。比如,对上面的数据,INPUT语句的写法为:
inputitem $ 1-13 idnum 15-19 instock 21-22 backord 24-25;
采用列模式输入有不少好处:
A. 可以按任意顺序读取这些域
B. 字符型变量可以长达200字符,并且内含空格
C. 空域被认为是遗漏数据,不会引起误读其它域的问题
D. 域或域的部分可以被重读
E. 域之间不需要用空格或其它符号分隔
标准与非标准数据
标准的数字型变量数据仅包含数字、科学记数符号、小数点和负号。字符型变量数据可包含任意字符、下划线、数字和符号。如果数字型变量数据中包含诸如逗号和美元符号的话,就被认为是非标准数据,非标准数字型变量包括:
A. 数据中含有特殊符号,如百分号、逗号和美元符号
B. 日期和时间数据
C. 分数、二进制或八进制的数据
对于固定域数据,列模式输入只能读取标准数据,而格式化模式输入则既能读标准数据,也能读非标准数据。
2) 格式化模式输入
按格式化模式输入时,INPUT语句的写法为:
INPUTpoint-control variable informat……;
其中,point-control为输入指针控制,将输入指针移到数据域的开始位置,variable定义变量名,informat定义输入格式。
例如:
input@1 lname $7. +1 fname $5. @15 jobtitle 3. +1 salary comm9.;
2)输入指针控制
在按格式化模式输入时,有两种输入指针控制方式:
A. @n :绝对指针控制,将输入指针移到第n列,可以前后移动
例:对一条记录:
----+----1----+----2----+--
EVANS DONNY 112 29,996.63
可以使用如下INPUT语句:
input@9 fname $5. @19 salary comma9. @15 jobtitle 3.;
B. +n :相对指针控制,将输入指针从当前位置向前移n列,不能后移
例:同样对上述记录,可以使用如下INPUT语句:
inputlname $7. +1 fname $5. +1 jobtitle 3. +1 salary comma9.;
或 input lname $7. +1 fname $5. +5 salary comma9.;
绝对指针控制 @n和相对指针控制 +n可混合使用,例:
inputlname $7. +1 fname $5. +5 salary comma9. @15 jobtitle 3.;
或 input @9 fname $5. @1 lanme $7. +11 salarycomma9. @15 jobtitle 3.;
另外,列模式和格式化模式也可混合使用,例:
inputlname $ 1-11 @9 fname $5. +5 salary comma9.;
3)SAS输入格式
下面我们来看SAS的输入格式informat,它指导系统如何读取数据。SAS系统提供许多输入格式,上面我们用到的是最常用的一些,解释如下:
$w. 用于读取字符型数据,$表示是字符,w表示域宽度
w.d 用于读取标准数字型数据,w表示域宽度,d表示小数点位数,可省略
COMMAw.d 用于读取非标准数字型数据,COMMA是关键词,w表示域宽度,
d表示小数点后位数,若数据中已包含小数点,可省略
你可以在SAS的HELP窗口中找到所有的SAS输入格式,方法为:
在任意窗口中,选择:
Help à SAS System à SASLANGUAGE à SASFormats and Informats
4)记录的格式
记录的格式是指,在外部文件中,记录是如何储存的,两种常见的记录格式为:
A.固定长度记录:每条记录的长度相同,典型的长度为80列,例如
----+----1----+----2----+----3----+----4----+----5----……
尽管每条记录中包含的域不同,但后面用空格填补,因而每条记录的长度都一样。
B.变动长度记录:各条记录的长度不同,例如:
----+----1----+----2----+----3----+---
由于在最后一个域后面立即就是一个结束记录的符号,而每条记录中的域数不同,因而每条记录的长度不一样。
5)有固定域数据的变动长度记录
当读取含有变动长度记录的文件时,系统可能会发生误读错误,例如:
----+----1----+----2
BED/BATH 1,354.93
HOUSWEARES 2,464.05
GARDEN 923.34
GRILL 598.34
SPORTS
TOYS 6,536.53
对上述记录,如果用下列语句读取数据:
input dept $ 1-11 @13 totrcpts comma8.;
当读到第三条记录的totrcpts变量的数据时,系统在读满8列之前遇到记录结束的符号,于是转向下一条记录,试图完成对该变量的读取,但GRILL是字符而非数值,因此,系统认为该数据无效。
为避免上述问题,对含有变动长度记录的文件,可在INFILE语句中使用PAD选项:
INFILEfileref PAD;
PAD选项会在每条记录填补空格,使它们具有同样的长度。
3. ReadingDate and Time Values(读取日期和时间值)
1)日期和时间数据
由于日期的表示方法很多,SAS系统读入数据时必须使用输入格式。SAS系统读入日期和时间数据后,将其转化为SAS日期值,它是一个数值型变量值。你可以方便地利用SAS日期值进行排序或计算。
SAS系统用三种不同的方法将一个日期的表达转化为SAS日期值:
A.日期值用从1960年1月1日到这一天的天数来表示
例: 1959.1.1. ßà -365
1960.1.1. ßà 0
1961.1.1. ßà 366
B.时间值用从0点到该时刻的秒数来表示
例: 12:00 am ßà 0
12:15 pm ßà44100
5:00 pm ßà61200
C.日期时间值用从1960年1月1日0点到该时刻的秒数来表示
例: 1776.7.4. 11:30:23 ßà -5790400177
1960.1.1. 0时 ßà 0
1989.4.22.16:10:45 ßà 924883845
2)日期和时间的输入格式
SAS系统用特别的日期和时间输入格式读取用不同方式表达的日期和时间数据并将其转化为SAS日期值。例见下表
日期表示值 |
SAS输入格式 |
SAS日期值 |
11/05/1990 |
MMDDYYw. |
11266 |
18DEC1985 |
DATEw. |
9483 |
06-29-1958 |
MMDDYYw. |
-551 |
08:32:13.35 |
TIMEw. |
30733.35 |
你可以用格式化输入的方法来读取日期和时间数据:
INPUTpoint-control variable informat.;
你可以在SAS的HELP窗口中找到所有的SAS输入格式,方法同上。
3)常用日期和时间的输入格式
在此,我们列出一些常用的日期和时间输入格式:
A.DATEw. 读形如ddmmmyy或ddmmmyyyy的日期值
例:12JAN90 à date7.
12-JAN-90 à date9.
B.DATETIMEw. 读形如ddmmmyy或ddmmmyyyy的日期后跟形如hh:mm或hh:mm:ss.ss的时间的值,日期和时间之间用空格或一特殊字符分隔
例:12JAN90/12:02:23.24 à datetime19.
12-JAN-90 12:02 àdatetime15.
C.MMDDYYw. 读形如mmddyy或mmddyyyy的日期值
例:01/12/90 à mmddyy8.
01-12-1990 à mmddyy10.
D.TIMEw. 读形如hh:mm或hh:mm:ss.ss的时间的值
例:12:02:23.24 à time11.
2:02 à time5.
4)YEARCUTOFF=选项
在读取日期数据时,如果你用两位数表示年份,SAS系统在将该日期转化为SAS日期值时会自动加上前两位。自动加上的前两位取决于SAS系统的一个选项:YEARCUTOFF=。它的缺省值是1990。例如:
04/15/00 被认为是 04/15/1900
15APR95 被认为是 15APR1995
YEARCUTOFF=选项决定采用两位数表示年份时所在的100年。YEARCUTOFF=1900表示所有用两位数表示的年份均在1900--1999之间。
你可以用OPTIONS语句或用OPTIONS窗口来改变YEARCUTOFF=选项,例如:
optionsyearcutoff=1950;
run;
该选项改变以后,用两位数表示的年份在转化为SAS日期值时,其所在的100年就变为1950-2049之间了。例如:
04/15/00 被认为是 04/15/2000
15APR95 被认为是 15APR1995
5)注意事项
读取日期和时间数据时应注意以下几点:
A.小心YEARCUTOFF=选项的缺省设置,并在必要时改变它
B.设定合适的输入格式
C.设定合适的域宽以读入完整的日期值
D.SAS日期值从A.D. 1582年到A.D. 20000年
E.SAS系统对闰年有调整,但忽略闰秒
6)用日期和时间值进行计算
由于SAS日期值是数值型变量,你可以用它来进行计算。例如:
data perm.aprbills;
infile aprdata;
input lname $8. @10datein mmddyy8. +1 dateout mmddyy8.
+1roomrate 6. @35 equpcost 6.;
days=dateout-datein+1;
roomchg=days*roomrate;
total=roomchg+equpcost;
run;
4. ReadingFree-Format Data(读取自由格式数据)
1)自由格式数据
上面我们考虑的都是固定域的数据,但是包含原始数据的外部文件也很可能是自由格式的,或者说,其中的数据不是按照固定域排列的。例如
----+----1----+----2----+----3----+
ABRAMS L.MARKETING $18,209.03
BARCLAY M.MARKETING $18,435.71
COURTNEY W.MARKETING $20,006.16
FARLEY J.PUBLICATIONS $21,305.89
HEINS W.PUBLICATIONS $20,539.23
或
----+----1----+----2----+----3----+
ABRAMS*L.*MARKETING*$18,209.03
BARCLAY*M.*MARKETING*$18,435.71
COURTNEY*W.*MARKETING*$20,006.16
FARLEY*J.*PUBLICATIONS*$21,305.89
HEINS*W.*PUBLICATIONS*$20,539.23
这些域之间可能是以空格分隔,也可能用其他的分界符分隔。
2)列表输入
自由格式数据可以简单地用列表输入方式读取,因为你无须指定数据从第几列开始,你只需要按照数据排列的顺序列出变量名即可。列表输入的一般形式为:
INPUTvariable $;
例如:
inputname $ age bankcard;
注意,你必须在变量名后用$符号标明字符型变量。
3)列表输入的规则和限制
A. 域之间必须有至少一个空格或其他的分界符分隔
B. 必须按顺序读取,从左到右,不得跳过或重读域
C. 不管对字符型或数字型变量,遗漏数据必须用一个“.”指明
D. 所有变量长度为8,超过长度的字符型变量值被截断,但是域的宽度可以超过8列
E. 数据必须是标准的数字型或字符型变量
F. 字符型变量不得内含空格
4)DLM=选项
如果原始数据文件中用不同于空格的分界符来分隔不同的域,你可以在INFILE 语句中用DLM=选项来设定分界符。一般形式为:
INFILEfile-specification DLM='characters';
例如:对下列文件 Fileref:CREDIT
----+----1----+----2
MALE,27,1,8,0,0
FEMALE,29,3,14,5,10
FEMALE,34,2,10,3,3
MALE,35,2,12,4,8
用 infile credit dlm=',';
5)MISSOVER选项和遗漏数据
如果你的原始数据文件在某些记录的最后一个或几个域中有遗漏数据的话,你可以在INFILE 语句中用MISSOVER选项来防止系统转到下一个记录继续读取数据。一般形式为:
INFILEfile-specification MISSOVER;
例如:对下列文件 Fileref:CREDIT
----+----1----+----2
MALE 27 1 8 0 0
FEMALE 29 3 14 510
FEMALE 34 2 10
MALE 35 2 12 4 8
用 infile credit missover;
如果你的原始数据文件在某些记录的开始或中间的域中有遗漏数据的话,为了要使用列表输入,你就必须对你的原始数据文件进行编辑,用一个“.”来代替文件中的遗漏数据。例如:
----+----1----+----2
MALE 27 1 8 0 0
. 29 3 14 5 10
FEMALE . 2 10 33
MALE 35 2 12 4 8
6)LENGTH语句
如果有字符型变量的长度超过8,你可以用LENGTH语句来定义,以免被截断。其一般形式为:
LENGTHvariable $ length;
例如: length lname fname $ 20;
或 length lname $ 20 fname $ 15;
注意,在DATA步中,变量的属性在当它第一次出现时确定,因此,LENGTH语句应该放在INPUT语句之前。另外,在LENGTH语句中已经定义为字符型的变量,在INPUT语句中可以不再用$符号指明起字符属性,当然,保留$符号也不会引起错误。
例如:对下列文件 Fileref:citydata
----+----1----+----2----+----3
ANCHORAGE 488081174431
ATLANTA 495039425022
PHILADELPHIA1949996 1688210
SACRAMENTO257105 275741
用: data perm.growth;
infilecitydata;
length city $12;
input city $pop70 pop80;
proc printdata=perm.growth;
run;
7)修正列表输入
在使用列表输入时,下面两个格式修正符可以帮助你更方便地读取数据:
A.“&”符号使你能读取内含单个空格的字符型变量
B.“:”符号使你能读取非标准数据或长于8个字符但不内含空格的字符型变量
一般形式为:
INPUTvariable :|& informat.;
例如:对下列文件 Fileref:topten
----+----1----+----2----+
1 NEWYORK 7,262,700
2 LOSANGELES 3,259,340
3CHICAGO 3,009,530
4HOUSTON 1,728,910
5 PHILADELPHIA 1,642,900
8DALLAS 1,003,520
9 SANANTONIO 914,350
10PHOENIX 894,070
可用 dataperm.cityrank;
infiletopten;
input rankcity & $12. pop86 : comma.;
run;
注意,当你使用格式修正符“&”时,域之间必须用两个连续的空格进行分隔。另外,由于在列表输入时,系统以遇到分界符(空格)为一个数据的结束,因此,对数字型变量的输入格式 COMMAw.,你不必设定宽度w。
8)格式化输入和修正列表输入的输入格式
同样的输入格式,在格式化输入和修正列表输入中,它们的实际效果是不同的。比如对上例,比较下面两种输入方法:
A. input @3 city$12.;
B. input rank city& $12.;
用A方法,每次读12列,不管其中是否包含空格,而用B方法,输入格式仅指明字符变量的长度,读取数据时,遇到两个连续空格时就会停止。
9)混合输入方式
为了方便用户,SAS系统允许在INPUT语句中混合使用各种输入方式。
例如:对 Fileref: rawdata
----+----1----+----2----+----3----+----4
209-20-3721 07JAN78 41,983 SALES 2896
223-96-8933 03MAY86 27,356 EDUCATION2344
232-18-348517AUG81 33,167 MARKETING 2674
251-25-939208SEP84 34,033 RESEARCH 2956
可用
data perm.mixed;
infile rawdata;
input ssn $ 1-11@13 hiredate date7. @21 salary comm6. Dept : $9. Phone;
run;
5. ReadingMultiple Records per Observation(由数条记录读取一条观测)
1)一条观测包含数条记录
在有些原始数据文件中,SAS系统所需要的一条观测分布与数条记录中,例如
Raw Data File SAS Data Set
----+----1----+---
ABRAMS THOMAS LNAME FNAME DEPT JOBCODE SALARY
MARKETING SR01
$25,209.03 --> 1 ABRAMS THOMAS MARKETING SR01 25209.03
BARCLAY ROBERT 2 BARCLAY ROBERT EDUCATION IN01 24435.71
EDUCATION IN01 3 COURTNEY MARK PUBLICATIONS TW01 24006.16
$24,435.71
COURTNEY MARK
PUBLICATIONS TW01
$24,006.16
你可以用几个INPUT语句读每一条记录,来构成一条观测:
input lname $ 1-8 fname $ 10-15;
input dept $ 1-12 jobcode $ 15-19;
input salary comma10.;
你也可以利用行指针控制,在一个INPUT语句中完成这些工作。
2)行指针控制“/”
“/”使输入指针转移到下一个记录。
例如,对原始数据文件 Fileref:memdata
----+----1----+----2
LEEATHNOS
1215RAINTREE CIRCLE
PHOENIX AZ 85044
HEIDIEBAKER
1751 DIEHLROAD
ALEXANDRIA VA 22314
可用
dataperm.members;
infile memdata;
input fname $ lname $ /
address $20. /
city : $10. state $ zip;
run;
3)行指针控制“#n”
“#n” 使输入指针转移到第n个记录。它能让你以任意顺序读取这n个记录。
例如,对原始数据文件 Fileref:memdata
----+----1----+----2----
ALEXBEDWAN
609 WILTONMEADOW DRIVE
GARNER NC27529
XM034FLOYD
ALISONBEYER
8521 HOLLYSPRINGS ROAD
APEX NC 27502
XF124LAWSON
可用
dataperm.patients;
infile patdata;
input #4 idnum $5.
#1 fname $ lname $
#3 city $ state $ zip;
run;
6. ReadingMultiple Observations per record(由一条记录读取数条观测)
1)一条记录包含数条观测
在有些文件中,每一条记录可能包含SAS所需要的数条记录,它可能有以下几种情况:
A.重复的块
例如:
----+----1----+----2----+----3-
01FEB90 1689.45 02FEB90 2167.34
B.相同数目重复的域
例如:
----+----1----+----2----+----3
001 WALKING AEROBICS CYCLING
002 TENNIS JOGGING SWIMMING
C.不同数目重复的域
----+----1----+----2----+----3
001 WALKING AEROBICS CYCLING
002 TENNIS
003 JOGGING SWIMMING
2)读取重复的块
为读取含重复块的记录,你只需在INPUT语句中加入行停留符@@即可。例如:
Fileref: TEMPDATA
data perm.april90; >----+----1----+----2----+----3--
infile tempdata; 01APR90 68 02APR90 67 03APR9070
input date : date7. 04APR90 74 05APR90 72 06APR90 73
hightemp @@; 07APR90 71 08APR90 75 09APR90 76
run; 10APR90 78 11APR90 70 12APR90 69
3)读取相同数目重复的域
重复的域的意思是说,在一个记录中,包含一个特征域(id field)和若干信息域,这若干信息域中所含的信息均对应于特征域所指的对象。也就是说,SAS的一条观测所包含的变量应由特征域和其中一个信息域组成。
为读取相同数目重复的域,要使用行停留符@和DO循环及OUTPUT语句。例如:
Fileref:DATA89
data perm.sales89;
infile data89; >----+----1----+----2----+----3----+----4
input idnum 4. @; 07341,323.34 2,472.85 3,276.65 5,345.52
do quarter=1 to 4; 09431,908.34 2,560.38 3,472.09 5,290.86
input sales : comma8. @; 1009 2,934.12 3,308.41 4,176.18 7,581.81
output; 10431,295.38 5,980.28 8,876.84 6,345.94
end; 11902,189.84 5,023.57 2,794.67 4,243.35
run; 1382 3,456.34 2,065.83 3,139.08 6,503.49
4)读取不同数目重复的域
如果在记录中重复域的数目不同的话,可在INFILE语句中使用MISSOVER选项,同时,用DO WHILE循环代替上述的DO循环。例如:
data perm.sales89; Fileref: DATA89
1. infile data89 missover;
input idnum 4. sales : comma8.@; >----+----1----+----2----+
quarter=0; 1824 1,323.342,472.85
do while (sales ne .); 1943 1,908.34
quarter+1; 2046 1,423.521,673.46
output; 2063 2,345.34
input sales : comma8. @;
end;
run;
5)行停留符@@和@
上面我们用到了行停留符@@和@,它们的作用都是使输入指针停留在当前记录,也就是说,使下一条INPUT语句能在同一条记录中读取数据。它们都用在INPUT语句的最后,如果遇到一个最后没有行停留符的INPUT语句,则下一个INPUT语句就从下一条记录中开始读取数据。它们的区别在于:
A.行停留符@@的作用比较持久,它可以在DATA步的循环中持续保持。
B.行停留符@仅在DATA步的一次循环中起作用,DATA步开始下一轮循环时,会从下一条记录开始。
6)DO循环
DO循环可以使在DO语句和END语句之间的SAS语句重复执行。一般形式为:
DOindex-variable specification;
More SASstatements;
END;
其中,index-variable是一个指标变量,决定DO循环的执行,条件(specification)可以是离散的,如:
doa=1,5,40;
或设定范围的,如:
doa=1 to 5;
或 do a=10 to 100 by 10;
7)DO WHILE循环
DO WHILE循环在条件为真时重复执行DO WHILE语句和END语句之间的SAS语句。一般形式为:
DOWHILE (expression);
More SASstatements;
END;
在循环的顶部,检验expression,当它为真时,执行循环内语句,否则,不执行。
8)SUM语句
SUM语句把一个表达式的结果加入到一个累积变量中。一般形式为:
Variable+expression;
例如:
time+1;
balance+(-debit);
9)OUTPUT语句
OUTPUT语句将当前的观测立即写入SAS数据集。事实上,在每个DATA步的最后,都隐含一个OUTPUT语句。OUTPUT语句的一般形式为:
OUTPUTSAS-data-set;
SAS-data-set是要写入的SAS数据集名,如果与DATA语句中设定的数据集名一致的话,可省略。
7. ReadingHierarchical Files(读取分级文件)
1)分级文件
这里,我们所说的分级文件是指在原始数据文件中的包含这样的结构:它由一些头记录,每条头记录后跟一条或几条详细记录所组成。例如:
Raw Data File
>----+----1----+--
header P 1095
detail C 01-08-89 $45.0
detail C 01-17-89 $37.5
header P 1096
detail C 01-09-89 $156.5
header P 1097
detail C 01-02-89 $109.0
header P 1099
detail C 01-03-89 $45.0
detail C 01-05-89 $45.0
header P 1201
detail C 01-05-89 $37.0
其中,每条记录的第一列标明,该记录是头记录或是详细记录。基于这样的数据文件,你可能希望对每一个详细记录建立一条观测,如:
OBS PATID DATE AMOUNT
1 1095 01/08/89 $45.00
2 1095 01/17/89 $37.50
3 1096 01/09/89 $156.50
4 1097 01/02/89 $109.00
或者,对每一个头记录建立一条观测,如:
OBS PATID TOTAL
1 1095 $82.50
2 1096 $156.50
3 1097 $109.00
对每一个详细记录建立一条观测
为了对每一个详细记录建立一条观测,可按以下步骤进行:
A.引入确定记录类型的变量,并在输出时将其丢弃
B.在DATA步的循环过程中保留头记录的内容
C.读取记录中确定记录类型的域
D.若是头记录,读取记录内容
E.若是详细记录,读取记录内容,并在数据集中写入一条观测
例如: Fileref: CENSUS
data perm.people(drop=type); >----+----1----+----2
infile census; H 321 S. MAINST
retain address; P MARY E 21 F
input type $1. @; P WILLIAM M 23M
if type='H' then input @3 address $15.; P SUSAN K 3 F
if type='P'; H 324 S.MAIN ST
input @3 name $10. @13 age 3. @16 gender $1.; P THOMAS H 79 M
run; P WALTER S 46 M
P ALICEA 42 F
注意,由于“ if type='P'; ”当条件不成立时,DATA步下面所有的语句都不执行,直接返回DATA步首,因此读取头记录时没有输出。而读取详细记录时,DATA步最后隐含的OUTPUT语句起作用,会输出一条观测到数据集中去。
对每一个头记录建立一条观测
为了对每一个详细记录建立一条观测,可按以下步骤进行:
A. 引入确定记录类型的变量,并在输出时将其丢弃
B.定义一个变量,用于判断是否已读到外部文件的最后一条记录
C.在DATA步的循环过程中保留头记录的内容
D.读取记录中确定记录类型的域
E.若是头记录,判断它是否第一条头记录
F.如果不是第一条头记录,则执行输出(OUTPUT)语句
G.读取头记录内容
H.若是详细记录,读取记录内容,并进行相应的计算
I.若已读到最后一条记录,则将最后一条观测写入数据集
例如: Fileref: CENSUS
data perm.residnts(drop=type);
infile census end=last; >----+----1----+----2
retain address; H 321 S. MAIN ST
input type $1. @; P MARY E 21 F
if type='H' then do; P WILLIAM M 23 M
if _n_ > 1 then output; P SUSAN K 3 F
total=0; H 324 S. MAINST
input address $ 3-17; P THOMAS H 79 M
end; P WALTERS 46 M
else if type='P' then total+1; P ALICE A 42 F
if last then output;
run;
4)DROP=选项
在DATA语句中的DORP=选项,可使某个在DATA步中出现的变量不被写入SAS数据集中。一般形式为:
DATASAS-data-set(DROP=variable);
注意,该选项用括号括起。
5)_N_变量
_N_是一个自动变量,它记录DATA步执行的次数。
6)END=选项
在INFILE语句中设定一个END=选项可使你确定是否已读到文件尾。一般形式为:
INFILEfile-specification END=variable;
其中variable是一个临时的数字型变量,当读完最后一行时,它的值是1,在这之前,它的值为0。同上述自动变量_N_一样,它不会被写入SAS数据集。
7)DO/END语句组
一般形式为:
DO;
More SASstatements;
END;
表明一组SAS语句被当作一个单位执行。它区别于DO循环和DO/WHILE循环。一般用在IF-THEN语句中条件地执行多个SAS语句。
8)RETAIN语句
一般形式为:
RETAINvariable;
其中,variable是你希望在DATA步的循环中保持起内容的变量名。你也可以在一个RETAIN语句中一个以上的变量,如:
retainidnum jobcode;
如果在RETAIN语句不设定任何变量,则数据集中所有变量的内容将被保留。如
retain;
9)IF-THEN/ELSE语句
一般形式为:
IFexpression THEN statement;
ELSE statement;
其中,statement是任意可执行的SAS语句。ELSE语句为可选,如果有的话,它必须紧接在IF-THEN语句后。
另外,一个特别的IF语句,其一般形式为:
IFexpression;
只有当条件满足时,DATA步剩下的语句才会被执行,否则,回到DATA步首。
8. ReadingVariable-Length Records(读取变动长度的记录)
前面我们已经遇到过变动长度的记录的读取,但每条记录中的域是按固定列排列的,或是在域之间有分界符隔开的。下面我们考虑以下两种情况:
1)含有变动域宽的变动长度记录
为读取含有变动域宽的变动长度记录中的数据,DATA步的语句应包含以下几点:
A.决定每条记录的长度
B.用行停留符停留在当前记录
C.从记录长度中减去固定宽度域的宽度
D.用$VARYINGw.的输入格式读取变动域宽的域
例: Fileref: PHONDAT
data perm.phones; >----+----1----+----2
infile phonedat length=reclen; 1802JOHNSON2123
input idnum 4. @; 1803BARKER2142
namelen=reclen-8; 1804EDMUNDSON2325
input name $varying10. namelen 1805RIVERS2543
phonext; 1806MASON2646
run; 1807JACKSON2049
2)含有变动域数的变动长度记录
假设每条记录中包含不同数目的重复块,但每个域有固定宽度,可按以下步骤读取数据:
A.决定每条记录的长度
B.用行停留符停留在当前记录
C.用重复的语句读取块中的数据,停留在当前记录,用OUTPUT语句输出,直到记录尾。
例如: Fileref: BPDATA
data perm.health;
infile bpdata length=reclen; >----+----1----+----2----+----3----
input idnum 4. @; 1234 13MAR89 120/80
do index=6 to reclen by 15; 1443 12FEB89 120/70 03FEB90 125/80
input date : date7. bp $ @; 1681 11JAN90 120/80 05JUN90 110/70
output; 2034 19NOV88 130/70 12MAY89 150/90
end;
run;
3)LENGTH=选项
一般形式:
INFILEfile-specification LENGTH=variable;
其中,variable是一个数字型变量名,它的值等于当前记录的长度。它不会被写入SAS数据集。
4)$VARYINGw.的输入格式
一般形式:
INPUTvariable $VARYINGw. Length-variable;
其中,variable是一个字符型变量,$VARYINGw.设定该变量的长度,Length-variable是一个数字型变量,它指明在当前记录中,这个字符变量的域宽。注意,在输入格式由两部分组成,另外,Length-variable的值应不大于w。