公告

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

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


2007年3月4日 星期日

The Power of CALL SYMPUT – DATA Step Interface by Examples

原文載點:http://www2.sas.com/proceedings/sugi29/052-29.pdf

CALL SYMPUT 是一個使用在 Data step 的指令。其主要功能是提供一個良好的橋樑讓變數可以自由使用在 Data step 和 Macro 之間。Yunchao Tian 在 2004 年的 SUGI 29 上利用三個例子簡單地來介紹這個語法的強大功能。

EXAMPLE 1: CREATE A SERIES OF VARIABLE NAMES FROM ANOTHER VARIABLE'S VALUES

在模式配適中,我們經常需要將一些離散變數轉成 dummy variable。但有時候會遇到離散變數內的分項太多,這樣要製造 dummy variable 便會花上很多時間。舉例來說,有個離散變數 Con 含有 506 層,傳統方法要轉成 dummy variable 要用到以下程式碼:

IF CON = 1 THEN CON1 = 1; ELSE CON1 = 0;
IF CON = 2 THEN CON2 = 1; ELSE CON2 = 0;
. . . . . .
IF CON = 506 THEN CON506 = 1; ELSE CON506 = 0;


總共 506 行,在撰寫上極為消耗時間。而 SYMPUT 可以大幅簡化上述的程式碼,自動生成所有的 dummy variable。

以下有個簡短的例子。假設有個資料夾裡面有一個變數,12 個觀測值。如下所示:
DATA TESTDATA;
INPUT CON @@;
CARDS;
1 7 34 115 7 1 487 34 506 57 7 43
;
RUN;


欲新增數個變數,其名稱是 CON 後面接上觀測值的數字(CON1, CON7, ..., CON43)。當新的變數等於 CON 後面的數字時,其值等於 1,反之為 0。要完成這個目的,首先先將資料排序,並刪除重複數據(使用 NODUPKEY),然後把結果存成新資料集 UNIQUE:
PROC SORT DATA=TESTDATA OUT=UNIQUE NODUPKEY;
BY CON;
RUN;


建立一個新的暫存資料庫 _NULL_,將 UNIQUE 資料集導入,並將 CON 的最大值(也是最後一個數值)設定成一個 macro 變數,名為 N。
DATA _NULL_;
SET UNIQUE END=LAST;
IF LAST THEN CALL SYMPUT('N', PUT(CON, 3.));
RUN;


再設一個新的暫存資料庫,並將 0 設定給所有的 macro 變數 M1~M8。
DATA _NULL_;
DO I = 1 TO &N;
CALL SYMPUT('M'||LEFT(PUT(I, 3.)), '0');
END;
RUN;


再設一個新的暫存資料庫,讓 UNIQUE 資料庫裡面的 CON 值設定到對應的 macro 變數。
DATA _NULL_;
SET UNIQUE;
CALL SYMPUT('M'||LEFT(PUT(CON, 3.)), PUT(CON, 3.));
RUN;


接下來用一個 macro 程式來生成 dummy variable。
%MACRO GETCON;
%DO I = 1 %TO &N;
%IF &M&I = 0 %THEN %GOTO OUT;
IF CON = &M&I THEN CON&I = 1;
ELSE CON&I = 0;
%OUT: %END;
%MEND GETCON;


在原始的資料裡面導入剛剛做好的 macro 程式,這樣就大功告成了。
DATA TESTDATA;
SET TESTDATA;
%GETCON
RUN;


把資料列印出來看看。
PROC PRINT DATA=TESTDATA;
TITLE 'Table 1. List of CON with dummy variables';
RUN;


sugi052_29_01

EXAMPLE 2: GENERATE LABELS FOR A SERIES OF VARIABLES USING EXISTING FORMATS

這個例子可以讓人輕鬆的一次貼上大量的變數標籤。作者僅用一個含有六個變數的例子簡化程式的說明。

有一個資料內有六個變數(FLAG1~FLAG6)。
DATA FLAGS;
FLAG1 = 1; FLAG2 = 1; FLAG3 = 0;
FLAG4 = 1; FLAG5 = 0; FLAG6 = 1;
RUN;


先把要用到的標籤用 PROC FORMAT 設定好。
PROC FORMAT;
VALUE FMTFLAG
1='Red'
2='Purple'
3='Blue'
4='Yellow'
5='Orange'
6='Green';
RUN;


設定一永久變數 N 等於六,再製造一個新的暫存資料集,讓 SYMPUT 將剛剛 PROC FORMAT 弄好的標籤依序分配到新的 macro 變數 FMT1~FMT6。
%LET N = 6;
DATA _NULL_;
DO I = 1 TO &N;
CALL SYMPUT('FMT'||LEFT(PUT(I, 3.)), PUT(I, FMTFLAG.));
END;
RUN;


接著寫一小段 macro 程式,讓剛剛生好的 macro 變數再依序設定到原始變數 FLAG1~FLAG6。
%MACRO LABELS;
%DO I = 1 %TO &N;
FLAG&I = "I"
%END;
%MEND LABELS;


最後,再原始資料集裡面執行上一段 macro 程式,就大功告成了。
DATA FLAGS;
SET FLAGS;
LABEL %LABELS;
RUN;


將資料內容列印出來看看。
PROC CONTENTS DATA=FLAGS;
TITLE 'Table 2. Contents of SAS data set FLAGS showing variable labels';
RUN;


sugi052_29_02

最後一個例子有點是在講如何做批次改檔名,但我覺得沒有相當實用,所以不多加說明。有興趣的人去看本文。

CONTACT INFORMATION
Your comments and questions are valued and encouraged. Contact the author at:
Yunchao (Susan) Tian
Social & Scientific Systems, Inc.
8757 Georgia Avenue, 12th Floor
Silver Spring, MD 20910
Work Phone: (301) 628-3285
Fax: (301) 628-3201
Email: Stian@s-3.com
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; }