msgbartop
List for SAS fans and programmer
msgbarbottom

01 9月 12 SAS函数精选一 翻译


下面是Dr. Ron Cody的一篇关于SAS函数的文章,非常好的函数介绍文章。曾经在2009年SAS公司(上海)举办的一次SASor聚会上,我做了一次关于SAS函数的presentation分享,见 ppt正文,我发现竟然有部分内容重合。 我个人非常喜欢SAS系统提供的函数,建议老手新手都可以读读下面的文章,祝都有所获!

最有用的一些SAS函数
A Survey of Some of the Most Useful SAS Functions

by Dr. Ron Cody   翻译 sxlion

摘要:

     SAS函数为你的数据步(DATA step)编程提供惊人的能力。有一部分SAS函数是精华,能够帮助你节省大量不必要的代码。这篇文章内容覆盖其中最有用的一些SAS函数。有些函数可能对你来说有些陌生,然后她们将会改变你的编程方式,并助你轻松完成日常的编程任务。

 介绍:

         本文写到的大部分函数都与字符数据有关,这些函数的功能包括搜索字符串,查找和替代字符串,或连接字符串,还有些函数能测量两个字符串之间的距离(这对于“模糊”配对非常有用)。一些最新和最叹为观止的函数还以Call例程的形式存在。你知道怎么用函数在同一个观察值进行排序吗?你知道你不仅可以定位一列变量中极大或极小值,而且可以定位到第二位、第三位最大或最小的值? 如果你觉得上面的介绍能够吸引你的兴趣,请继续往下读! http://saslist.net

SAS是怎样存储字符值的?

 在我们讨论字符函数之前,了解SAS怎样存储函数值非常重要。为了帮助讨论,你首先需要理解两个重要的字符函数:LENGTHN和 LENGTHC。

LENGTHN和 LENGTHC

        这两个函数返回字符值的长度信息,其中LENGTHN返回未计算后缀空格语句的长度。LENGTHC返回字符变量的存储长度。你也许对旧的SAS函数LENGTH比较熟悉,大部分情况下函数LENGTH和LENGTHC返回同样的值。有一个例外的是,当语句里是缺失值时,LENGTH函数返回的是1,而LENGTHN返回0。有一些新函数看起来是在旧函数后面加个字母“n”,这里的“n”代表“空字符串”(“null string”)。在SAS9中,长度为0的字符串概念被引进。在大多数情况下,如果你看到一个你似曾相识的新函数(比如说新函数TRIMN,你已经知道函数TRIM),你应该使用带“n”的新函数。     看一下下面的程序:

 程序1

1
2
3
4
5
6
7
8
9
10
 data chars1;
length String $ 7;
String = 'abc';
Storage_length = Lengthc(string);
Length = lengthn(String);
Display = ":" || String || ":";
put Storage_length= /
Length= /
Display=;
run;

图1:程序1的结果

Storage_length=7
Length=3
Display=:abc    :

 记住,SAS字符变量的存储长度在编译阶段被设置。因为LENGTH语句在字符设置语句之前,SAS为字符串设置了长度为7。因为字符串长度为3,LENGTHN函数没有计算字符后面的空格,于是返回3。最后,在字符串的两边各加一个冒号,这样就清楚的看到字符串后面包含了四个空格。http://saslist.net

如果你把LENGTH语句往后面移一步,像下面:

程序2

1
2
3
4
5
6
7
8
9
10
data chars2;
String = 'abc';
length String $ 7;
Storage_length = lengthc(String);
Length = lengthn(String);
Display = ":" || String || ":";
put Storage_length= /
Length= /
Display=;
run;

你将得到下面结果:

图2:程序2的结果

Storage_length=3

Length=3

Display=:abc:

        注意到上面结果中,LENGTH语句被忽略了。因为Sting = “abc”出现在LENGTH语句之前,字符串的长度已经被设置。根据经验,运行PROC CONTENTS来查看所有数据集,检查所有字符变量的存储长度。如果你看到有些字符串的长度达到200,你不用吃惊,因为很多SAS字符函数的默认长度就是200,也就是说如果你没有显示的用LENGTH语句或其他方式定义变量长度的话,SAS就会默认字符串长度为200。

缺失值函数和CALL MISS例程

 在过去,你可以像下面这样检查一个数据步中的缺失值:

 *老方法 ;

if Age = . then . . .

If Char = ‘ ‘ then . . .

*新方法 ;

if missing(Age) then . . .

if missing(Char) then . . .

     这个missing函数的新语句可以确认数值变量和字符变量是否为空 ,如果是空,则返回1,否则返回0。我个人非常推荐你在任何需要测试一个变量是否为空的程序中使用这个函数。这样你会发现你的程序更漂亮。

      如果你需要设置一个或多个字符或数字变量为空值,你可以使用下面的老方法,比如:

1
2
3
4
5
6
7
8
9
 array x[10] x1-x10;
array chars[5] a b c;
do i = 1 to 10;
x[i] = .;
end;
do I = 1 to 3;
chars[i] = ' ';
end;
drop i;

或者你也可以使用像下面这样的call missing历程,以便节约更多的时间。

 call missing(of x1-x10, a b c);

INPUT函数

      这是我学习SAS(多年前)是遇到理解困难的函数之一。一个简单的方法就是思考INPUT函数,问自己“INPUT语句是干什么的?”,它通常从按照预先提供的INFORMAT格式从一个文件中读取文本。同样,INPUT函数做类似的工作,它根据函数提供的第二个语句INFORMAT,读取函数提供的第一个语句中的文本。也许下面的程序可以跟直观的帮助理解。

程序3

1
2
3
4
5
6
7
data _null_;
c_date = "9/15/2004";
c_num = "123";
Sas_Date = input(c_date,mmddyy10.);
Number = input(c_num,10.);
put SAS_Date= Number=;
run;

                程序3中有两个字符变量c_date和c_num。使用INPUT函数,你可以根据第一个语句的值新建一个真实的SAS数据(数值型),根据第二个语句将字符转化为数值。注意,c_num的读入格式是10.。和从文件中读入文本不同的是,INFORMAT不能读完字符值。运行这段代码,SAS_Date和Number的值显示如下: http://saslist.net

图3:程序3的结果

 Sas_Date=16329 Number=123

PUT函数

          PUT函数是与INPUT函数对应的函数。同样,你可以考虑PUT语句的作用——读取一个SAS值(字符或数值型),应用输出格式FORMAT,并通常写出到一个文件的结果中。PUT函数获取第一个语句的SAS值,并且按照第二个语句的格式写出到结果中。PUT函数的用途之一就是将数值型转化为字符型,另外一个用途就是使用用户自定义格式建立一个新变量。下面是一个例子:

程序4

1
2
3
4
5
6
7
8
9
data _null_;
SAS_Date = 1;
Number = 1234;
SS_num = 123456789;
Char_Date = put(SAS_Date,mmddyy10.);
Money = put(Number,dollar8.2);
SS_char = put(SS_num,ssn.);
put Char_date= Money= SS_char=;
run;

 这个例子使用了三个数值(分别是SAS日期,一个数和一个社会安全号),并且新建了三个字符型变量。运行这段代码后,字符变量的值为:

图4,程序4的结果

Char_Date=01/02/1960

Money=$1234.00

SS_char=123-45-6789

     下一段程序告诉你使用一个格式将不同年龄组进行分类,这种方式在某种程度上比使用一系列的IF-THEN-ELSE语句更简单。下面是程序例子:

程序5

1
2
3
4
5
6
7
8
9
10
11
12
13
proc format;
value agegrp 0-20='0 to 20'
21-40='21 to 40'
41-high='41+';
run;
data PutEx;
input Age @@;
AgeGroup = put(Age,agegrp.);
datalines;
15 25 60
;
proc print;
run;

               新变量AgeGroup是一个使用了格式化的Age值的字符变量。新变量的存储长度是与格式化值最大长度是一致的。下面,你可以看看变量Age和AgeGroup的值。

 图5:程序5的结果

Age    AgeGroup

 15    0 to 20

 25    21 to 40

 60    41+

FIND和FINDC函数

          FIND函数使用第一个语句定义的字符串,查找有第二个语句定义的子字符串,如果子字符串找到,函数返回它的位置。如果没有找到,则返回0。FIND函数中有两个可选的语句——修饰符和起始位置。最常用的修饰符为“i”,表明忽略大小写。起始位置定义在开始搜索的位置,如果起始值为负数,则搜索开始于起始位置绝对值的位置,并且从右往左搜索。随便提一下,两个可选语句的位置可以颠倒。为什么这样也可以呢? 修饰符通常是字符值,而起始位置通常是数字值,哈哈,厉害吧!如果你仅仅输入了一个修饰符或起始位置值,放第三个语句位置即可。下面是一个例子。http://saslist.net

程序6

1
2
3
4
5
6
7
8
9
10
11
data locate;
input String $10.;
First = find(String,'xyz','i');
First_c = findc(String,'xyz','i');
/* i means ignore case */
datalines;
abczyx1xyz
1234567890
abcz1y2x39
XYZabcxyz
;

       这个例子中的两个函数使用修饰符“i”,使用了此修饰符,你可以省去改变一个或多个字符串大小写形式的麻烦。

图6:程序6的结果

String      First    First_c

abczyx1xyz      8         4

1234567890      0         0

abcz1y2x39      0         4

XYZabcxyz       1         1

    第一个观察值,子字符串‘xyz’在String的第八个位置才找到。因为FINDC函数在寻找字母“x”或“y”或“z”,在第一个观察值中返回一个4,因为字母‘z’在第四个位置找到了。注意但在观察值2中没有找到任何配对成功时,函数返回0。

COMPRESS函数

     这个当然是我最喜欢的SAS函数之一。据我所知,这是唯一从版本8升级到版本9的函数。这怎么可能呢?该函数写法在SAS8和SAS9中是一模一样的么?答案是“yes“,除了在版本9中增加了一个可选的第三项外。

在COMPRESS函数中的三个语句是:

Compress(String, characters-to-remove, optional-modifiers)

其中,Sting是你想要压缩的字符串(除非你使用‘k’修饰符)

characters-to-remove是你一列你想要从String中去掉的字符串。如果你仅仅给出了COMPRESS函数一个语句,那么就将除掉String中所有的空格。

可选修饰符允许你指定字符串子语句,例如:

  • a    大写 或小写字母
  •  d     数值(dignits)
  •  i     忽略大小写
  •  k     保留列表字符串,而不是去掉
  • s     空间(blank,tabs,if,cr)
  •  p     标点符号

         我相信修饰符‘k’让这个函数变得真正强大。‘k’选项告诉函数所需要保留的字符列表。设定你需要保留的通常要优于你想去掉的。比如说,如果你使用两个修饰符‘k’和‘d’,函数将会保留字符串中所有数字,丢掉其他东西。这个在你的字符串中包含不可打印的字符串非常有用。下面是一个例子:

程序7

1
2
3
4
5
6
7
8
9
data phone;
input Phone $15.;
Phone1 = compress(Phone);
Phone2 = compress(Phone,'(-) ');
Phone3 = compress(Phone,,'kd');
datalines;
(908)235-4490
(201) 555-77 99
;

        COMPRESS函数将除掉Phone1中的所有空格,因为你仅仅使用了一个语句。对于Phone2,你指定了左右括号,破折号和空格。对于Phone3,你指定了两个修饰符‘k’和‘d’。注意两个冒号,这个非常有必要,可以告诉SAS‘kd’是修饰符(第三个语句),而不是需要除掉的字符(第二个语句)。注意下面结果中,Phone2和Phone3是同样的结果,然而在Phone中有多余的符号字符。

图7:程序7的结果

      Phone            Phone1          Phone2        Phone3

 (908)235-4490      (908)235-4490    9082354490    9082354490

 (201) 555-77 99    (201)555-7799    2015557799    2015557799

       这里有另外一个非常有用的例子,将演示COMPRESS函数能够用于从包括像包含单位的非数字字符串中提取数值。看下面:

程序8

1
2
3
4
5
6
7
8
9
10
data Units;
input @1 Wt $10.;
Wt_Lbs =
input(compress(Wt,,'kd'),8.);
if findc(Wt,'K','i') then
Wt_Lbs = 2.2*Wt_Lbs;
datalines;
155lbs
90Kgs.
;

       你看输入数据中包括像lbs.或kgs.的单位。这是非常的问题。使用COMPRESS函数可以得到一个非常简单和漂亮的方法。你开始可以仅保留原始值中的数值,然后使用INPUT函数把字符转化成数值。现在你需要判定,是否原始值中包括一个大写或小写的‘k’。如果是,你需要把公斤单位转化成英镑。带修饰符‘i’的FINDC函数可以轻而易举的完成这个判断。http://saslist.net

图8:程序8的结果

   Wt      Wt_Lbs

 155lbs      155

 90Kgs.      198

待续系列:      SAS函数精选二        SAS函数精选三

原创文章: ”SAS函数精选一 翻译“,转载请注明: 转自SAS资源资讯列表

本文链接地址: http://saslist.net/archives/282


Leave a Comment

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据