2.4 养成编程好习惯
上一节我们终于开始了SAS编程之路,相信几个简单的编程无法让你满足,你一定在期待更深入的编程讲解。不过这一节我们把编程的具体语法先放下,探讨一下在编程过程中我们需要注意的地方。这部分内容在一般的图书中会放到编程技术之后,但我们在第一章就提到过“工欲善其事,必先利其器”,如果说数据分析是“事”,那么SAS编程就是“器”。如果把数据分析比喻成武侠小说里的武功招式,那么SAS编程就是内功心法,只有内功深厚,才可以自如地使用各种招式。一门内功心法,最重要的就是对修炼者不能有害,像吸星大法,长期修炼则会对自身造成反噬,又如七伤拳,修为不够强行修炼会造成自身内伤,更别提葵花宝典这样的邪恶武功。
这一节我们就探讨一下SAS编程中我们应该养成的好习惯,即编程的“内功”应该如何修行。SAS是一款高级语言,很多事情它可以自动帮我们完成,像内存管理、并行计算等,在其他语言中需要我们自己写,但SAS中可以不必为它们操心。但不必操心并不代表所有人用SAS的水平都可以不相上下,相反一些SAS高手编写的程序用出神入化来形容也不为过,因为SAS提供了大量操作和选项帮我们完成复杂的任务,熟练掌握和运用可以让你的数据分析功力更上一层楼。图2-42是SAS学习难度曲线,通过这条曲线能明显看出SAS的入门比较容易,提升却很困难。
图2-42
对于这类语言,我们在学习之初就一定要养成良好的编程习惯,避免不好的编程习惯导致后续的学习难度增加。这就像修炼武功,一定要打好基础,日后才能有所突破。今天我们就介绍4套“武功心法”,助你打好SAS编程基础。
2.4.1 缩进——六合刀法
六合刀法是韦陀门的武学,全守六合之法。所谓六合,精气神为内三合,手眼身为外三合,其用为“眼与心合,心与气合,气与身合,身与手合,手与脚合,脚与胯合”,全身内外,浑然一体。
对应到SAS上,我们也应当注意编程的“合”,即应该对应的地方一定要对应。对于同一级的代码,我们往往会让它们的头尾对齐,如果是次级代码,我们要用Tab键进行缩进。例如以下代码:
该代码包括一个data步和一个proc sort,其中data和其对应的run处在同一列,proc与其对应的run处在同一列,分别在它们之内的程序则用Tab键缩进了一层。这样的代码看起来非常清楚、明确。在比较复杂的代码中,我们也可以用这种方法,让同一级别的代码对齐,让不同级别的代码相互错开,例如以下代码:
以上代码涉及数组和循环,我们还没有展开,这里也不需要完全理解语法。可以看出,array语句引导的数组和do语句引导的循环都是data步下的操作,而do循环之内还有语句,它们处于do循环之内,所以程序要分为3层,最外层是data和run,中间层是array和do,最低层则是在do循环内的操作。这样的语句让人一看就可以理解每一行程序所在的位置。
当程序不长的时候,如果没有良好的分层习惯,我们尚可以通过记忆和逻辑明确每个语句的功能,但当程序很长,又需要与其他人协作的时候,很可能产生意想不到的问题,相比起同事或老板一次次地来问你,这个语句是在那个语句之外还是之内运行,还是建议大家养成好习惯,善用Tab缩进功能。这就是编程中的“六合刀法”。
2.4.2 关注日志——三分剑术
三分剑术是《书剑恩仇录》中天山派的武功,所谓三分,乃因此剑术中的每一招仅使到三分之一,敌人刚要招架,我方已经变招。而且因为每招仅使用三分之一,因此一招时间之内可以出三招,以快打慢,讲究的就是灵活多变。对应到SAS编程中,就是要勤于查看日志文档,不要等所有程序编写完成后再统一执行,这样可能导致前期积累的错误在后续反复出现,不但影响程序执行,还可能导致意想不到的后果。
每次SAS程序运行之后,都会在日志窗口中输出程序执行的步骤和结果,如图2-43所示。
我们使用了data步中最简单的set语句,将sashelp库中的cars数据集读取进来。在上方的日志窗口中,显示了我们所运行的程序以及程序执行的结果。日志语句第一行,在sashelp.cars数据集中有428条记录,第二行显示我们创建的car数据集读取了428条记录,第三行以下是SAS进行以上操作的时间。看了以上信息,我们知道数据集已经成功地被读取和创建,这样就可以开始下一步的操作了。
图2-43
有些时候,日志中会出现一些特殊的信息,当你看到这些内容时候就要警惕了。特殊信息包括ERROR、WARNING和NOTE。在讲解SAS窗口的时候,我们提到ERROR、WARNING和NOTE是SAS中常见的3种提示语句,它们表示的警示程度依次降低。
(1)ERROR表示错误。即程序因为某些错误无法执行的问题,这时你在该步想要创建的数据集无法创建,想进行的操作也无法完成,如果这一步在一系列程序之中,它往往会影响到后续的程序。ERROR在日志中是绝不允许存在的,如果存在,就一定要修正程序,重新运行,保证它消失不见。
(2)WARNING表示警告。当日志中出现了WARNING,程序不一定会无法运行,也可能得出了你需要的结果,但很多时候是因为程序不明确或错误,导致SAS只能按照缺省设置完成操作,此时你获得的数据集和结果不一定是你真正想要的。对于WARNING,不同行业甚至不同公司的规定都不同,对笔者所在的医药行业而言,因为对数据正确性的要求极高,不允许有任何问题,因此WARNING也是不被允许的。
(3)NOTE表示提示。是三者中警示级别最低的,在上图中我们就看到了NOTE,它们只是提示一些执行过程,但有些NOTE会提示相对重要的信息。这些NOTE出现的原因往往并不是你的语法有错误或不明确,而是由于操作产生的结果与SAS预想的不同,所以在日志中显示NOTE给分析师,分析师可以根据情况选择是否修改代码。在编程中,NOTE一般允许存在,不过提示大家如果日志中有不寻常的NOTE,需要着重查看逻辑,以确定结果符合我们的预期。
在日志中,程序和宏程序用黑色字体表示,如图2-43中我们看到的前3行。NOTE用蓝色表示,WARNING用绿色表示,ERROR用红色表示,它们的警示度依次提升。所以一个SAS运行日志,最好的情况不是花花绿绿,而是素雅宁静,只包含黑色和蓝色。
下面我们通过一些具体的图片来直观感受一下经常遇到的日志提示内容。首先我们看几个常见的ERROR。
(1)语句错误。
图2-44的日志中包含了红色的ERROR和绿色的WARNING。ERROR提示语句无效或者未被正确使用,因此数据集car无法创建,抛出WARNING。原因也很简单,我们的if语句的if被错打成了ef,因此无法被SAS识别。其实这个问题很好发现,因为在编程栏ef已经变红进行提示,但注意这是SAS桌面版才有的效果,虚拟机版和SAS OnDemand并没有这种提示。
图2-44
(2)变量不存在。
图2-45同样是拼写错误导致的问题,但此处错的不是语句而是变量名。在SAS中的提示内容为变量invoce不存在,这是因为car数据集中只存在变量invoice而非invoce,SAS在执行前并不能判断某个变量是否存在,只能按图索骥,发现invoce变量不存在,于是抛出错误。
图2-45
(3)函数参数不足。
图2-46中,程序比之前的内容新增了一行,使用到了substr函数,函数是SAS中功能丰富的数据处理工具,我们会在第3章涉及,这里只用知道substr需要至少两个参数,而以上语句只包含了一个参数,因此substr无法执行,抛出的ERROR提示substr函数没有足够的参数,同时WARNING提示数据集car无法创建。
图2-46
简单介绍几个ERROR后,让我们再来了解一下常见的WARNING。
(1)在keep drop rename中的变量不存在。
图2-47使用keep语句保留部分变量,但数据集中不包含变量tipe,这个问题不会导致程序无法执行,只是无法保留keep语句中所有的变量,因此程序抛出WARNING,提示用户在keep后的变量列表里,变量tipe不存在。虽然问题存在,但程序依然可以执行,只是生成的数据集中只包含4个变量,缺少了tipe。
图2-47
(2)长度已被定义。
图2-48中所示的程序是在data步中读取数据集sashelp.cars,并且对变量model的长度进行设置。但由于变量model已经在原有的数据集中,我们无法对一个已经存在的变量再次设置长度,因此程序抛出WARNING,字符型变量model的长度已经被设置,下面一句还贴心地给出了提示,告知分析师可以把length语句提前到data步非常靠前的位置来设置长度。
图2-48
下面再来看几个值得注意的NOTE。
(1)变量类型的转换提示。
SAS中有两种变量类型——字符型和数值型,如果某个变量是字符型,但被当作数值型使用,在可以理解的范畴内SAS就会自动转换理解数据的方式然后执行。这里有两点需要注意。
第一点是可以理解的范畴。例如一个字符型变量中的内容是数字,如果在程序中被当成了数值型变量,参与了某些运算,SAS就会将其自动理解为数值,并进行运算,然后抛出提示,确认这是用户希望做的方式,图2-49中的提示就是一例。
图2-49
第二点就是转换“理解”数据的方式,而非数据本身的格式,在转换操作后,被涉及的数据类型并不会转变。
(2)变量未初始化。
图2-50的提示也是我们有时会看到的,它表示变量b未被初始化,即我们在这一步执行之前,并未创建该变量。在以上程序运行完后,我们会在数据集car中得到两个变量a和b,它们都是缺失值,也就是说,SAS在执行到某一步时如果发现某个新变量并未定义,它会自动创建但不会赋值。
图2-50
(3)merge语句有多条相同by中变量的对应值。
图2-51中提示是由merge语句引发的,在两个数据集合并过程中导致的问题。merge语句的用途是横向合并数据集,我们会在后续的内容中涉及,这里只是提醒读者,当merge语句运行后出现以上提示的时候,你的合并结果往往与预期不同,需要检查、修改并重新运行。
图2-51
SAS提供了非常多的ERROR、WARNING和NOTE信息,很多信息还提供了详细的解决方法,这也是SAS作为高级语言的优势之一:调试速度较快。
在编程实践中,建议读者不要将所有程序编写完毕后一起运行、调试,而是应该小步快跑,每完成一部分程序就应当运行一下,确认没有问题后再开始下一部分的编程。如果产生了问题,要详细理解ERROR和WARNING中的提示信息,并加以改正。这也是三分剑术的精髓所在,不要追求一次击杀敌人,在多次快速的攻击中寻找机会,逐步完成自己的目标。
2.4.3 善用注释——太极剑法
太极剑法为武当派绝学,特点是以意驭剑,千变万化,无穷无尽,是张三丰闭关修炼多年参悟的武学。它的特点是只有一招,即圆弧形刺出,只要记住这一招,根据战斗局势灵活地变化,即可击破敌人。当年张三丰在教导张无忌时,直到张无忌渐渐遗忘了具体招式,才称其学有大成。
在SAS中,我们也希望找到这样一“招”,它就像锚一样,可以让我们记住它就能想起具体的内容,这就是SAS中的注释。
注释在程序中由绿色字体表示,并不会执行,一般在代码中用于记录某一段代码的功能或某个变量的用途。SAS中的注释有两种创建方法。
一种以星号*开头,以分号;结尾,例如以下代码:
在array语句之前和do语句之前插入注释,解释array和do语句分别引导的内容。
另一种以/*开头,以*/结束,例如以下代码:
同样可以实现上述功能。
需要注意的是,两种注释均可以跨行操作,即在某一行使用开头符号,在另一行使用结尾符号,那么两行之间所有的语句都会成为注释的内容。例如我们在SAS程序的开头,往往会使用注释来描述SAS程序的内容,例如以下内容:
它记录了程序的名称、作者、创作时间和版本号,可以提供给数据分析师程序的基本信息,方便改写或续写。
另外,注释功能还有一个妙用,当你有一些语句不希望运行,但仍希望保留的时候,可以使用注释功能将其注释掉,这样程序便不会执行。SAS还提供了相应的快捷键,使用Ctrl+/键(Mac OS中是Command+/),可以将选定行全部注释。使用Ctrl+Shift+/(虚拟机版和SAS Studio中是Ctrl+/),即可将选定行的注释取消。
SAS的注释就如同太极剑法中的圆刺一样,是武学和编程中的锚,在程序中做好注释,可以帮助我们的编程更上一层楼。
2.4.4 帮助文档——北冥神功
北冥神功是逍遥派上乘内功,完整版由李秋水收藏于无量山洞琅寰福地中,可以吸收他人内力为己所用,并且吸收的内力可以转化为阴阳并济的北冥真气。
在SAS编程的学习中,也一定会有自己未碰到过的问题,即使是本书也不可能将SAS所有编程知识全部讲解,这就需要读者有一定的领会能力和查询能力。在各个信息源之中,SAS官网和人大经济论坛是笔者比较推崇的学习途径。
SAS官网提供了大量学习SAS的资料,而且资料的结构设置合理,很容易按图索骥。例如我们希望学习SAS substr函数的用法,可以直接在搜索引擎中搜索SAS substr,如图2-52所示。
图2-52
在得到的搜索结果中选择SAS官网的内容,即以https://support.sas.com/开头的地址。
可以看到,SAS官网提供了substr函数的详细信息(见图2-53),包括语法、参数、细节、案例和相关内容。需要注意的是,SAS对中文的支持不是非常好,有些中文优化甚至可以说做得比较糟糕,建议大家直接阅读英文内容,这也对学习者的英语有一定的要求。SAS数据分析师在中国的很多职位其实是做外国公司的项目,需要用英文电话沟通,对工作者的英文本身就有一些要求,在学习SAS的时候熟练掌握英文,也可以更好地了解专业词汇,一举多得。
图2-53
如果你有一些具体的问题需要了解,可以到人大经管论坛询问和查询,地址为https://bbs.pinggu.org/,这是中国最大的经管和数据分析论坛。因为论坛良好的奖励机制,很多优秀的SAS从业者发表自己的经验和帮人解答问题,是职场新人提升不可错过的宝地。
通过别人的经验,提升自己的能力,这是每一个数据分析师都应该掌握的技能。所谓“他山之石,可以攻玉”的道理就在于此。在信息获取渠道上,还有一些知名博客、某些线上课程,总之我们应像“北冥神功”一样,吸收各方的真气为我所用。还要注意的是,别人提供的只是信息,想要真正掌握还需要自己领悟和理解,就如同段誉只学习了北冥神功的第一幅图,虽然可以吸收敌人的真气,却无法转化,导致自身被反噬,最终演化成“吸星大法”这样的邪派武功的话,就得不偿失了。
以上就是本节的内容。我们用金庸武侠中的4种武功代表了SAS编程的好习惯。浑然一体的六合刀法,代表在编程中对齐的好习惯;小步快跑,随时变招的三分剑术,代表了编程中随时运行,查看日志,调整代码的好习惯;只抓主干,认定锚点的太极剑法,代表了SAS中注释的用处;博采万家,为我所用的北冥神功,代表了数据分析师应当善用外部资料的能力。
到此为止,我们可以算了解了SAS这个“朋友”。编程语言的学习和交朋友非常类似,如果一开头就奔着功利的目的,整天盘算这个朋友能给我带来多少价值,那么这种友情既不深也不远,只有找到基本价值观相同的人,从历史聊到爱好,从一起做事到共同进步,才是交朋友的正道。本章希望给你带来的就是这种“朋友的体验”,从SAS的历史到版本,从编写第一个SAS程序到养成编程好习惯,笔者一直希望传递给读者一种感觉,即SAS是一个优秀的好朋友。
从下一章开始,我们将从细节处讲解SAS编程的知识点,请你收拾好行装,准备上路,我们最终都要远行。