宏概述

  • 宏以前被认为是经验老道的SAS程序员使用的高级技术。

  • 宏处理器 标准SAS程序中,提交程序后,SAS就编译并立即执行。但宏语句多了一步,在提交之后,SAS会将宏语句传送到宏处理器上,将其转变为SAS标准代码,通常叫做“变换代码”(meta-programming.)

  • 宏和宏变量 SAS宏代码包括两个基本部分:宏命令和宏变量。宏变量通常加一个“&”作为前缀,而宏命令通常加一个“%”作为前缀。

  • 局部VS全局 宏变量有局部宏变量和全局宏变量。如果在宏的内部定义则为局部宏变量,只能在内部使用。如果在开放代码中定义则为全局宏变量。避免两种错误:在宏之外(开放代码)使用局部变量;创建同名的局部变量和全局变量。

  • 启动宏处理器 使用宏指令之前必须将宏系统选项打开,尽管有时默认是打开的。可以用下面代码查看是否打开:

PROC OPTIONS OPTION=MACRO; 
RUN;

查看日志,如果看到MACRO,则打开了;如果看到NOMACRO,则没有打开。

宏变量

  • %let创建一个宏变量 最简单给宏变量分配一个值的方法是%let,基本形式为:
%LET macro-variable-name=value;
  • 宏变量名必须符合SAS命名法则,(少于等于32字节、以字母或下划线开头、只能包括字母、数字和下划线),下面创建了宏变量:
  %LET iterations=10;
  %LET country=New Zealand;
  • 当赋值字符串时,不需要加引号。除非在开头和结尾有空格,否则从等号到分号的全部内容都是变量值。

  • 使用宏变量 宏变量前面要加前缀&,注意宏处理器找不到单引号内的宏变量,只能用双引号。如下的例子:
DO i=1 to &iterations;
TITLE ”Addresses in &country”;

经宏处理器编译后,语句变成:

DO i=1 to 10;
TITLE ”Addresses in New Zealand”;

一份关于花店销售的数据,变量为顾客ID,销售日期,花的种类,数量 想要一份反映某一种类型花的销售情况数据,宏变量就可以不用编辑数据步和过程步来选择一种花种:

TropicalSales.dat 下载

%LET flowertype = Heliconia;

* Read the data and subset with a macro variable;
DATA flowersales;
   INFILE 'c:\MyRawData\TropicalSales.dat';
   INPUT CustomerID $4. @6 SaleDate MMDDYY10. @17 Variety $9. Quantity;
  IF Variety = "&flowertype";
RUN;
* Print the report using a macro variable;
PROC PRINT DATA = flowersales;
   FORMAT SaleDate WORDDATE18.;
   TITLE "Sales of &flowertype";
RUN;

宏模块化代码

  • 宏可以使一段代码在一个或多个程序中被反复使用,而不需要重复地去编写相同或相似的代码。基本形式为:
%MACRO macro-name;
macro-text
%MEND macro-name;

%MACRO语句告诉SAS这是宏开始,而%MEND则意味着结束。macro-name是自己命名的,但mend后面的macro-name则是可选的,但加入会使得句子好很多(easier to debug and maintain)。

  • 启动宏 定义了宏之后,可以通过在宏名称前面增加%来启动宏:%macro-name,注意这里可以不用分号。

例子

使用前面花店销售的数据:

下面的代码创建了一个名为%SAMPLE的宏,来将数据按照Quantity排序,打印出最大销售额的五个观测值(先降序排列,然后用OBS指定最后一行)。然后用标准数据步读取数据,并启动宏:

/* Program */
* Macro to print 5 largest sales;
%MACRO sample;
   PROC SORT DATA = flowersales;
      BY DESCENDING Quantity;
   RUN;
   PROC PRINT DATA = flowersales (OBS = 5);
      FORMAT SaleDate WORDDATE18.;
      TITLE 'Five Largest Sales';
   RUN;
%MEND sample;

* Read the flower sales data;
DATA flowersales;
   INFILE 'c:\MyRawData\TropicalSales.dat';
   INPUT CustomerID $4. @6 SaleDate MMDDYY10. @17 Variety $9. Quantity;
*proc print;
RUN;

* Invoke the macro;

%sample
  • 宏自动呼叫库 本书中的宏仅在一个程序内部定义和启动。也可以将宏储存在一个中心位置,叫做自动呼叫库,被各个程序分享。具体来说,将宏作为文件储存在某路径中,或作为分区数据集中的一员。使用MAUTOSOURCESASAUTOS=系统选项告诉SAS在哪里查找宏。之后,即使宏没有出现在程序中,也可以启动它。

宏参数

  • 参数就是宏的变量,给宏增加参数,在%MACRO语句中的括号内列出宏变量的名字。基本形式为:
%MACRO macro-name(parameter-1=,parameter-2=,...parameter-n=);
macro-text
%MEND macro-name;
  • 比如,一个叫做%QUARTERLYREPORT的宏可能这样开始:
%MACRO quarterlyreport(quarter=,salesrep=);
  • 这个宏有两个参数&QUARTER&SALESREP。启用这个宏可以用这样的语句:
%quarterlyreport(quarter=3,salesrep=Smith)

例子

/* Program */
* Macro with parameters;
%MACRO select(customer=,sortvar=);
   PROC SORT DATA = flowersales OUT = salesout;
      BY &sortvar;
      WHERE CustomerID = "&customer";
   RUN;
   PROC PRINT DATA = salesout;
      FORMAT SaleDate WORDDATE18.;
      TITLE1 "Orders for Customer Number &customer";
      TITLE2 "Sorted by &sortvar";
   RUN;
%MEND select;


* Read all the flower sales data;
DATA flowersales;
   INFILE 'c:\MyRawData\TropicalSales.dat';
   INPUT CustomerID $4. @6 SaleDate MMDDYY10. @17 Variety $9. Quantity;
RUN;

*Invoke the macro;
%select(customer = 356W, sortvar = Quantity)
%select(customer = 240W, sortvar = Variety)

使用条件逻辑写宏代码

  • 在宏中使用条件逻辑的基本形式为:
%IF condition %THEN action;
%ELSE %IF condition %THEN action;
%ELSE action;
%IF condition %THEN %DO;
SAS statements
%END;
  • 自动宏变量 每一次启动SAS,宏处理器自动创建一些宏变量,可以使用在程序中。最常见的有:
    • &SYSDAY
    • &SYSDATE
  • 比如,可以像这样结合自动宏变量和条件逻辑语句:
%IF &SYSDAY=Tuesday %THEN %LET country=Belgium;
%ELSE %LET country=France;

例子

%MACRO dailyreports;
   %IF &SYSDAY = Monday %THEN %DO;
      PROC PRINT DATA = flowersales;
         FORMAT SaleDate WORDDATE18.;
         TITLE 'Monday Report: Current Flower Sales';
      RUN;
   %END;
   %ELSE %IF &SYSDAY = Saturday %THEN %DO;
      PROC MEANS DATA = flowersales MEAN MIN MAX;
         CLASS Variety;
         VAR Quantity;
         TITLE 'Wednesday Report: Summary of Flower Sales';
      RUN;
   %END;
%MEND dailyreports;
DATA flowersales;
   INFILE 'c:\MyRawData\TropicalSales.dat';
   INPUT CustomerID $4. @6 SaleDate MMDDYY10. @17 Variety $9. Quantity;
proc print;   
RUN;
%dailyreports