公告

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

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


2010年7月23日 星期五

Stupid Human Tricks with PROC EXPAND®

Link: http://support.sas.com/resources/papers/proceedings10/093-2010.pdf

鮮少有人知道 SAS/ETS 裡面有個叫做 PROC EXPAND 的程序。這個程序主要是用來整理時間序列資料,比方說可以自己定義時間區間後再來做一些次數量表的製作。David L. Cassell 利用這個程序進行了一些平常使用者可以用來做資料處理的功能,並發表了一篇教學文件在 SAS GLOBAL FORUM 2010 上。讓我們來看看如何用 PROC EXPAND 程序來取代一些複雜的資料操作。


TRICK 1: LAGS AND LEADS
在 data step 裡面,我們可用 LAG() 或 LAGn() 函數來求出某個變數的前1~n天的數據,但如果反過來要找某變數的後1~n天數據,雖然有許多方法可以做,但並沒有一個簡便的 call function 可以處理。但是,用 PROC EXPAND 可以輕鬆地製作出這兩種數據出來。範例程式如下:
proc expand data=YourData method=none;
by pt;
convert dosedt = lead1_dt / transformout = (lead 1);
convert dosedt = lead2_dt / transformout = (lead 2);
convert dosedt = lag1_dt / transformout = (lag 1);
convert dosedt = lag2_dt / transformout = (lag 2);
run;

其中,我們打蘇案要轉換的變數是dosedt,而在 PROC EXPAND 裡面,只需要用 convert 指令,把新變數名稱定義好先(lead1_dt, lead2_dt, lag1_dt, lag2_dt),然後在後面斜線後加上一個 transformout= 的選項,然後在等號括弧裡面寫上 lead n 或 lag n 便可以造出後 n 天或指是前 n 天的變數。
TRICK 2: MAX OR MIN OF THE LAST K RECORDS
如果想要知道某一個變數在前n筆或後n筆資料的最大值或最小值,一般的做法是會在PROC MEANS或PROC SUMMARY後加上一個where statement來限制程序要讀取的資料範圍,但在PROC EXPAND裡面,可以直接指定前n筆或後n筆資料,如下所示:
proc expand data=YourData out=YourMax method=none;
by factory;
convert x = max_x / transformin=(movmax 50);
convert x = min_x / transformin=(movmin 50);
run;

同樣利用convert statement,在後面加上transformin選項,並用"movmax n"或"movmin n"來讓SAS去讀前n筆或後n筆資料的最大值最小值。實際上SAS還是會從第一筆資料開始讀,每讀一筆資料就會算一次最大最小值,直到讀進來的資料數量大於movmax和movmin所指定的n值後,SAS才會開始去計算前n筆或後n筆資料的最大值最小值,而所有的結果都會完整呈現在新的資料裡面,我們只需要取最後一筆資料的x_max和x_min數據即為所求。
TRICK 3: AGGREGATING CHUNKS OF RECORDS
我曾經在網路上看過很多人詢問過如何讓資料每跳幾筆資料算一個平均數,或者是每跳幾筆資料取一個數據。許多人用數個PROC程序和data step來完成這兩個動作,但在PROC EXPAND裡面,只需要兩個指令便可完成。

假設資料如下:
data temp1;
input obs vol price;
datalines;
1 2 11
2 2 11
3 2 12
4 3 13
5 3 11
6 3 12
7 4 14
8 4 12
9 4 12
10 5 11
11 5 16
12 5 14
13 6 10
;
run;

總計十三筆資料,兩個變數(vol, price)。如果我們想要每三筆資料算一次vol的總值,以及每三筆資料抓出price的數據,則程式如下:
proc expand data=temp1 out=exp1 factor=(1:3);
convert vol=aggrvol / observed=total;
convert price=new_price / observed=end;
run;


結果如下:
TIME AGGRVOL NEW_PRICE
0 6 12
3 9 12
6 12 12
9 15 14


如何讓成是每三筆資料做一次運算,關鍵完全在PROC EXPAND後面的factor(n:m)選項。以此例來看,factor(1:3)便是要求SAS每三筆資料做一次運算。至於運算的方法,則是定義在convert statement後面的observed=選項。當observed=total時,則會求出每三筆資料的總合,當observed=end時,則會求出每三筆資料的最後一筆數據。實際上,observed=選項有許多參數可以設定,比方要算平均數就只要用observed=average即可。所有可使用的選項可以參考SAS線上手冊。

TRICK 4: THE MOVING AVERAGE
最後一個是算moving average,而這也是PROC EXPAND在處理時間序列資料時最常使用到的計算。假設我們要算每筆資料含前四筆資料的平均,程式如下:
proc expand data=temp1 out=YourOut method=none;
convert number1=mean1 / transformout=(movave 5);
run;

如同前面所述,我們只要在convert statement後面加上一個transformout=的選項,並於括弧內寫上"moveave 5"便可輕鬆算出moving average。

CONTACT INFORMATION
David L. Cassell
Design Pathways
3115 NW Norwood Pl.
Corvallis, OR 97330
DavidLCassell@msn.com
541-754-1304
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; }