STATA 的排序與群組別操作
群組別操作
事前準備:排序
如果有別的程式經驗的話,群組別的操作常常需要花上不少力氣,但在 STATA 中,只要利用 prefix by
就可以輕鬆完成這項任務。 by <varlist>: <command>
可以讓我們依 <varlist>
的值分組別執行 <command>
。請注意,並非所有指令都能搭配 by 使用,另外,在使用 by 之前,需要先將變數進行 sorting。Sorting 的指令相當簡單,以下簡單地介紹:
sort <varlist>
可以讓樣本點依照<varlist>
進行升冪(numeric)或字母別(alphabetical)的排序。gsort (+/-)<var> (+/-)<var> …, gen(<var>) mfirst
是一個更一般化的 sorting,透過在變數<var>
前方加上正負號可以設定排序方向。optiongen(<var>)
可以生成變數<var>
作為排序順序的 index,而 optionmfirst
可以設定是否將 missing 排在最前方。
Sorting 時需要特別留意 sorting 的過程是否 stable(排序結果是確定 deterministic 的),以及後續的指令是否會因此而受影響。想像一下,你拿交易資料卻只對個人 id 排序,因為每個人可能有數筆交易,因此同個人哪筆交易排前就有不確定性。
群組別操作
讓我們回到 by
吧!by
其實也可以直接和 sort 結合成 bys
。我在 Fig 2-8 展示了一些 by command 的範例以及組別操作後的資料,以下條列詳細說明:
bys <varlist1>: <command>
,先 sort on<varlist1>
,然後對<varlist1>
進行群組操作。bys <varlist1> (<varlist2>): <command>
,先 sort on<varlist1> <varlist2>
,但是只對<varlist1>
進行群組操作。¹- Fig 2-8 的例 1,是在算組平均,這種
by
、egen
的搭配非常好用。 - 例 2 在算組樣本數,2–2 提到的
_N
在這裡就相當實用。另一方面,我們也可以用_n
來產生組內的 index,只要資料的排序符合預期。 - 例 3 試圖找出組內第一次的成績。請注意,我利用
bys ID (test)
來確保組內排序正確後,再利用grade[1]
取出第一次的考試成績。各位不妨猜猜看grade[_N]
會跑出什麼呢? - 例 4 試圖計算每一次考試(變數
test
)前後的成績差異。記得_n
可以回傳當前的 index(第幾筆)嗎?當例 4 的指令套用在每個樣本點時,就會是當前的成績值減去「組內前一個樣本點」的成績值,也就是說,當在某組第 2 個樣本點時,就會計算grade[2]-grade[1]
,而這也是為什麼各組第 1 個樣本點會產生 missing。 - 例 5 想要取出哪次考試的成績最好(和例 3 類似,把最好的成績 sort 到頭或尾後,利用
[1]
或[_N]
取得)。另外,如果擔心 grade 相同而無法確定挑哪筆的話,也可以額外 sort ontest
,保證在 grade 相同下,挑到 test 編號大的那筆。² - 例 6 則是要計算考最好的兩次成績平均,利用了 2–2 計算條件平均的技巧。
善用 by
可以幫忙省下許多功夫,也還有很多應用,像是搭配 egen
底下的 total(<logic exp>)
來計算組內符合條件的個數。如果對 by
產生的結果有疑問的話,可以善用 tab
、 assert
之類的指令檢查,或是用 br
來瀏覽資料。
目前為止,我把 STATA 最基本的操作都帶過了。從存取資料(2–1)、探索資料與生成變數(2–2)、邏輯條件與條件下生成變數(2–2)、利用迴圈簡化操作(2–3)、利用標籤與 wildcard 來輔助閱讀與操作(2–3),最後我們學會群組別的操作(2–4)。希望筆記至此,我能夠說服各位 STATA 真的很好學,而且也是個實用的工具。
[1]: 如果你也是 SQL 的使用者,這可以對應到 window function 的 PARTITION BY
以及 ORDER BY
。
[2]: 這是一個非常經典的問題:找出最大值很容易,但要找出最大值的 id 就要多花點巧思,尤其還要在群組別內執行。