公告

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

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


2007年4月26日 星期四

Storing and Using a List of Values in a Macro Variable

原文載點:http://www2.sas.com/proceedings/sugi30/028-30.pdf

之前曾經提過一個相當強大的 text utility macro 可以批次更改大量的變數名稱,但是在使用那個程式之前,我們必須先把舊的變數名稱用一個 %let 的函數先命個名起來,之後才能將舊變數一次代入 text utility macro。可是,當舊變數高達上百甚至上千個時,怎樣將舊變數一次代入 %let 函數就變成另一個問題。比較笨一點的方法,就是把資料轉成 EXCEL 檔,則第一行會變成變數名稱,再把他全部剪下來貼到 SAS 裡面。不過 Arthur L. Carpenter 在 2005 年的 SUGI 30 就發表了一個技術文件來說明如何迅速地一次使用一串變數。

首先,得把資料裡面所有變數的相關訊息,包含變數名稱、格式和長度存出來。

proc contents data=sashelp.class noprint out=metaclass;
run;


存出來後,就可以做下列很多事情:

BUILD THE LIST IN A DATA STEP

在一個 data step 中把 metaclass 裡面的變數名稱叫出來並命名為 allvars。

%let varlist =;
data _null_;
set metaclass;
call symput('varlist',trim(resolve('&varlist'))||' '||trim(name));
run;
%put &varlist;


CREATING THE LIST WITH SQL

用 PROC SQL 把所有變數(包含名稱、長度、格式等訊息)一次叫出來,以供接下來的任何程序來使用。

proc sql noprint;
select name ,type, length
into :varlist separated by ' ',
:typlist separated by ' ',
:lenlist separated by ' '
from metaclass;
quit;
%let cntlist = &sqlobs;
%put &varlist;
%put &typlist;
%put &lenlist;
%put &cntlist;


上述程式中的 separated by 可以讓 SQL 一直加入接下來的東西,無論是變數名稱、格式或長度。如果只想抓出變數名稱,只要留下 varlist 相關的程式碼,其他諸如 typlist 和 lenlist 相關的程式碼都可以刪除。此外 cntlist 代表變數個數,其實這是巧妙的利用 &sqlobs 這個變數去自動計算的。

USING A MACRO LOOP

其實本文真正重點是這個 macro 程式碼。因為只要呼叫這個 macro,並且指定資料檔,電腦就可以自動幫你去抓該資料檔裡面所有的變數。裡面唯一要設定的變數 Dset 其實就是資料檔名稱。

%Macro GetVars(Dset) ;
%Local VarList ;
/* open dataset */
%Let FID = %SysFunc(Open(&Dset)) ;
/* If accessable, process contents of dataset */
%If &FID %Then %Do ;
%Do I=1 %To %SysFunc(ATTRN(&FID,NVARS)) ;
%Let VarList= &VarList %SysFunc(VarName(&FID,&I));
%End ;
/* close dataset when complete */
%Let FID = %SysFunc(Close(&FID)) ;
%End ;
&VarList
%Mend ;


COUNTING THE WORDS IN A LIST

這是另一個用來計算變數總數的 macro,雖然不知道其實用性,不過還是列出來。

%macro wordcount(list);
%* Count the number of words in &LIST;
%local count;
%let count=0;
%do %while(%qscan(&list,&count+1,%str( )) ne %str());
%let count = %eval(&count+1);
%end;
&count
%mend wordcount;


一個簡短範例。執行上述 macro 後再輸入下列程式碼:

%put SASHELP.CLASS has %wordcount(&varlist) variables;

則 log 視窗會出現下面結果:

86
87 %put SASHELP.CLASS has %wordcount(&varlist) variables;
SASHELP.CLASS has 5 variables


嗯~有點無聊,我覺得用 PROC CONTENTS 就可以知道變數總數了。= =

STEPPING THROUGH THE LIST USING THE %SCAN FUNCTION

這個 macro 主要是幫你產生一個新的資料夾,裡面有原來的變數(包含所有格式和長度),但是這個資料夾是空的,也就是說沒有任何觀測值在裡面。至於有什麼用呢?我也不知道,但總是有人會需要用到吧!裡面唯一的 macro 變數 dsn 是用來指定新的資料檔名稱。

%macro emptydsn(dsn);
data &dsn(keep=&varlist);
length
%do i = 1 %to &cntlist;
%scan(&varlist,&i) %if %scan(&typlist,&i)=2 %then $; %scan(&lenlist,&i)
%end;
;
stop;
run;
%mend emptydsn;
%emptydsn(dummyclass);


上述 macro 執行出來的結果,其實就和下面這個普通的 data step 所產生出來的資料檔是一樣的。好處是,使用者就不用慢慢輸入那些煩人的變數名稱、格式和長度了。

data dummyclass(keep=Age Height Name Sex Weight);
length
Age 8
Height 8
Name $ 8
Sex $ 1
Weight 8
;
stop;
run;


AUTHOR CONTACT
Arthur L. Carpenter
California Occidental Consultants
P.O. Box 430
Oceanside, CA 92085-0430
(760) 945-0613
art@caloxy.com
www.caloxy.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; }