SAS初探




圖文無關啦。

最近因為工作關係開始接觸SAS這套計量軟體,在這之前我涉略較深的主要是STATA;後者在學術領域——又尤其是經濟學研究——有非常強大的實作能力,除了對單張表單的分析在語法撰寫的效率上超群,有龐大的各種資料處理乃至於(尤其是)經濟計量的函式之外,也能開啟一種名為MATA的矩陣語言作更深層的數據與數學操作。然而,在商業上面對極龐大的資料庫、多張表單的環境下,STATA會變得很吃力,SAS的實作能力在這方面就取而代之成為更好的選擇。

不過這兩套計量軟體在語法與處理資料的邏輯上都有可觀的差異,對使用者來說需要一些轉換成本。

SAS對我來說比較特別的地方在於它在一種名為Data Step的主要程序下存在的內建迴圈。這個迴圈是loop over rows,配合它讀取表單的方式這個內建的迴圈主宰了Data Step下資料處理的操作邏輯。

拿一個實例來看看吧!
如果我今天面對下面這樣一張表單:


可以很快看得出來這份資料的邏輯,它是一個群組內每個物件有個別次數以及累加結果,且次數經過排序。現在我有一個簡單的任務,就是把構成至少90%群組內次數的成員留下,其餘剃除。換言之,我想留下EBCF,他們是總共構成了96%群組內次數的前四大。可以想像我有很多個不同的群組,我都要做這件事情。

很快的我就發現在SAS的Data Step底下我沒有辦法輕易完成我想要的。當我說輕易,指的就是三兩行了結的意思。如果現在是在STATA環境,我可以很快利用下面這個code來完成任務:

use test.dta, clear
generate _include = cond(cum <= 0.9, 1, 0)
replace _include = 1 if _include == 0 & cum[_n-1] < 0.9
keep if _include == 1

這是一個不經由迴圈就達成的任務。概念就是先進行分組,留下累計次數cum小於0.9的,但是我還要把大於0.9的群組中第一個留下,因為他是使累計次數跨過0.9的那個成員。(這件事情是這個任務的核心。)
當然這裡說不經由迴圈是有點弔詭,因為STATA真正在處理變數(欄位)的時候也有它的一個內建迴圈邏輯,事實上這邊我利用它的迴圈邏輯才能使用[_n-1]這個列標籤。所以精確來說,我應該說我不必經由人工迴圈來處理這個問題,不需要forvalues、while等工具。

然而這件事情來到SAS之後卻成為一場噩夢。(我是SAS新手嘿!)
首先,如果採用上面的邏輯來實作,那麼因為我不知道SAS中是否有對應如同STATA那樣以列標籤呼叫內建迴圈中相對位置的列資料,所以我只好這樣寫:

data test;

set test;

if cum < 0.9 then include = 1;

else include = 0;

run;

proc sort data = test;

by include cum;

run;

proc rank data = test out = test1 ties = low;

var cum;

by include;

ranks rank;

run;

data test1;

set test1;

if include = 1 or rank = 1;

drop include rank;

run;

花惹發。
沒錯,一方面由於SAS的變數排序實在很機車,必須使用Proc程序,而這個程序不能包在Data Step程序下,偏偏Data Step下的By statement需要其變數先被排序……

這只是一個小工作,就搞你這麼多行,就別說整個project涉及多少類似的細節了,一定會哭。(正色)

再來,因為SAS中的do loop不能包Data Step,只能被Data Step包,而一旦把這個迴圈邏輯包進其中,再加上Data Step的內建迴圈之後,就變得很難處理事實上就是難到我不知道怎麼處理啦於是只好怒寫巨集——得到以下替代方案:

%macro test;

%do i = 1 %to 7;

data test_temp;

set test (firstobs = &i obs = &i);

call symput("cum2", cum);

run;

%if &cum2 > 0.9 %then %goto leave;

proc append base = result data = test_temp;

run;

%end;

%leave:

proc append base = result data = test_temp;

run;

%mend test;
%test

因為巨集下的迴圈可以包Data Step,再配合限定一次只處理一行的Data Step,由我人工寫的%DO來取代內建的迴圈,來進行更彈性的邏輯操作。嗯,老實說,看起來是比較FANCY了點,但我內心有個聲音覺得這一切不該這麼複雜。

怎麼可能沒有更簡潔的方式?

而且這裡的counter尾數實際上必須變數化,這邊是因為例子簡單所以我就直接給他1到7,這個7應該要由程式自己去抓列數來判定,因此勢必還會再多加幾行。



好吧。
SAS真的蠻詭異的。
我還不是很能參透它的精神,歡迎高手指教了。0rz.

1 comment(s):

sqiar | 29 November, 2013 22:35

SQIAR (http://www.sqiar.com/solutions/technology/tableau) is a leading global consultancy which provides innovative business intelligence services to small and medium size (SMEs) businesses. Our agile approach provides organizations with breakthrough insights and powerful data visualizations to rapidly analyse multiple aspects of their business in perspectives that matter most.

Post a Comment

回應文章前請注意下列三勿原則:

1)勿拍照;(→會有靈異的照片從你的相機裡跑出來...
2)勿餵食;(→會有飢渴的猛獸從我的網誌裡跑出來...
3)勿告白。(→會有奇怪的東西從站長體內裡跑出來...

謝謝大家的配合。
( > ー <)b