本节书摘来自华章出版社《深入解析sas:数据处理、分析优化与商业应用》一书中的第3章,第3.5节,作者 夏坤庄 徐唯 潘红莲 林建伟,更多章节内容可以访问云栖社区“华章计算机”公众号查看
3.5 SAS常用函数
SAS函数是编程语言的一个组件,可接受参数、执行计算或进行其他操作并返回值。返回值是字符型或数值型的结果,可用于赋值语句或表达式中。SAS包含很多函数,也可以自定义函数。在BASE SAS软件中,SAS函数可用于DATA步编程、WHERE表达式、宏语言语句、PROC REPORT和结构化查询语言SQL(Structured Query Language)。本节将会介绍一些常用的SAS函数。
CALL例程转变变量值或执行其他系统函数。CALL例程和函数相似,不同的是CALL例程不能用于赋值语句或表达式。所有的CALL例程都使用CALL语句调用。本书不介绍CALL例程,有兴趣的读者可参考SAS帮助文档进行学习。
3.5.1 函数语法
SAS函数的形式如下:
函数名(参数1 <, ...参数n>)
函数名(OF 变量列表)
函数名(参数 | OF 变量列表 | OF数组名{*} <..., 参数 | OF 变量列表 | OF数组名{*} >)
其中:
函数名用于给出函数名称。
参数可以是变量名、常量或任何SAS表达式。多个参数间使用逗号(,)分隔。
变量列表可以是任何形式的变量列表。多个列表之间使用空格分隔。例如sum(of x y z)、sum (of x1-x10)、sum(x, of x1-x5 y1-y5)、sum(x, of x1-x5, of y1-y5)。最后两种表示方式具有同等效果。
数组名{*}指在当前DATA步中已经定义的数组。
3.5.2 数值函数
表3.11给出了SAS常用的数值操作的函数。
数值函数的使用相对简单,例3.23中给出了使用SUM函数的例子,这里不再举例说明。
3.5.3 字符操作函数
常用的字符操作函数如表3.12所示。
例3.28:将数据集saslib.contact2中的变量Name中的姓和名分开为Last_Name和First_Name。
在例3.17中已经使用了SCAN函数将Full_Name中由空格分隔的第1个单词和第2个单词存储在了First_Name和Last_Name中,本例则使用INDEX和SUBSTR函数来完成该部分功能。例3.17中将原变量Name重命名为Full_Name这部分本例不涉及。代码如下:
data work.contact2;
set saslib.contact2;
split=index(Name, ' ');
First_Name=substr(Name,1,split-1);
Last_Name=substr(Name,split+1);
drop split;
run;
proc print data=work.contact2 noobs;
run;
PRINT过程打印输出数据集的数据如图3.31所示。
这里以DATA步中第一次迭代的变量值(Name的值为“Greg William”)为例来解释说明。
第一条赋值语句:INDEX函数返回该字符串中空格的位置5,并存储在split中。
第二条赋值语句:右侧SUBSTR函数返回字符串“Greg William”中从第1个字符开始到第4(5-1)个字符中的字符串“Greg”,并存储在First_Name中。
第三条赋值语句:右侧SUBSTR函数返回字符串“Greg William”中从第6(5+1)个字符开始剩下的所有字符“William”,并存储在Last_Name中。
这里为了便于理解,在给出变量的值时未将字符串中的尾缀空格列出。例如,因为Full_Name的长度为20个字符,所以所存储的字符串实际上是“Greg William ”(后面共8个空格)。字符值中包含的空格对理解字符串操作非常重要。
例3.29:数据集saslib.shop包含各汽车经销商的4S店信息,其中包括变量Street、City、State。现在要将这3个变量组合成完整的地址信息。
数据集saslib.shop的内容如图3.32所示。
可使用级联操作符||组合完整地址,应在Street、City、State之间使用标点符号,因为多个空格字符在HTML中会显示为一个空格。这里为了清楚,将PRINT过程的打印结果输出到PDF文件中。输出PDF文件使用了SAS的输出交付系统ODS(Output Delivery System),在本书第5章会进行介绍。代码如下:
data work.shop_fulladdr;
set saslib.shop (drop=telephone zip);
Full_Address=Street || ", " || City || ", " || State;
drop Street City State;
run;
ods pdf file="c:\sas\data\output\full_address.pdf";
proc print data=work.shop_fulladdr noobs;
run;
ods pdf close;
PDF文件的内容如图3.33所示。其中Full_Address列的地址中包含很多空格。这是因为原数据集中的变量Street和City数据值的长度小于变量的长度,这时SAS会在数据值后补充空格以达到给定变量长度。以数据集saslib.shop中的第一个观测为例。变量City的长度定义为20,第一个观测中City的值实际为“Culver City ”。对Street也是相同的情况。因为State的长度是2,所以其后不会存在空格。
例3.30:使用TRIM函数将各字符变量尾缀空格删除,并将其进行级联产生完整的地址信息。
因为这里的State长度为2,也可以不对State变量使用TRIM函数。代码如下:
data work.shop_fulladdr;
set saslib.shop (drop=telephone zip);
Full_Address=trim(Street) || ", " || trim(City) || ", " || trim(State);
drop Street City State;
run;
ods pdf file="c:\full_address.pdf";
proc print data=work.shop_fulladdr noobs;
run;
ods pdf close;
所生成的PDF文件的内容如图3.34所示,变量Full_Address列中没有多余的空格。
例3.31:直接使用CATX函数删除各字符变量值的尾缀空格,并将其进行级联产生完整的地址信息。
CATX函数也可以删除字符串的前导空格,虽然本例中字符串不含前导空格。代码如下:
data work.shop_fulladdr;
set saslib.shop (drop=telephone zip);
Full_Address2=CATX(", ", Street, City, State);
drop Street City State;
run;
ods pdf file="c:\full_address.pdf";
proc print data=work.shop_fulladdr noobs;
run;
ods pdf close;
所产生的数据集与上例相同,这里不再给出。
3.5.4 数值与字符转换函数
在介绍表达式的时候介绍过,当代码中给出的值与所需要的类型不匹配时,例如,在需要数字值的地方使用了字符变量,SAS会试图自动将该值转换成所期望的类型,但是,自动转换有时候会出错或产生意外的结果。SAS提供了PUT和INPUT函数进行显式类型转换。这两个函数很有用,即使有些情况自动转换能够处理,使用显式类型转换也会更有效率。
1.?PUT函数
PUT函数使用指定的格式返回值,可用于将数字值转换成字符值。其基本形式如下:
PUT(源, 格式)
其中,源为要进行重新格式化的常量、变量或表达式,可以是字符型或数值型。格式为要应用在源上的SAS格式。PUT函数可用于将数字根据格式转换为字符或将字符值转换为其他字符。默认情况下,如果源是数值型,结果字符串会向右对齐,如果源是字符型,则结果字符串会向左对齐。也可以在格式中添加对齐标识-L、-C、-R分别表示左对齐、居中或右对齐,改变默认对齐方式。格式必须与源的类型一致。也就是说,如果源是字符,格式名必须以$符号开始;如果源是数字,格式则不能以$开始。PUT函数不影响数据集中的变量格式或属性。
例3.32:在对总公司的多个子公司员工信息进行合并时,发现某个子公司员工数据中的员工ID为数字值,而其他子公司员工数据中的员工ID为字符值,这时需要将该子公司员工ID的数字转换成字符型,以便进行合并操作。
该子公司员工信息保存在saslib.employee2中,使用PUT函数对Emp_ID的数值进行转换,并创建新的字符型变量New_Emp_ID,同时,使用DROP语句将原始变量Emp_ID删除,之后再使用RENAME语句将New_Emp_ID改名为Emp_ID。这样,所生成数据集中包含的变量名就会保持不变。该过程很容易理解,这里不再给出数据示例进行讲解。相关代码如下:
data saslib.employee2;
set saslib.employee2;
New_Emp_ID=put(Emp_ID, best10.);
drop Emp_ID;
rename New_Emp_ID=Emp_ID;
run;
2.?INPUT函数
INPUT函数返回当SAS使用指定输入格式转换SAS值之后的结果。其基本形式如下:
INPUT(源, 输入格式)
其中,源为要应用输入格式的字符常量、字符变量或字符表达式。格式为要应用在源上的SAS输入格式。
INPUT函数会将源的值使用指定的输入格式进行转换。INPUT函数可用于将字符值转换为数字值或其他字符值。输入格式指定了结果是数值型还是字符型。INPUT函数也不影响数据集中的变量输入格式或属性。
例3.33:数据集saslib.sales中的日期值(Date)以字符方式进行存储,其数据内容和变量的属性如图3.35和图3.36所示。
公司需要对员工入职日期进行排序,首先要将日期值(Date)转换为数字。这里使用INPUT函数,并使用输入格式date9.将字符格式的日期值(例如“01JAN2012”)转换为该日期对应的数字进行存储。代码如下:
data saslib.sales;
set saslib.sales;
Num_Date=input(Date, date9.);
drop Date;
rename Num_Date=Date;
run;
proc print data=saslib.sales noobs;
run;
proc contents data=saslib.sales;
run;
PRINT过程和CONTENTS过程打印的数据集内容和属性如图3.37和图3.38所示。而且Date变量的类型为数值型,这样就可以根据Date值对整个数据集进行排序了。
3.5.5 与日期时间相关的函数
SAS提供日期(date)、时间(time)和日期时间(datetime)函数从日期、时间和日期时间值中得到年份、月份、日、小时、分钟、秒等信息,它们也可以将这些信息组成SAS的日期、时间和日期时间值。表3.13给出了SAS中常用的与日期、时间相关的函数。除此之外,SAS还提供对日期的间隔进行操作的函数,详细情况请参考SAS帮助文档。
例3.34:将公司员工入职日期中的年份、月份和日分别提取出来,建立新的变量Year、Month和Day。数据集saslib.employee的内容参考例3.13。
代码如下:
data work.employee_ymd;
set saslib.employee;
Year = year(Entry_Date);
Month = month(Entry_Date);
Day = day(Entry_Date);
run;
上面分别使用YEAR函数、MONTH函数和DAY函数得到原数据集Entry_Date中员工入职年份、月份和日期,所生成的数据集的内容如图3.39所示。