公告

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

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


2007年3月19日 星期一

A Macro for Reading Multiple Text Files

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

以前曾經遇過這樣的情況,那就是從某個大型資料庫下載檔案,但都不是 SAS 格式。每個檔案裡面有些變數數量或格式還不盡相同。在沒有比較好的方法可一次將所有資料讀進 SAS 時,就只能一個一個導入,然後再另外想辦法合併。Debbie Miller 在 2004 年的 SUGI 29 上發表了一個可以一次讀取多重文字檔的 macro,我想應該就可以解決當年我遇到的問題。

假設現在有兩個外部資料檔,如下所示:



有上圖可知,兩個資料檔的變數並不完全相同。可能另外還有數百個資料檔都類似這樣的模式,所以必須想個方法來一次導入所有的檔案。

首先,先把所有外部資料檔都放在同一個檔案夾裡面(例如:d:\requests\miller\testfiles),然後利用 filename 指令下的 pipe 功能把所有資料檔名稱都記錄起來存入一個文件 indata 裡面。

filename indata pipe 'dir d:\requests\miller\testfiles /b';

接著,執行下列程式,把 indata 裡面的東西存入一個資料集 file_list 裡面,並把資料檔總數變數 num_files 用 symput 指令設定成一個 macro 變數。如下所示:

data file_list; length fname $20; infile indata truncover; /* infile statement for file names */ input fname $20.; /* read the file names from the directory */ call symput ('num_files',_n_); /* store the record number in a macro variable */ run;

然後,執行下面這個 macro 來一次完成 (1) 讀取變數名稱、(2) 合併所有資料。

%macro fileread; %do j=1 %to data _null_; set file_list; if _n_=call symput ('filein',fname); run; data var_names; length x1-x17 $12; infile "d:\requests\miller\testfiles\&filein" obs=1 missover; input (x1-x17) ($) ; run; %macro varnames; %do i=1 %to 17; %global v&i; data _null_; set var_names; call symput("v&i",trim(x&i)); run; %end; %mend varnames; %varnames; /* read the data lines into a temporary file */ data temp; infile "d:\requests\miller\testfiles\ firstobs=2 missover; input (&v1 &v2 &v3 &v4 &v5 &v6 &v7 &v8 &v9 &v10 &v11 &v12 &v13 &v14 &v15 &v16 &v17) ($); run; /* assemble the individual files */ %if &j=1 %then %do; data data_all; set temp; run; %end; %else %do; data data_all; set data_all temp; run; %end; %end; /* end of do-loop with index j */ %mend fileread;

上述的 macro 比較特別的地方是裡面又用了另一個 macro 來執行取得變數名稱的功能。等於說是一個大的 macro 包住另一個小的 macro,這樣執行大的 macro 時,小的 macro 會一併被執行。

最後,只要執行這個沒有參數的 macro 即可完成所有動作。

%fileread;

特別注意一點,這個 macro 有一個地方,我認為是很大的敗筆!!那就是他已經限定了所有變數總數是 17 個。因此整個 macro 就被限定了。我私下改了一下這個 macro,讓使用者可以自由指定全部的變數總數和檔案路徑。

%macro fileread (direction,varnum); %let path=&direction; %do j=1 %to &varnum; data _null_; set file_list; if _n_=call symput ('filein',fname); run; data var_names; length x1-x&varnum $12; infile "&path\&filein" obs=1 missover; input (x1-x&varnum) ($) ; run; %macro varnames; %do i=1 %to &varnum; %global v&i; data _null_; set var_names; call symput("v&i",trim(x&i)); run; %end; %mend varnames; %varnames; /* read the data lines into a temporary file */ data temp; infile "&path\&filein" firstobs=2 missover; input (&v1-&v&varnum) ($); run; /* assemble the individual files */ %if &j=1 %then %do; data data_all; set temp; run; %end; %else %do; data data_all; set data_all temp; run; %end; %end; /* end of do-loop with index j */ %mend fileread;

新增兩個參數,direction 是拿來設定存放資料檔的路徑,varnum 是指定變數總數。假設全部資料檔的變數總數(扣掉重複的)是35,則只要執行下列程式碼即可:

%fileread(direction=d:\requests\miller\testfiles\, varnum=35);


CONTACT INFORMATION
Your comments and questions are valued and encouraged. Contact the author at:
Debbie Miller
National Park Service, Air Resources Division
12795 W. Alameda Parkway
Lakewood, CO 80129
Work Phone: (303) 987-6947
Fax: (303) 969-2822
Email: debbie_c_miller@nps.gov
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; }