0

Think SAS(二)

 3 years ago
source link: https://cosx.org/2010/12/think-sas-2/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

有个老本家,著有《白话文学史》(上卷)、《中国哲学史大纲》(上卷),——你知道他叫胡适。然后有朋友这个 “Think SAS” 系列有没有下文,我自然不敢托大,“半卷先生” 不能做,还是老老实实地把这个系列往前推吧。

第一篇 “Think SAS” 中的 “Think”,纯粹做“考虑” 解,说,诸君如果为工作计,不妨考虑下 SAS。下面说些关于 SAS 本身的一些思考与认识。俗话说,人类一思考,上帝就拍砖。上一篇是纯劝导型,这一篇就是求拍砖型。

0. 总结与回应

在展开讨论之前,希望大伙对 “事实问题” 而不是 “价值问题” 能有一个统一的认识,这也是我对上篇各位的评论的一个总结与回应。

0.1 功能:SAS 与 R

一些朋友询问 SAS 或 R 或其他软件功能的优劣,然后决定自己应该着手学哪个。这是一个伪问题,或至少也是一个不好的问题。一般来说,没有不好的问题,只有不好的回答,——但那的确是一个不好的问题。

一门编程语言(本文讨论的是统计编程语言),只要能实现分支(if … then …)和循环(for/while/do … loops),就能够完成几乎所有的运算。这样说来,单问 SAS 是不是比 R 强大,或者 R 是不是比 SAS 强大就是一个意义不大的问题。它们都能较好地完成大多数的任务,强不强大的区别,在于背后的用户。一些更好的问题或许是,比如,它们的某些模块相比起来如何,它们的扩展性相比如何、它们的运算效率相比如何等等。个人认为,最好的问题是,在我现在如此这般的情况下,哪一款软件最适合我?这些问题也仁者见仁智者见智,但都能讨论出有意思的东西出来。

我认为讨论软件优劣不是一个好问题,还有一个基于经验的理由,就是一般在这种情形下,你需要的不是一个答案,而是不管基于什么理由而迅速选择一门语言,然后沉浸下去。时间和精力不能浪费在观望上面。R 如何,SAS 又如何,如果还停留在询问探索阶段,它们都不是你的(套用一句话,不学进去,神马都是浮云)。

以前说过,大多时候,你选择一门语言,不是因为你经过比较,认为 A 比 B 好故选 A。你在图书馆看到哪本书,你旁边的朋友、同事、老师在使用哪个,或者更直接的,你被要求用哪个。无论是什么,学下去了都能胜任你大多数的日常工作。如果发现不够用,那恭喜你,你就处在一种知识 / 技能上的饥渴状态,我相信无论是哪一种新的语言,你都能迅速上手。

0.2 工具:SAS 与统计

提到 SAS,一些学统计出身的朋友很不屑:不就工具吗?统计思想才是王道!

都说到思想了,我想认真回应下。在做统计分析时,SAS 编程是工具。但在做决策时,统计本身也是辅助工具。因为处在上下游的关系而相互轻视,这不是一种开放的心态。

oloolo 对行业顶尖的统计师有一个非常好的总结,就是 “对业务敏感,对统计老到,对编程熟练”。要是业务人员嘲笑统计师不懂业务,统计师嘲笑程序员不懂统计,程序员反过来嘲笑他们其实什么啥都做不了,这生态圈的境界未免就低了些。

0.3 SAS 与 FDA 以及 “路径依赖”

作为一家标榜平台无关的监管机构,FDA 没有要求药厂必须用 SAS 作为统计分析工具。但是,FDA 要求所有的临床数据,都必须用 SAS 公司研发出来的一种开放数据格式提交(SAS transport file,后缀是. xpt)。还有,FDA 的统计师的 PC 上装有 SAS 软件。这样,你大概就能理解为啥这行业都用 SAS 了。

或者有人说,SAS 被广泛使用,是因为它出道早,抢了个先机,倒不是因为它本身如何如何好。这个诘难在我看来是很软弱的:

–首先,SAS 并不是出道最早的,SPSS 就比它早。S-plus 也跟它是一个时代的产物。

–关于 “强了个先机”(路径依赖)。有时候你不能过高相信了用户的忠诚度。想想,你换了几种输入法、几种浏览器、几种搜索引擎?几十年来大浪淘沙,一个产品或服务始终占优,单单一个用户忠诚度是不能完全解释的。

举个例子,比如 FDA 要求所有的临床数据用 xpt 格式提交,这个不是一成不变的。以前也提到,SAS 的优势根本就不在数据存储上,XML 就比 xpt 好,而且就是将来的方向。但是在药厂,程序员们还是将继续使用 SAS 来生成各种 XML 文件(包括 define.xml)。SAS 或许不是处理 XML 文件的最好工具,但至少在功能上没有任何问题,它可以是 SAS 程序员的最好工具(参见本文 0.1)。

下面回到正题,说说 SAS 本身。

1. “巨无霸”SAS

下面这幅图,取自 SYSTAT 的创始人 Leland Wilkinson 的文章,The Future of Statistical Computing,大概按照几种标准对市场上存在的统计软件做了个聚类。一些统计软件的特点是将数据全部读入内存,在处理完了才跟磁盘交换数据,比如 Stata、R 等;Minitab、Statistica 和 SAS 的 JMP 归为一类是因为它们都专注于质量控制领域;SPSS 和 SYSTAT 在框架和用户界面比较类似(而且它们的归宿也类似,SYSTAT 卖给了 SPSS,后来 SPSS 又把它转手卖给印度。后来啊,SPSS 本身又被 IBM 给买了);Google 和 Microsoft 归在一起,因为它们不是专注做统计软件的公司,但又有用户界面非常人性化的统计分析产品(轻客户端,比如 Google Analytics)。

SAS 呢?SAS 跟它们都不一样。上文只好根据安装介质最大这条标准,把 SAS 单独归为一类(图中 SAS 的字号最大,是因为这家公司在分析领域收入最高)。

SASetc

“巨无霸” 的确是 SAS 给人的第一个鲜明的印象。所以在大多数场合,拿它跟其他统计软件相比,就有以大欺小之嫌,SAS 早已经不仅仅是 Statistical Analysis System(具体的可参见本系列第一篇之 “SAS 是什么?”)。

1.1 SAS 的编程元素

SAS 的” 巨无霸” 特点, 表现在它的产品线的多样化(功能 / 行业), 也表现在它编程元素的多样化

–- 它主要是一门过程式的语言(循环、分支、数组,……),但其中也不乏面对对象的特性:

  —首先,SAS/AF 就是一门完全面对对象的应用开发语言。

  —在 SAS/Base 中,–通过 Data Step Component Interface, 你可以在数据步里建立纯 OOP 的 Java 对象。

  —在 DDS 中,有一个类似的 DDS Data Step Object

  —最后,在 Macro 中,一样可以体现出以上提到的各种 OO 特性

–对 C/C++ 程序员来说,它提供了一个 SAS/C Complier

–- 对 Java 程序员,它有一个基于 Eclipse 的开发环境 SAS AppDev Studio,可以方便地利用 SAS 的计算引擎开发各种应用,

–- 矩阵运算一块,SAS 的矩阵语言 IML 与 Matlab、R 等相比也不弱

–- 字符处理,除了大量的字符函数,SAS 也支持 Perl 正则表达式

–- 支持标准 SQL 语句

–- 支持 Hash 表

–- 为 XML 数据提供了 XML 引擎

SAS 的这种 “杂糅” 风格,也受到不少批评。一个感觉就是似乎有些“粗”(大象能不能跳舞?),比如,很明显,S 语言就比它精细许多。在统计分析一块,S 语言是 SAS 的主要竞争者,我先绕开讲个故事。

1.2 SAS vs S: AK47 vs M16: 一个类比

在枪械史上,有两款步枪最受人瞩目,而且经常拿来做对比,它们就是 AK47 和 M16(以下关于这两款步枪的材料来自网络)。

AK47 出自前苏联一名坦克车长卡拉什尼科夫上士之手。1942 年他回家养伤,跟一个火车司机在一个小工棚里打磨了一支自动步枪。以后不断改进,1946 年,他的 AK46 送去靶场接受极限测试:连续射击子弹 1.5 万发,枪管打红了,射击精度却没有什么大的变化。以后这支步枪就以 AK47 的名字扬名天下,它结构简单,结实耐用,故障极少,造价低廉,威力巨大,能在寒冷、炎热、风雨、沙漠甚至水中都能使用。

M16 最早出现在上世纪 60 年代,设计师是美国知名的枪械大师斯通纳。他在 M16 的各个部件上广泛采用了铝合金和塑料等轻型材料,制造工艺非常先进,枪身也更精致时尚。另外,M16 口径稍小,射击精度有所提高,但它对射击的环境要求很高,枪管不能进水,有时下雨受潮也影响射击精度。再加上性能不稳定,连续打出 4500 发以上的子弹,就造成某些零件的断裂。

讲到这里,大家都应该能猜到我想说什么。除了价格因素,在比喻的意义上,SAS 就是 AK47(:这里的 SAS 指其与 S 相对应的部分,下同;整个 SAS 系统是一个武器库而不是一个单兵武器),S 语系就是 M16,或者保险一点,与 M16 相比,SAS 更像 AK47;与 AK47 相比,S 语系更像 M16。S 语言出身名门(贝尔实验室),设计精巧,获过 ACM 大奖。SAS 语言则出自于一位物理学背景的程序员之手(Tony Barr),当时他所在的机构急需解决方差分析等问题。接下来的故事大伙都很清楚了,AK47 成了战场上使用最受欢迎的步枪。

1.3 SAS 的优缺点,以及关于其编译器的一些讨论

SAS 的设计,很多是基于商业世界的要求。比如,对于数值型变量,SAS 只提供一种浮点型格式,这让它在计算性能方面有些吃亏(想想看,就连 1+1,SAS 都要当成两个浮点数来计算,习惯于首先声明 “int x” 的 C/C++ 程序员看了大概要不爽),但是,比如,关于日期格式 (format 和 informat),SAS 却提供了近百种供选择。纯浮点数让系统开销大一些,但是在设计方面可以简化不少,但是全世界各种不同的日期格式却丝毫不能省略。SAS 系统一路“堆积” 至此,是考虑,有时甚至是迎合了市场的需要。

在比喻的基础上做进一步的引申会很危险。SAS 语言脱胎于 PL/1。与其他过程式编程语言相比,往好里说,PL/1 在异常处理方面强过 Ada,在文本处理方面强过 Basic,在输入输出管理方面强过 Cobol,在计算方面强过 Fortran,在流程控制方面强过 Pascal,在内存管理方面强过 C,当然,在宏替换方面强过汇编。SAS 无意在系统编程或算法实现跟其他语言一较长短,但它在数据访问、数据管理、报表展示、数据分析以及编程灵活和易用性方面的强大优势(详见下),使得它在商业世界一直长盛不衰。

当然,SAS 的缺点也非常明显。比如, 直到 SAS9.2 它才能够在数据步 (data step) 里自定义函数,你会想,作为一门过程式的语言,以前不能自定义函数的日子怎么过?毫无疑问,这是一个限制。但是,在 SAS 中,你还以通过其他方式完成类似的功能。首先,SAS 有大量的内置函数,在你想自定义函数之前,先麻烦查一下函数手册;然后,你可以定义一个 “类似函数的” 宏(Macro),这是应用最广泛的方式; 或者,你也可以直接在 SAS 的矩阵语言 IML 定义函数。

说到 IML,这是一个好东西,但是,这么多年了,这家伙居然不能够实现递归!!毫无疑问,这也是一个限制。但是,首先,所有的递归都可以写成一个等价的循环,而且循环的效率还高些;其次,你可以在 Macro 里实现递归;而且,好消息是,SAS9.2 的自定义函数完全支持递归调用。

讨论 SAS 本身的优点跟缺点,不得不提一下系统底层的东西。比如,Tony Barr 在设计 SAS 系统的时候(上世纪六七十年代),它的编译器用的就是一个递归下降解析器 (recursive descent parser),这是一种自上而下的编译方式。深入讨论这个话题超出了本文的范围,简单说一下这种编译方式的优点和缺点。

它的突出优点是:它超级简单,跟 AK47 一样,意思是说它超级稳健(robust)。它的缺点也很明显,超级简单的一个代价就是,有时候它不够精确。想想看,假设你跑一段代码,然后查日志文件 (log),发现报错信息是在第 2011 行。一个建议是,比如,你最好从 2009 行开始查看你的代码。

1.4 关于 SAS 与 S 语系的一些展望

上面多次提到了 S 语系。我不熟悉它,但也非常看好它。冒着危险再讲个故事。

战后卡拉什尼科夫访问过美国,跟斯通纳玩了个友谊赛,他用 M16,斯通纳用 AK47。两位对手中的步枪评价都很高。他们都认为,未来步枪将会向向小口径、轻型化、通用性方向发展(S?!);当然,其前提仍然是性能可靠,适合各种复杂多变和条件恶劣的自然气候(SAS?!)。

再一次,我鼓吹的是 SAS 与 S 的融合。现在 SAS 系统有好几个部分兼容 R,你可以在 Stat Studio 和 JMP 里跑 R 代码。作为一个 SAS 程序员,我觉着这样还不够,最好是在 SAS Base 里整合一个与 PROC SQL、PROC IML 平行的 PROC R。

2. Programming SAS(用 SAS 编程!)

SAS 中文社区神龙见首不见尾的高手,SAS_Dream,在 2004 年抛出一篇《SAS 语言管窥》,梳理 SAS 的各种语系,如 BASE、STAT、AF 等,多读多有启发。

下面讨论的也是 SAS 的编程特点。有一个区分,SAS 程序员 (SAS Programmer) 和 SAS 用户(SAS User)。一个纯 SAS 程序员更多使用 SAS 的编程模块(SAS Base、SAS/AF 等),一个纯 SAS 用户更多使用 SAS 的非编程模块,比如统计分析模块 SAS/STAT、SAS 的 GUI 工具 SAS Enterprise Guide、SAS Enterprise Miner 等。从这个角度来说,跟 SAS_Dream 的看法不一样,我把 SAS/STAT 等分析模块从 SAS 编程语言的范畴中剔除出去了。那些模块需要的更多的是业务知识(比如统计学),没有丝毫的编程乐趣。当然,一个人可能倾向于是 SAS 程序员或者 SAS 用户,或者有时候是 SAS 程序员,有时候是 SAS 用户。

2.1 Data Steps

data steps(数据步)是 SAS 最核心的东西,一种第四代过程式编程语言,脱胎于 PL/1

一些人认为 SAS 的语法结构怪异,其实这是很大的误解。作为一门通用性的过程式语言,它在顺序语句、分支、循环方面跟其他过程式语言(或过程式 / 结构式编程方式)没什么太大区别。

SAS data step 跟其他语言最大的区别,在于它的内置循环。举个例子,在 d 盘里有一个数据文件,data.dat,存有三个数字:

1
2
3

用 SAS 读取这个文件并计算它们的和是很简单的事情。先看看其他语言是如何操作的,比如 C++。C++ 是一门过程式兼面对对象的语言,下面的例子展示的是 C++ 过程式的编程风格(不熟悉 C++ 语法的朋友,可以只看中间加粗的部分):

#include 
#include 
using namespace std;

int main() 
{ 
     int x; 
     int sum=0; 
     ifstream inFile; 
     inFile.open("d:data.dat");    
     inFile >> x;    

    
     while (!inFile.eof( ))      
     { 
         cout<<x<<endl;  
         sum = sum + x; 
         inFile >> x;               
     }


     inFile.close( ); 
     cout << "Sum = " << sum << endl;      
     return 0; 
}

中间加粗的部分是一个循环,在没有到达数据末尾时(即 “3” 那个数字,代码中的条件是! inFile.eof(), 其中,感叹号是 not 的意思,eof 就是 end of file。),持续输出文件里的数字并累加,结果就是

1
2
3
sum=6

以下的 SAS 代码产生同样的结果:

data null; 
    infile "d:\data.dat" end=eof; 
    input x;

    sum+x;

    put x; 
    if eof then put sum=; 
run;

上面的 SAS 代码,同样是运行直到文件的末尾,但它并不需要一个显式的循环来读取那文件里的 3 个数字(内置循环,说的就是这个)。理解 SAS data step 内置循环的特点,是 SAS 进阶的关键。详细的,可见 Overview of DATA Step Processing

—————-

写不动了,下期预告,大伙新年愉快。

2.2 SAS BASE

SAS BASE 不是一门语言,而是一系列编程语言的大杂烩。它是在 data step 的基础上,加上其他编程元素,如 SQL、Macro、ODS 和一些 proc steps 等。只有最顽固(可能也是最骄傲)的 SAS 程序员仍然坚持 2.1 的风格,大多数 SAS 程序员都是使用 SAS BASE 进行混合编程。当我们是 SAS 编程语言的时候,一般说的就是这个 SAS BASE。它是 SAS 系统的一个模块(或软件),与 SAS/STAT 等模块并列。

2.2.1 PROC SQL

2.2.2 过程步 (PROCs steps)

2.2.3 宏(Macro)

(to be continued)

敬告各位友媒,如需转载,请与统计之都小编联系(直接留言或发至邮箱:[email protected]),获准转载的请在显著位置注明作者和出处(转载自:统计之都),并在文章结尾处附上统计之都微信二维码。

统计之都微信二维码

← Sweave 后传:统计报告中的大规模计算与缓存 第三届中国 R 语言会议(上海会场)纪要 →

发表 / 查看评论


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK