STATA 小技巧 (1):迴圈、命名與變數標籤

CW Wayne Yeh
6 min readSep 4, 2021

--

迴圈

STATA 迴圈
Fig 2–6 STATA 迴圈

迴圈(Loops)可能是程式語言中最具代表性的用法之一,好的迴圈不僅簡潔易讀,也可以很方便地進行修改。STATA 的迴圈主要有對數值的 forv ,以及對 item 的 foreach 。兩者的結構基本上一樣,Fig 2-6 各舉了一些簡單的範例與輸出結果。簡單來說,迴圈就是在指定的範圍內,如:1/5,也就是 1 2 3 4 5),依序將值帶入迴圈變數(iterating variable,i)中並且執行指令,如圖中的 display (印出值的簡單指令)。注意,迴圈內的指令是使用「{ }」包起來, 而迴圈內的迴圈變數 i 需要利用` 包起來 (` i’)。相較於 forvforeach 很多時候是用來對一個 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>*) 。 因此,命名時不妨考慮幾點:

  1. 名稱能清楚反應變數內涵(self-explained)。
  2. 概念類似的變數可以加上同樣的字首 prefix 或字尾 suffix,以方便利用 wildcard。
  3. 名稱如果是短句(詞)的話,可以用大寫或底線_來分隔單字,如 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 )。對於連續的數值變數,我們需要先將其轉變為整數的數值變數(即間斷化),再進行類別化。我們可以用 genreplace 完成,或是參考 recode 以及 egen 底下的函數 cut()

Fig 2–7 類別標籤

Fig 2-7 利用簡單的人造資料來展示 label 的實例與結果。有幾個值得注意的地方:

  1. female 的 missing 在 label 時是怎麼被處理的?因為未定義,所以也不會顯示在 label list 中。
  2. 由 label list 可以得知,我們產生了兩個類別標籤:分別由 encode 產生 dep2 以及由 label define 產生 map_gender
  3. 右下角的 tabstat是以類別標籤(male/female)顯示分組的,比起單純顯示 0、1 提供更多資訊,也更好讀懂。
  4. encode 是針對字串變數的類別化,以字串本身為類別標籤,新產生的數值變數 dep2 同時也是值與類別標籤 mapping 的名稱。由於 dep2 的整數值(代碼)不是我們手動指定的,有需要的話,正好可以利用 label list dep2 查詢。

[1]: 一些迴圈 coding 上的習慣:(1) 迴圈內的指令縮排;(2) 有意義的變數命名(self-explained,如 Fig 2-6 中的 var 代表的是 loop over 變數);(3) 下大括號} 建議獨自一行。

--

--

CW Wayne Yeh

資料分析/閱讀筆記/生活雜感。我是葉政維,台大經研畢,目前是樹鋸分析師🪚,正在職場站穩腳步,也在探索什麼是好的生活。