樓主的問題其實都很好,尤其對於新手來說,都算是重要但不易弄清的觀念。因此小弟決定花些時間仔細解釋,回饋一下論壇,文長請耐心,如有錯誤也請諸位前輩指教。
Q1. 哪些statement要求数据是要排序的?比如:merge by含有by的是需要sort、class却不需要sort。
小弟不敢說自己有資格做窮舉總結,但是可以提供一些概念,幫助理解 class 跟 by 的區別與使用時機。
(1) 先講 class。class 是一種 nominal variable(名目變量)的概念,排序是無意義的。例如三原色的「R,G,B」就是一種名目變數,純粹代表類別的名稱。雖然按照字母順序可以排出 B<G<R,但這個排序並沒有實際意義。
在我個人經驗當中,class 通常只被用在 proc freq, proc means, proc univariate 這種產生 summary statistics 與統計報表的程序當中。你可以將 class variable 簡單想像成一些「桶子」。今天假設一個 proc 只需要先將每一筆讀入的資料,分別丟進對應的桶子裡頭,最後再對每個桶子裡的資料做整體性的統計,並且資料的順序及桶子的順序並不重要,那就可以只使用 class 關鍵字,而不是要求預先排序的 by。
(2) 再講 by。當資料的順序是必要之時,便一定要將資料先 sort 好,然後使用 by 關鍵字。問題是,什麼時候排序是必要的?答案也很簡單,只要 SAS proc 或 data step statements 內建的 algorithm(演算法)要求資料必須被排序,那麼 sort 便是必要的。例如 merge,例如 first. 與 last.,例如 proc gplot 的 by statement。原則上,只要涉及資料集的比較、合併、以及(有順序的)分群處理,用的都是 by。事實上,很多時候 SAS 根本就不提供 class statement,by 的使用時機佔了絕大多數。
值得一提的是,proc sql 之所以不需要事先排序,是因為 sql 語言內建的演算法,在執行 query 之前都會自動將資料排序,而不是因為 proc sql 處理資料不依賴排序。
Q2. sortedby=XX 和 notsorted 这两个options是怎么使用?
sortedby=
這個選項表示 data set 雖然未經 proc sort 或 proc sql order by 等排序程序處理,但天生就是已排序的資料。指定這個選項,可以讓某些程序直接跳過排序步驟,增加執行效率,例如 Q1. 後面所提到的 proc sql。
notsorted
這個關鍵字,很容易被依字面意思,被錯誤的理解為「完全未經排序的散亂資料」。但是,它的意思其實是指「by variable 已經被分區集中形成一個個的資料區塊,只是資料區塊本身並未被排序」。
例如下面資料集的 ID 變量,就是 "notsorted" 的情形。ID 的資料已按字母分區集中,但並不按照 'A', 'B', 'C' 的順序。
ID x
-----
A 1
A 2
C 3
C 4
C 5
B 6
B 7
同樣的,指定這個選項,可以增加某些程序的執行效率。
Q3. sort by variable和加index有什么区别吗?
sort 會改變 obs (資料列) 的順序,建立 index 則不會。
可以把 index 想成是 SAS 偷偷對某個變數做了排序,但又不想變更資料集本身,所以只好在 dataset 上偷偷附加了一個隱藏欄位,用來記錄排序后的第 1,2,...n 筆資料,分別對應到原來的第幾筆資料這樣。
index 的好處是,第一不用移動資料(尤其針對 big data),第二就算資料集經過多次增刪(但不得重新排序),index 依然存在且可用。並且就 DBMS(資料庫管理系統)的角度,index 是維持資料一致性、避免資料重複的必要工具,當然這裡就不多深入。壞處則是,在發生資料增刪之時,index 的維護也會拖慢一些執行效率。另外,已設定index的資料,無法進行原地排序。程序設計者必須自行斟酌 index 的使用時機。更詳細的說明,請見SAS 官方說明文件。
Q4. SAS程序如何运行?data step有的有description portion有的会全部读入memory? 所以会使用view?
大哉問啊,並且問題似乎不是很明確。不過一些一般性的觀念是這樣的:
(1)跟其他統計語言(例如R)比起來,SAS 運行邏輯的最大特色,就是把資料當成打孔紙帶來處理。基本上,SAS 每次只會將一個 row 讀進記憶體,然後逐列處理、逐列輸出。(當然,像 proc sql 這種外來語模組,以及 proc ds2 這種最近才出現的高效能模組,就未必如此。但一般來說,這樣理解大致是沒有錯的。)
這種做法有好有壞:好處在於記憶體用量不大,且不受 data set 的大小影響,故非常適合處理 big data。但壞處也很明顯,就是 I/O 次數多、對小型資料集的處理效能低下、以及各種基於「欄」的操作非常困難(例如「欄比較」,R語言是一句話搞定,SAS 卻要搞半天,上 stack overflow 找答案就可以知道,這裡也不多做深入)。
(2)sql table (就是 SAS data set) 的 descriptive information 我不確定 SAS 怎麼處理,但是這些資訊,佔用記憶體不多,過程中又一定會被更新,整個讀進記憶體應該是沒有問題的。
(3)所謂的 view,一般應該是指由 proc sql 的 create view 指令所創造出來的 view。view 是什麼東西?就是只記錄 query (資料查詢的規則),而不實際產生一個新的 data set。與之相對的是 create table,它會實際產生一個 data set,而不記錄這些資料是怎麼來的。每次你打開 view 的時候,SAS 都必須對原始資料重新執行一次 sql query,才能給出你想要的資料。因此,跟 create table 比起來,create view 其實就是一種以運算時間為代價,換取節省儲存空間的做法。個人認為,跟記憶體的使用倒是沒什麼關係。
Q5. data step里面的keep=xx, drop=xx和set statement里面的keep=xx, drop=xx有什么区别吗? keep statement drop statement和keep=xx, drop=xx有什么区别吗?
當然有,這也是一個很好的問題。當你需要把一個資料集,根據條件,輸出成許多個資料集的時候,了解這個區別就很重要(也很便利,能大幅精簡代碼量)。簡言之:
- statement keep/drop xx yy; 會影響「每一個」「輸出」資料集。注意:它不會影響輸入資料集,所以被 drop 掉的變數,在 data step 裡頭仍然能被使用。
- dataset option (keep/drop=xx yy) 則只會針對性的影響該輸出資料集或輸入資料集。
當上面兩者 keep 跟 drop 的作用對象衝突之時,dataset option 的順位高於 statement。利用這個特性,我們可以同時對欲輸出的變量,先用 statement 做整體的設定,再用 dataset option 做個別調整。如下面範例程序碼所示:
可以清楚看到,data step 讀進了變數 ID 與 x1-x6,雖然 ID 不在 keep statement 之列,但仍然能夠在 data step 裡面被使用。並且在輸出時,dsout1 保留了 x1-x4, x5 跟 x6 被 drop 掉;dsout2 則保留了 x1 x5 x6, x2-x4 被 drop 掉。故 data set option 的效力確實高於 statement。
另外,經測試,在 statement (或data set option)裡頭, keep 跟 drop 的作用對象衝突之時,drop 的順位較高(在keep statement 上方加入一句 drop=x1; 即可驗證)。但應該盡量避免這種寫法。
最後要注意,keep statement 並非隨處可用,例如 proc sort 就無法使用 keep x; 的 statement。而 data set option (keep=) 是到處都能用的。