公告

[公告]
2014/01/17
由於已經是faculty的關係,不太有足夠時間寫部落格。因此更新的速度會相當緩慢。再加上近幾年來SAS GLOBAL FORUM沒有出現讓我覺得驚艷的技術文件,所以能分享的文章相對也減少許多。若有人推薦值得分享的SAS技術文件,請利用『問題討論區』告知。

2013/07/19
臉書留言板的功能因為有不明原因故障,因此特此移除。而intensedebate的留言板因管理不易,也一併移除。目前已經開啟內建的 G+ 留言系統,所以請有需要留言的朋友,可直接至『問題討論區』裡面留言。


2011年4月3日 星期日

So Many Variables; Too Many Labels, Moving Labels from One Variable to Another

原文載點:http://support.sas.com/resources/papers/proceedings10/047-2010.pdf

在 SAS 資料處理的過程中,使用者會發現,當複製一個變數並給予新的變數名稱時,舊變數的格式雖然會一併複製到新變數裡面,但舊變數的 label 卻沒有辦法複製過去。若只有一兩個變數時還可以用手動的方式在 data step 裡面重打,但若變數過多時,這就會成為一個相當棘手的問題。John Ladds 提供了一個簡易的方式來解決這個 label 複製的問題。

以下面這個資料集當作範例:
proc format;
   value OriginalOrderAgree
       1 = 'Strongly agree'
2 = 'Somewhat agree'
3 = 'Neither agree nor disagree'
4 = 'Somewhat disagree'
5 = 'Strongly disagree'
6 = 'Not applicable'
      97 = "Don't know"
99 = 'Not stated';
   value ReverseOrderAgree
       5 = 'Strongly agree'
4 = 'Somewhat agree'
3 = 'Neither agree nor disagree'
2 = 'Somewhat disagree'
1 = 'Strongly disagree'
       other='Missing';
run;
** Create some test data;
data work.theData;
   input @01 id    $10.
         @11 Q001    2.
         @13 Q002    2.
         @15 Q003    2.
         @17 Q004    2.
         @19 Q005    2.
         @21 Q006    2.
         @23 Q007    2.
         @25 Q008    2.
         @27 Q009    2.
         @29 Q010    2.;
   label Q001 = "Have material's and equipment I need";
   label Q002 = "Material and tools avail in lang choice";
   label Q003 = "I use the language of my choice";
   label Q004 = "My jobs fits my interests.";
   label Q005 = "I have support at work.";
   label Q006 = "I am satisfied, current work arrangement";
   label Q007 = "I can claim overtime";
   label Q008 = "Overall, I like my job.";
   label Q009 = "I get satisfaction from my work.";

   label Q010 = "I know how my work contributes";
format Q001-Q010 OriginalOrderAgree.;
datalines4;
1234567890 1 2 3 4 5 6 1 2 3 4;
1234567892 2 3 4 5 1 1 2 3 4 5;
1234567893 3 4 5 1 2 2 2 3 5 1;
1234567894 4 5 1 2 3 3 3 3 1 2;
1234567895 5 1 2 3 4 4 4 4 2 3;
1234567896 1 2 3 4 5 5 5 5 3 4;
1234567897 2 3 4 5 1 1 1 1 4 5;
1234567898 3 4 5 1 2 2 2 2 5 1;
1234567899 4 598 2 3 3 3 3 1 2;
123456781099 199 3 4 4 4 5 2 3;
;;;;
run;

根據這個資料集,裡面有十個變數,從Q001~Q010,每個變數為數據「1,2,3,4,5」。現在假設要製造新變數R_Q001~R_Q010,而這些新變數是將就舊變數的數據倒轉過來,也就是 1 變成 5,2 變成 4,...,5 變成 1。於是作者利用下面這個 macro 來處理這段:
%macro reverseValueOrder(Q=,Qfmt=);
   select(&Q.);
     when(1)   R_&Q.=5;
     when(2)   R_&Q.=4;
     when(3)   R_&Q.=3;
     when(4)   R_&Q.=2;
     when(5)   R_&Q.=1;
     otherwise R_&Q.=.;
   end;
   ** Transfer the questions label to the new variable;
   if eof then call execute("label R_&Q.="||'"'||strip(vlabel(&Q.))||'";');
   ** Add the new value labels to the new variable;
   format R_&Q. &Qfmt..;
%mend reverseValueOrder;

其中,「select(&Q);.....end;」主要就是在做變數倒轉的工作,而下面有一行「if...then...」搭配「call execute」便是在處理 label 複製的動作。裡面的 vlabel 函數的作用是將舊變數裡面的 label 給列出來,放在 strip 函式後面主要是移除不必要的空格,並確保 vlabel 函式叫出來的 label 是字串形式。

接著就可以在新的 data step 裡面一邊進行數據倒轉的工作,一邊進行搬移 label 的工作,如下所示:
data work.thedata;
   set work.theData end=eof;
** Open the post DATA STEP Processing;
if eof then call execute('data &syslast.; set &syslast.;'); 
**A. My Job World                              ;
   %reverseValueOrder(Q=Q001, Qfmt=ReverseOrderAgree);
   %reverseValueOrder(Q=Q002, Qfmt=ReverseOrderAgree);
   %reverseValueOrder(Q=Q003, Qfmt=ReverseOrderAgree);
   %reverseValueOrder(Q=Q004, Qfmt=ReverseOrderAgree);
   %reverseValueOrder(Q=Q005, Qfmt=ReverseOrderAgree);
   %reverseValueOrder(Q=Q006, Qfmt=ReverseOrderAgree);
   %reverseValueOrder(Q=Q007, Qfmt=ReverseOrderAgree);
   %reverseValueOrder(Q=Q008, Qfmt=ReverseOrderAgree);
   %reverseValueOrder(Q=Q009, Qfmt=ReverseOrderAgree);
   %reverseValueOrder(Q=Q010, Qfmt=ReverseOrderAgree);
;... ... ... ... ... ... ... ... ... ... ... **  
** Close the post DATA STEP Processing;
if eof then call execute ('run;');
run;

特別提醒的地方有三個。一是 set 後面一定要加上「end=eof」字樣。二是執行 macro 前加上「if eof then call execute('data &syslast.; set &syslast.;'); 」,目的是確保程式執行的資料是當前資料。所以記得在運作此程式之前,別去跑其他不相干的資料。三是結束前加上「if eof then call execute ('run;');」,這樣就大功告成了。


CONTACT INFORMATION
Name:  John Ladds
Enterprise: Statistics Canada – SDD SAS Technology Centre
Address:  14-R-90 R.H. Coats Building,
100 Tunney’s Pasture Driveway
Ottawa, Ontario, Canada
K1A 0T6
Phone:  613 951-1767
E-mail: John.Ladds@statcan.gc.ca
Web:  www.statcan.ca
CODE { display: block; /* fixes a strange ie margin bug */ font-family: Courier New; font-size: 8pt; overflow:auto; background: #f0f0f0 url(http://klcintw.images.googlepages.com/Code_BG.gif) left top repeat-y; border: 1px solid #ccc; padding: 10px 10px 10px 21px; max-height:200px; height:200px; // for IE6 line-height: 1.2em; }