STATA 小技巧 (1):迴圈、命名與變數標籤
迴圈
迴圈(Loops)可能是程式語言中最具代表性的用法之一,好的迴圈不僅簡潔易讀,也可以很方便地進行修改。STATA 的迴圈主要有對數值的 forv
,以及對 item 的 foreach
。兩者的結構基本上一樣,Fig 2-6 各舉了一些簡單的範例與輸出結果。簡單來說,迴圈就是在指定的範圍內,如:1/5
,也就是 1 2 3 4 5),依序將值帶入迴圈變數(iterating variable,i
)中並且執行指令,如圖中的 display
(印出值的簡單指令)。注意,迴圈內的指令是使用「{ }
」包起來, 而迴圈內的迴圈變數 i
需要利用`
、’
包起來 (` i’
)。相較於 forv
, foreach
很多時候是用來對一個 list 進行迴圈,例如 Fig 2-6對一堆變數或 <varlist>
(price length weight
)的標準化。我們其實也可以在迴圈內再包迴圈(nested loop),但建議把每一層的迴圈變數與 loop over 的對象給註記清楚。
好的迴圈可以讓 coding 更簡潔,但若缺乏適當的排版、命名與 comment 的話,反而容易造成許多困惑。¹最後補充一下,STATA 也可以寫其他程式語言常見的 while 迴圈以及 if-else 條件式,但多數時候 forv、foreach 就很夠用了。
變數命名
變數命名是一件非常簡單,卻值得花心思的事。好的命名邏輯可以省下許多查詢甚至 coding 的時間,尤其是我們可以利用「wildcard」來一口氣呼叫一堆變數(varlist)。修改變數名以及利用 wildcard 的方法列舉如下:
rename <var1> <var2>
,可以將 var1 改名為 var2。rename (<varlist1>) (<varlist2>)
,是進階版用法,可以一口氣更改許多變數的名稱(varlist1 -> varlist2)。<var>*
,是一個varlist
,代表所有以 var 開頭的變數。<v1>-<v10>
,是一個varlist
,代表 Variable Block(主界面右側)v1到 v10 之間的變數。建議使用前利用order
將類似的變數排序在一起。
例 3 的 wildcard 有很多方便的運用,像是 sum <var>*
、 egen <var1> = rowmean(<var2>*)
。 因此,命名時不妨考慮幾點:
- 名稱能清楚反應變數內涵(self-explained)。
- 概念類似的變數可以加上同樣的字首 prefix 或字尾 suffix,以方便利用 wildcard。
- 名稱如果是短句(詞)的話,可以用大寫或底線
_
來分隔單字,如 AvgScore、Mean_GPA,以增加可讀性。
變數標籤與類別標籤
這段會談到變數標籤與變數的類別標籤,這些東西也許不直接和清理與分析資料有關,但可以讓閱讀資料或結果呈現更明確好懂。標籤的概念是這樣的:首先, 每個變數都可以有標籤,給予變數更多的描述,這可以在主介面右側的 Variable Block 查看;此外,我們也可以給變數的「值」或是「類別」標籤,這通常用在類別變數上,因此我且稱為類別標籤,據此可以定義一個值與標籤的 mapping。事實上,這樣的 mapping 還挺常見的,像是問卷調查中,整數 1 到 5 也許會對應到某個選項,此外國家、城市等變數也很常使用整數或英文代碼來表示(通常要另外找譯碼簿查看具體內涵)。定義出值與類別標籤的對應關係,並套用在變數身上就可以完成類別化(在 data browser 中呈藍字)。類別化後的變數在 data browser 以及許多指令的輸出結果中,將以「類別標籤」呈現,但其在運算上仍然是數值喔!下列針對相關指令做些整理:
label var <var1> <string>
,給<var1>
標籤,標籤內容為字串<string>
。label define <map_name> <value1> <label1> <value2> <label2> …
,定義「值與類別標籤的 mapping」,比如說<value1>
就被對應到標籤<label 1>
。其中的<map_name>
, 是這個 mapping 的名稱。label value <var> <map_name>
,將定義的「值與類別標籤的 mapping」套用在<var>
上。label dir
,列出所有值與類別標籤的 mapping,<map_name>
,的名稱。label list <map_name>
,列出<map_name>
值與類別標籤的對照情形。若沒有給<map_name>
,則會列出所有<map_name>
的對照情形。label drop <map name>
,丟掉定義的 mapping。
這邊也許寫得有些拗口,但實際試試看就會知道怎麼回事了!請注意,「值與類別標籤」的值只適用於「整數」與「遺失值」。若想適用於字串變數,可以直接利用 2–2 提到的 encode
完成類別化,同時也給予類別標籤(see Fig 2–7 )。對於連續的數值變數,我們需要先將其轉變為整數的數值變數(即間斷化),再進行類別化。我們可以用 gen
、 replace
完成,或是參考 recode
以及 egen 底下的函數 cut()
。
Fig 2-7 利用簡單的人造資料來展示 label 的實例與結果。有幾個值得注意的地方:
- female 的 missing 在 label 時是怎麼被處理的?因為未定義,所以也不會顯示在
label list
中。 - 由 label list 可以得知,我們產生了兩個類別標籤:分別由
encode
產生dep2
以及由label define
產生map_gender
。 - 右下角的
tabstat
是以類別標籤(male/female)顯示分組的,比起單純顯示 0、1 提供更多資訊,也更好讀懂。 encode
是針對字串變數的類別化,以字串本身為類別標籤,新產生的數值變數dep2
同時也是值與類別標籤 mapping 的名稱。由於dep2
的整數值(代碼)不是我們手動指定的,有需要的話,正好可以利用label list dep2
查詢。
[1]: 一些迴圈 coding 上的習慣:(1) 迴圈內的指令縮排;(2) 有意義的變數命名(self-explained,如 Fig 2-6 中的 var
代表的是 loop over 變數);(3) 下大括號}
建議獨自一行。