你可能有各种形式的数据,包括手写在纸上、存放在电脑上、或是在数据库管理系统里,不论如何,总有一种方法可以让SAS来读取。
SAS读取的数据的方法主要有以下几种类型:
直接输入;
从原始数据文件中创建一个SAS数据集(creating SAS data sets from raw data files);
将其他软件中的数据文件转换成SAS数据集;
直接读取其他软件的数据集;
直接输入
View table窗口可以让你以表格形式输入数据,可以定义变量、设置属性,如name、length和 type(character or numeric).
SAS 企业向导模块
SAS/FSP 模块,是Full Screen Product的简称,可以设计定制的数据输入窗口,也有检测数据输入错误的功能(The SAS/FSP product is licensed separately from Base SAS software.)。
从原始数据文件中创建一个SAS数据集
你有两种方法读取原始数据文件:
数据步可以读取任何形式的原始数据文件,比如text, ASCII, sequential, flat files。
导入向导(Import Wizard)、导入过程(IMPORT procedure)适用于UNIX、OpenVMS和 Windows操作环境的简单方法,可以读取CSV(comma-separated values)和其他一些限定的文件类型。
将其他软件中的数据文件转换成SAS数据集
如果数据在一个软件中以某种格式存放,但需要用另一种软件分析时,就会很麻烦。有几种方法可以将某种软件中的数据转换成SAS数据集:
如果安装SAS/ACCESS模块,可以用导入过程(import procedure)和导入向导(Import Wizard)将Excel、Lotus、dBase和Access文件导入SAS数据集。
如果没有安装,可以用存放数据的软件创建一个原始文件,并用数据步或导入过程(import procedure)读取。很多软件都可以创建CSV文件。
Windows操作环境下也可以用动态数据交换技术(Dynamic Data Exchange,DDE)。前提是必须有一个其他的Windows程序与SAS同时运行,再使用DDE和数据步。
直接读取其他软件的数据集
SAS/ACCESS产品可以不用转换数据格式读取数据,并适用于大部分数据库管理系统,包括ORACLE,DB2,INGRES和 SYBASE(但使用方法本书没有介绍)。
使用Excel engine和Access engine来读取这两种类型的数据。(SAS帮助文档)
还有其他的一些数据引擎(data engines)来读取数据,如SPSS engine(附录D),查
使用DATA步,通过INFILE语句指定原始数据文件;
SAS提供了以下3种基本输入方式:
列表输入
按列输入
格式化输入
一、列表输入
1) FILENAME语句指定到单个文件的文件引用
2) FILENAME语句指定到一组外部文件存储位置的文件引用
列表输入(List Input)用于读取原始数据记录中每个字段由至少一个分隔符隔开,并且数据值中不包含该分隔符的原始数据。列表输入默认分隔符为空格,连续的分隔符会当成一个分隔符处理,INPUT语句中包含了简单的变量名称列表。在SAS窗口中提交如下代码:
INPUT语句会逐行顺序地读取inventory.dat中的数据值,并赋值给变量。在读取每行数据时,遇到空格就停止读入当前数据值,并从非空格处读入下一个数据值。
3) 使用INFILE语句的选项DLM=指定分隔符
当原始数据中数据记录的数据值未使用空格,而是使用其他分隔符时,需在INFILE语句中使用DLM=选项,告诉SAS读入数据时需要使用的分隔符。
下面将上面外部数据文件的内容稍作修改以便比较。文件inventory_dlm.dat的内容如下,数据记录中的各数据值之间由逗号(,)隔开。
正确读取该数据文件的代码如下:
使用DLM=选项可处理原始数据记录中数据值中包含空格的情况。此外,使用DLM=选项的DATA步也可以很好地处理数据中的缺失值。如果接连有多个指定的分隔符,也会当成一个分隔符处理。但如果分隔符之间有空格,则该空格会当作缺失值读入变量并写入数据集。例如,当数据文件inventory_missing.dat的内容如下:
注意:当用dlm=“,”时,想要识别缺失数据必须使用空格作为占位符,否则没有空格只有两个逗号时,数据只会读入该行的第一个数据,并且之后的数据也不会读入;
提交与上例相同的SAS代码,PRINT过程打印的数据集内容如下图所示,其中第3个观测Instock变量为默认值:
4) 使用INFILE语句的选项DSD
DSD (Delimiter-Sensitive Data)
指定选项DSD后,如果数据值是由引号引起来的,可以将数据值中的分隔符当成是数据值的一部分读入,字符值中的引号在读入PDV时会被删除。DSD选项将默认的分隔符设置为逗号,还改变了使用列表输入时SAS处理分隔符的方式,比如,如果有两个连续的逗号,将被当作缺失值。
选项DSD还可以和其他选项(例如DLM=和DLMSTR=)一起使用。
5) 使用INFILE语句的选项missover
MISSOVER:会在DATA步的本次迭代中阻止INPUT语句读入原始数据的下一条记录,并将PDV中所有未赋值的变量保持为缺失值(PDV中变量未赋值时就为缺失值)。当原始数据记录中的最后一个或多个字段没有值且没有占位符时,并且希望SAS将对应的变量置为缺失值时使用MISSOVER。
外部数据文件missover.dat的内容如下,依次包括课程编号、课程名称、参加课程人数和讲师姓名等信息。其中第二条记录中未提供参加课程人数和讲师姓名,也没有占位符。
在INFILE语句中加上MISSOVER选项,代码如下:
PRINT过程打印的数据集如下图所示:
5) 使用INFILE语句的选项turnover
默认情况下(选项为FLOWOVER),当原始数据记录长度小于INPUT语句的预期时,INPUT语句自动读入下一条数据记录。当指定选项TRUNCOVER时,即使当前输入行数据的长度小于INPUT语句的预期,也会将当前输入行的数据赋值给当前处理的变量,并将其他没有赋值的变量设置为缺失值。
TRUNCOVER选项常用于处理变长的原始数据记录,可在INPUT语句中定义足够长度的变量,即使当前数据记录中的数据长度小于变量指定的长度,也可以将该记录从缓冲区读入PDV,并写入数据集,以便进一步处理。
原始数据文件comments.dat的内容如下,共3条记录,全部为文本,文本长度不确定。
使用TRUNCOVER选项读入该文件记录。设置变量Text的输入格式为“$500.”,当原始记录中文本长度不足500个字符时,TRUNCOVER选项会将当前输入缓冲区中的所有内容写入PDV,并写入数据集。
PRINT语句打印的数据集内容如下图所示。可以看到,所有的评论信息都读入了数据集中。
MISSOVER与TRUNCOVER的不同之处在于,如果当前变量没有读到要求长度的数据,MISSOVER会将当前变量的值也置为缺失值。还是以上面的示例为例,如果将TRUNCOVER换成MISSOVER,所生成的数据集中3个观测值都为缺失值。
5) 使用INFILE语句的选项PAD
选项LRECL为系统选项指定用于读写外部文件的默认逻辑记录长度。LRECL指定逻辑记录的长度为1(字节)或1024(k字节)的倍数。例如32表示32字节、16k表示16384字节。该选项的范围为1~32767。在SAS 9.4中,LRECL系统选项默认值为32767,通常不需要修改。
PAD和NOPAD选项控制SAS是否使用空格对从外部文件读入的记录进行填充,使其达到选项LRECL=指定的长度。默认设置为NOPAD。
当使用PAD选项时,SAS会自动用空格填充从外部文件中读入的记录长度。
还是以上面的comments.dat文件为例:
下面在INFILE语句中使用PAD选项,代码如下:
PRINT过程打印的数据集内容如下图所示。DATA步正确读入了文件中的所有评论。
6) 使用INFILE语句的选项控制输入
FIRSTOBS=
FIRSTOBS= 选项告诉SAS从哪一行开始读取数据,当数据开头有些说明信息,或者想要跳过某些行时,这个选项很有用。例如,如下原始数据文件中,开头两行是关于数据的描述:
那么用如下程序可以让SAS从第三行开始读取数据:
OBS= OBS=告诉SAS一直读取到哪一行位置,注意是行而不是观测值(有的观测值占据多行)比如,如下的原始数据文件中,结尾处还有一句不需要的数据说明时。就需要这个选项:
用FIRSTOBS=3和OBS=5就可以读取第三行到第五行的数据:
二、按列输入
当原始数据记录中的数据值在每条记录中占据相同的列时,可使用按列输入的方式。按列输入(Column Input)可以读取固定列的数据。
文件customer.dat的内容如下,其中,第114列为产品编号,第1626列为附属品牌,第2829列为专卖店数,第3135列为产品库存
数。
三、格式化输入
上面介绍的按列输入与列表输入一样,只能读取标准的字符或数字值到数据集中。SAS还可以读取特殊格式的数字数据,例如二进制数据、日期/时间(01FEB2013),或者包含逗号(1,262)、货币符号($87.3)等特殊字符的数字值。在这种情况下,就需要使用格式化输入(formatted input)了,即在INPUT语句中提供特殊的指令,以便SAS正确地读取原始数据记录中的数据值。这些特殊指令称为输入格式(Informat)。格式化输入组合了按列输入特征和读取非标准化数字或字符值的能力,保证数据值可正确地从原始数据记录中读入。
来看个示例,原始数据文件sales.dat的内容如下,该文件中原始数据记录包含字段依次为员工ID、部门、销售额和上次修改日期,其中销售额和日期都不是标准数字值,需使用对应的输入格式。
读入处理该文件的SAS代码如下,其中Sales和Date变量分别使用了输入格式comma6.和date9.,Emp_ID和Dept使用的是上面介绍过的按列输入方式。
在INPUT语句中,还使用了相对列控制符号+1和绝对列控制符号@22,分别表示将当前的输入列控制指针向前移1位和将该指针直接移动到列22。在上面的示例中,程序读入一行记录到输入缓冲区后,列控制指针的移动情况如下:
·第1~5列写入Emp_ID,列控制指针在第6列。
·第7~9列写入Dept,这时列控制指针在第10列。
·+1将列控制指针移到第11列。
·开始读入comma6.中指定的6列,即将第11~16列使用输入格式转换后写入Sales,这时列控制指针在第17列。
·@22将控制指针直接移到第22列,读入date9.中指定的9列,即第22~30列,然后使用该输入格式进行转换,并写入Date。
四、带修饰的列表输入
将列表输入、输入格式和修饰符结合起来,结合后就成了带修饰的列表输入(modified list input),这样可以使用列表输入方式更灵活地读入数据。
·&修饰符(ampersand format modifier):使用列表输入时,该修改符能够读入数据值中包含一个或多个嵌入空格的字符值,并指定字符的输入格式。SAS读入数据直到遇到两个连续的空格或达到所定义的数据长度或输入行结束才停止。&修饰符解决了使用列表输入方式读取数据值中包含嵌入空格的问题,但要求该包含空格的数据值与下一个数据值之间至少间隔两个空格。
·:修饰符(colon format modifier):使用列表输入时,该修改符可以在变量名后指定输入格式。SAS读入数据直到遇到空列、达到所定义的数据长度(对字符型变量来说)或输入行结束才停止。:修饰符可以读取超过8个字节的字符数据和包含特殊字符的数字字符。
·~修饰符(tilde forat modifier):可以读入并保持数据值中的单引号、双引号和分隔符。
原始数据文件customer2.dat的内容如下,每条记录包含联系人信息:客户ID、名字和出生日期,其中名字里面嵌入了空格,可使用&修饰符读入。注意,使用&修饰符要求名字和出生日期之间为两个空格。
处理该数据的SAS代码如下,其中,Name变量使用了&修饰符读入带空格的名字,并指定输入格式为$20.,所以Name变量的字符长度为20个字节,而且SAS会将缓冲区中的20个字符读入Name。Birth_Date使用了:修饰符读入日期格式的数据。
@’character’ 列指示器
@column列指示器可以让SAS直接从某列开始读取数据。但有时候你不知道要读取的数据是从哪列开始,此时你只要知道要读取的数据的前面那个字符或单词即可。比如有一个关于狗的原始文件,你想要读取狗的品种号,但文件排列很凌乱,只知道品种号跟随在单词breed后面,那么可以用如下方式读取:
Input @’Breed:’ DogBreed $;
例子 web日志是凌乱数据的一个很好例子,下面是一个网站的web日志,数据开始于访问IP,后面有访问日期、访问文件名等信息。
现在想要读取访问日期和访问的文件名,但是它们每行中所占据的列的位置都不同,而且文件名的长度每行都不一样,那么SAS读取这种文件通过如下方式:
@’[’作为列指示器,告诉SAS读取[之后的内容,@’GET’告诉SAS读取GET之后的内容,由于文件名作为字符串变量,这里基本都会超过8个字节,因此后面附加:$20。输出结果如下:
五、混合输入
在使用INPUT语句时不限于使用一种输入方式,可以在一条INPUT语句中混合使用这些输入方式,只要可以适当地描述原始数据记录就行。
原始数据文件mixedinput.dat的内容如下,其中依次包括了课程编号、课程名称、开课日期和报名人数等信息。
列表输入读取Course_ID和Attendee、按列输入读取Course_Name、格式化输入读取Open_Date。代码如下:
跨行观测值的读取方式:
一般原始文件中一行代表一个观测值,有时会出现一个观测值跨行的情况。由于SAS会自动转到下一行读取数据,直到读取这个观测的所有变量(input语句中给出),所以你需要告诉SAS什么时候不要换行,以便在日志中不出现SAS-went-to-a-new-line的暂停说明,此时需要在INPUT语句中加行指示器。
行指示器,斜线/:告诉SAS跳至原始数据的第二行;#n:跳至第n行,n代表原始数据中某观测值的行数(#2则让SAS跳至某观测值的第二行),#n不能用来回跳。
例子 有一组关于温度的数据,temperature.dat第一行代表城市和州,第二行代表本日最高温和最低温,第三行代表史上最高温和最低温。
用如下的程度来读取这份数据:
Input后面告诉SAS读取第一行的city变量和state变量,斜线/告诉SAS移动到下一行的第一列,以便读取normalhigh和normallow。#3告诉SAS移动到第三行的第一列以便继续读取观测值的recordhigh变量和recordlow变量。这里/可以用#2代替,也可以用/代替#3。
日志记录如下:
输出结果如下:
一行有多个观测值的原始文件读取
当一行出现多个观测值时,可以在input语句结尾加一个停止符号@@
例子 有一个关于降水量的数据,precipitation.dat,文件包含城市名、州名、月平均降水量、月平均降水天数:
这个数据文件中,第一行包含了两个观测值,可以用@@的程序读取:
输出结果如下:
读取原始数据的部分观测值
有时候只需要读取原始数据的部分观测值,比如只需要年鉴中的女性数据、收入超过10万的人口数据等。此时的数据读取方式如下:在SAS读取某一行观测值时,首先读取足够的变量以便决定是否需要保留此行的观测值。然后在input语句结尾加符号@,叫做a trailing at(called a trailing at),这告诉SAS先停在(hold)此行,同时用IF语句检测此观测值是否满足需要,如果是,那么可以再用一个input语句来读取现有的变量。
例子 有一个关于当地交通的数据,traffic.dat数据包含街道的类型(freeways和surface)、街道名称、早晨每小时的机动车流动量、晚上每小时机动车流动量。
如果现在你只需要freeway的数据,可以用下述程序:
第一个input读取字符串变量,@是SAS停留在观测值上并用IF检测,第二个input读取input后面的变量值。
输入结果如下所示:
@ vs @@ ,@的作用类似于@@,都是行停留指示符(line-hold specifiers),不同地方在于停留多久,@能使SAS停留到下一个input语句(也不换行),@@能使停留的时间到下一个data步(也不换行)。
比如这段代码:
data test;
infile cards ;
input x @;
input y;
input z @@;
cards;
1 2 3 4 5 6
7 8 9 10 11 12
13 14 15 16 17
;
run;
test输出结果就是:
****************************************************** The End ***************************************************