2014年3月14日 星期五

[SAS] macro的使用

Macro又名巨集,是非常實用的SAS coding技巧,
當你需要執行某程序,並且反覆執行它時,
最簡單的就是copy-paste..copy-paste..copy-paste..copy-paste這段程序,
ex.
假設手中有2005-2010 4筆資料(a2005 - a2008),想知道各年中y_05跟x的OR值等統計資訊,
*直覺懶人法;
proc logistic data=a2005;
  model y1(event="1") = x1;
run;
proc logistic data=a2005;
  model y2(event="1") = x2;
run;
proc logistic data=a2006;
  model y1(event="1") = x1;
run;
proc logistic data=a2006;
  model y2(event="1") = x2;
run;
...
...
...
proc logistic data=a2008;
  model y2(event="1") = x2;
run;
但是,我們都知道這是很笨也很沒效率的作法,也不符合優雅coding的理念,
所以macro是有學起來的必要性的,
如果引進macro寫法會變成怎樣呢,
OPTION NOSYMBOLGEN MPRINT;
%MACRO logiMc(year, y_vb, x_vb);
  proc logistic data=a&year;
    model &y_vb(event="1") = &x_vb;
  run;
%MEND logiMc;

%logiMc(2005,y1,x1)
  %logiMc(2005,y2,x2)
    %logiMc(2006,y1,x1)
      %logiMc(2006,y2,x2)
        %logiMc(2007,x1,y1)
          %logiMc(2007,x2,y2)
            %logiMc(2008,x1,y1)
              %logiMc(2008,x2,y2)
MACRO實際改寫出來的logistic程式碼只有4行(%MACRO和%MEND中間包的code),
原始寫法大約24行左右,節省了20行!
要不要學呢?! 當然看個人: )
其實macro不難,只是多了%和&符號而已,和一些參數設定的概念,
解釋如下:
由&開頭的變項稱為"巨集變項",
在要重複執行程序以外的指令程序,開頭要加上%,姑且稱作"巨集程序",
OPTIONS NOSYMBOLGEN MPRINT;      *在log檢視巨集和變數內容;
%MACRO logiMc(year, y_vb, x_vb);  *%MACRO-->宣告巨集的開頭,以及巨集名稱為logiMc,巨集接收3個參數year, y_vb, x_vb;
  proc logistic data=a&year;  *此處往下3行就是要重複執行的程序所在;
    model &y_vb(event="1") = &x_vb;  *由&開頭的巨集變項,會不斷被下方設定的巨集變數組代換,達到重複執行的目的;
  run;
%MEND logiMc;                    *%MEND-->宣告巨集的結尾;

/***巨集會來此處抓取設定好的巨集變數組,在程式區不斷做代換;**/
%logiMc(2005,y1,x1)			
  %logiMc(2005,y2,x2)
    %logiMc(2006,y1,x1)
      %logiMc(2006,y2,x2)
        %logiMc(2007,x1,y1)
          %logiMc(2007,x2,y2)
            %logiMc(2008,x1,y1)
              %logiMc(2008,x2,y2)
了解macro的精神後,就可以自由配合do, while, if-then, cat, 或甚至把多樣程序包到一個macro裡面,
for example:
先利用暫存檔作條件判斷
-->做retain 資料處理
-->再依條件output我要的檔案
//此處無需了解變數是什麼,只需了解怎麼編寫這樣的macro
OPTIONS NOSYMBOLGEN MPRINT; 
%MACRO test(o_y, o_y1, m_flag);
  %IF &m_flag=1 %THEN %DO;
    DATA WORK.in7; set WORK.in6;
        if season=&o_y & mdy(12,1,&o_y) <= indate < mdy(2,28,&o_y1) then output;
      run;

    DATA WORK.in8; set WORK.in7;
      by id;
        retain flu&o_y 0;
        flu&o_y = flu&o_y+1;
        if first.id then flu&o_y = 1;
    run;

    DATA in&o_y; set WORK.in8;
      by id;
        if last.id then output;
        keep id flu&o_y;
    run;
%END;
%MEND subset;
  %subset(2004,2005,1)
    %subset(2005,2006,1)
      %subset(2006,2007,1)
這邊會發現我多加了一條"%IF &m_flag=1 %THEN %DO;"和一個新參數"m_flag",
其實他的用意很簡單,就是"開關"的功用,
利用"如果m_flag=1(打開)就執行此組巨集變數"的概念,可以快速開關某組變數要不要跑巨集,
//進階寫法
當變數太多時,可能碰到設定巨集變數組麻煩的情況,
這時候可以配合do來達到更簡潔的寫法,
ex.
*記得,巨集語法開頭要加%;
%MACRO box( xStart, xEnd );
  %do xValue = &xStart %to &xEnd;
    proc surveylogistic data=aa;
      model y = &xValue * &xValue;
    run;
  %end;
%MEND box;
%box( 1, 16 )
Like this ! 歡迎提供補充和建議! : )

沒有留言:

張貼留言