日本一意孤行?国际原子能机构认为福岛处理水排海计划符合国际安全标准

普里戈津之死!我的三点评论!

从人类历史,看人类未来

目录一览!马工程重点教材《习近平新时代中国特色社会主义思想概论》

从福岛核废水说起:我们是在谈科学还是讲立场

生成图片,分享到微信朋友圈

自由微信安卓APP发布,立即下载! | 提交文章网址
查看原文

SAS岩论 | Macro系列(1)——入门篇

统计札记 2023-02-24

The following article is from SAS中文论坛 Author 辛岩

Macro系列导读

SAS Macro作为SAS高手不可或缺的一项技能,是因为它功能足够强大,能极大的提升程序开发效率;使你的时间和精力投入在更有价值的事情上。

Macro系列文章,将会逐一奉上SAS Macro的点点滴滴,带你踏上从认识Macro到熟练使用Macro之路。掌握SAS Macro,将会使你的SAS编程能力更上一层楼。



本篇作为SAS Macro系列的开篇文章,通过一个实际问题来引入Macro。带你走入Macro的世界,初步认识它,了解它主要能完成什么事情。



问题说明

客服中心每天都会接到大量的客户咨询、投诉电话,后台系统会记录相关的数据,例如:客户ID、通话开始时间、通话结束时间、通话类型等指标。现需要统计每半小时的话务接入量,数据如下所示:


完成这个统计,需要以下几个过程:

1.将通话开始时间的时间部分提取出来;

2.判断该时间属于48个区间的哪个区间,可以简单的用数字1~48来标记;

3.利用PROC SQL或者PROC FREQ统计每个区间的频数


DATA步实现

一般情况下,完成1、2两个步骤,会使用类似下面的DATA步实现(非一般情况的方法,请看文末):

data data1;

   set sample;

   call_time=timepart(call_start_time);

 

   if call_time<'00:30:00't then time_class=1;

   else if call_time<'01:00:00't then time_class=2;

   else if call_time<'01:30:00't then time_class=3;

   else ifcall_time<'02:00:00't then time_class=4;

   ......

   else if call_time<'23:00:00't then time_class=46;

   else if call_time<'23:30:00't then time_class=47;

   else time_class=48;

run;


可以看到,要想完成区间的标记,需要使用48个IF-ELSE语句来实现;假设要每隔15分钟来统计,就需要写96个IF-ELSE语句!

 

写完如此大量重复的IF-ELSE语句,将会使人崩溃,而且将会耗费不少时间。有没有办法减少写重复语句的办法?有,可以使用Excel来协助批量生成这些重复的ELSE-IF语句,然后将语句复制到SAS即可。使用Excel的办法看起来很Low,但是有时候特别见效。



Macro实现

除了Excel来协助,另外一个办法就是利用SAS Macro来帮你生成这么多的ELSE-IF语句。先直接上代码,看看Macro如何完成此功能。

%macro mark_time;

data data1;

   set sample;

   call_time=timepart(call_start_time);

 

   if call_time<'00:30:00't then time_class=1;

   %do i=%to 47;

      %let h=%sysfunc(int(&i/2));

      %let m=%eval(%sysfunc(mod(&i,2))*30);

      else if call_time<"&h:&m:00"t then time_class=&i;

   %end;

   else time_class=48;

run;

%mend mark_time;


是不是很简单?利用Macro的循环,帮你生成46个ELSE-IF语句,将这些重复的工作交给Macro来完成。这个过程就好比利用Excel来批量生成ELSE-IF语句,只不过你不用手动去生成,Macro帮你完成。



启用MPRINT OPTION,调用MARK_TIME Macro,在日志中会显示生成的SAS代码:

option mprint;

%mark_time





上面的Macro程序为了使生成的代码好看易理解,特地生成”hh:mm:ss”t形式的日期常量。如果只是实现功能,还可以更直接一点:

%macro mark_time2;

data data2;

   set sample;

   call_time=timepart(call_start_time);

 

   if call_time<1800 then time_class=1;

   %do i=%to 47;

      else if call_time< (1800 + (&i-1)*1800) then time_class=&i;

   %end;

   else time_class=48;

run;

%mend mark_time2;



运行该Macro,生成的SAS代码如下:


透过上面的例子,我们可以基本了解Macro是用来做什么的。它就是你的编程助手,协助你批量生成代码,完成特定的功能。我曾在一本书上看到过形容Macro的一句话,我觉得形容的特别贴切:


“When you write a macro program, you are writing a program that writes a program.”



Macro Language和SAS Language(常用的DATA步和PROC步),可以理解为独立的处理的。Macro language是专门由Macro Facility处理,而且是在SAS Language编译前处理的。正如上面的例子,Macro Language(带%的语句)先由Macro Facility处理,生成46个ELSE-IF语句,然后整个DATA步开始编译、执行,得到最终的结果。


Macro除了可以批量生成代码,还可以完成:DATA步,PROC步相互之间的数据传递、根据条件动态执行DATA步或者PROC步、代码的封装,重复利用等等功能。更多内容,请持续关注“SAS中文论坛”微信公众号——“SAS岩论-Macro系列”。



 

作者:辛岩,从事了多年的SAS数据分析挖掘工作,担任过项目经理、技术顾问、培训讲师等职务,拥有丰富的项目实战经验。

剑指SAS,尽在今朝。欢迎各位技术达人交流,可以长按下面群二维码入SAS中文论坛微信群@Slash,也可以发邮件:slash.xin@hotmail.com。


SAS岩论系列文章,请点击阅读

SAS岩论|在SAS中如何解决中文乱码问题(1)

SAS岩论|在SAS中如何解决中文乱码问题(2)-干货篇

SAS岩论|SAS EG中如何显示Data步处理进度

SAS岩论 | 使用DATA步并行处理超大数据集



最后,附上解决上面时间标记问题的,非一般的、不使用Macro的程序:

data data3;

   set sample;

   h=hour(timepart(call_start_time));

   m=minute(timepart(call_start_time)); 

   time_class=h*2 +int(m/30) + 1;

 

   drop h m;

run;

此种方法,属于取巧的一种。通过分析时间和标记区间的关系,直接一步到位;基于时间,直接推算出所属区间。


文章有问题?点此查看未经处理的缓存