帶你走進SAS宏的世界

帶你走進SAS宏的世界

一、什麼是宏?

當我們剛開始接觸宏的時候,往往會使用些由%LET、CALL SYMPUT和PROC SQL INTO等建立一個全局的宏,應用到後續的過程步中,隨著這些宏的頻繁使用,我們腦海裡往往會形成一個這樣的概念:在SAS中,預處理器會根據一系列預定義的“內容”對源代碼進行替換運行。如下例1:

%LET OUTPATH = %STR(E:\\TEST\\) ;

%LET TABLENAME = %STR(TEST);

********

ODS RTF FILE = “&OUTPATH.&TABLENAME..rtf” ;

********

但隨著宏更進一步的使用,慢慢的會發現自己之前給的這麼一個定義也沒那麼準確,好像差點什麼,尤其是在宏過程的使用中。宏參雖然也是一個個“內容”,但更確切的說,它是一個個符合需求的條件,這個時候我們的概念就更加清晰了:在SAS中,預處理器會根據一系列定義的規則有條件地對源代碼進行替換運行。如下例2:

LET OUTPATH = %STR(E:\\TEST\\) ;

%MACRO CLASS(FACTOR ,TABLENAME) ;

DATA CLASS ;

SET SASHELP.CLASS ;

&FACTOR. ;

RUN ;

ODS RTF FILE “&OUTPATH.&TABLENAME..rtf” ;

PROC REPORT DATA = CLASS ; RUN ;

ODS RTF CLOSE ;

%MEND ;

%CLASS(WHERE AGE > 13 ,TABLENAME1);

%CLASS(WHERE AGE > 15 ,TABLENAME2);


二、什麼時候使用宏?

我們使用的宏的目的往往是因為它“省事”,使用宏可以讓我們少寫點代碼,讓我們代碼看起來很簡潔,減少手動更改的操作量。基於這些目的我們可以知道我們應當在以下情境下使用宏:

1、一個重複使用的變量,如例1的&OUTPATH;

2、一個重複使用的語句內容,如例2的&FACTOR;

3、一個重複使用的過程步,如例2的DATA STEP;

4、一個重複使用的綜合過程,如這個例2;


三、怎麼去使用宏?

❑ 宏與PDV

我們接下來會通過三個方面來講解怎麼去使用宏,第一個方面是全局宏和局部宏,第二個方面是循環體和條件語句,第三個方面是如何進一步的提升運行效率。但在考慮怎麼應用宏之前,我們有必要了解下宏在PDV(Program Data Vector)是怎麼被處理的。如下圖1所示:

帶你走進SAS宏的世界

我們可以看到,相對一般DATA STEP的PDV過程,擁有宏的程序內會多一個宏處理器的過程。在首次確定宏之後會進行一個預編譯,再到了宏展開的時候,會將預編譯的結果返回值Buffers進行一次非宏過程過程的編譯過程。這過程也很簡單,但不能被忽略,比如在DATA STEP中應用CALL EXECUTE,而且在CALL EXECUTE中創建宏變量的同時應用該宏變量,這就犯了這個PDV的過程,要知道CALL EXECUTE裡邊的內容是先被編譯然後再去執行的。

❑ 全局宏與局部宏

在應用宏過程中,我們需要知道全局宏變量和局部宏變量的概念,全局宏的定義是在開放型代碼中定義的宏為全局宏,而局部宏的定義則為在一個宏過程中定義或生成的宏為局部宏。兩者的區別很顯然,是一個相對的概念,是否是在宏過程中創建的宏變量。兩者都可以通過%LET、CALL SYMPUT語句和PROC SQL過程等語句或過程創建,全局宏不可以轉換為局部宏,但局部宏可以通過%GLOBAL轉換為全局宏。

我們瞭解了全局宏和局部宏,還需要知道的是全局宏可以應用到局部宏,一級宏中嵌套了二級宏,這個時候一級宏的宏參可以被應用到二級宏中。值得注意的是,如果一級宏的宏參名字和二級宏參的名字出現了一樣的情況,這會出現以下的情況:

帶你走進SAS宏的世界

雖然對於懶得想名字的人來說,這無疑是個好應用,但如果這樣操作,勢必會增加Debug的難度。

❑ 循環體和條件語句

在宏應用裡邊,還有個重要的內容我們需要了解的是循環體和條件語句,循環體如下:

1、%DO <macro-var> = <start> %TO [%BY STEP];/<start>/<macro-var>

MACRO STATEMENT ;

%END ;

2、%DO %WHILE <macro> ; /<macro>

MACRO STATEMENT ;

%END ;

3、%DO %UNTIL <macro> ;/<macro>

MACRO STATEMENT ;

%END ;

條件語句如下:

1、%IF <macro> %THEN <true>;/<true>/<macro>

%ELSE <false>;/<false>

和平常使用的未加百分號的循環體不同的是,這裡加了百分號的循環體是可以脫離DATA STEP而存在的,也就是說循環體中間的“MACRO STATEMENT”可以是過程步,也可以是語句。那麼怎麼去循環一個數據集呢?

以DIXON檢驗法為例,不同樣本量之間的高端離群值、低端離群值、檢出水平和剔除水平都是不一致的,每發現出一個新的統計離群值,就要在原來的樣本上剔除該樣本,對剩下的樣本繼續檢驗,直至高端和低端都沒有統計離群值出現,才終止循環,同時這個時候需要將統計學離群值呈現出來。如果使用循環體,又該如何操作?

很顯然,我們是反覆的對同一個數據集進行操作,中止循環的條件是高端和低端同時沒有出現統計離群值,在這裡會使用到宏嵌套宏的辦法摻雜著循環體,如下所示簡要代碼:

%MACRO DIXON(MACRO PARAMETERS1 ,……);

%DO %UNTIL(&DIXON_OUTLIERS. = 0 );

%GLOBAL DIXON_OUTLIERS ;

%DIXON_PROCESS(&DATA._&TARGET._4) ;

%END;

%MEND;

宏過程DIXON中嵌套著宏過程DIXON_PROCESS,同時宏過程中會返回數據集之外還會返回由宏過程DIXON_PROCESS產生的全局宏DIXON_OUTLIERS,用以做循環體%DO %UNTIL的循環判斷。


四、進一步提升效率

❑ 從宏過程輸出著手

減少中間數據集的生成及陳列,可以使用PROC DATASETS指定性的刪除work中的數據集,同時不陳列刪除了的數據集名稱,這樣使用SAS EG或 SAS BASE的時候很快捷的瀏覽自己所需要的數據集,可以使用 NOLIST 和 NOPRINT選項的儘量使用該選項,這樣某些程序產生的結果不必要的生成在HTML頁面或SAS結果頁面上;

❑ 從宏結構著手

減少宏過程,增加宏過程;比如就簡單的區分空腹和餐後,在開頭就進行簡單判斷,只分析餐後的數據或者只分析空腹的數據,如果能在不區分空腹和餐後的前提下分析數據,結果還是區分了空腹和餐後,那就一次性分析完,結果呈現上再區分空腹和餐後輸出。


分享到:


相關文章: