1. 問題背景
我們經(jīng)常使用 generate
(后文簡稱 gen
) 命令提供的 group()
函數(shù)對某個變量進(jìn)行分組,產(chǎn)生分組變量 gg,繼而基于 gg 變量進(jìn)行后續(xù)的分組回歸分析。
例如,在公司金融中,常用如下代碼產(chǎn)生融資約束的分組指標(biāo):
*-用公司規(guī)模衡量融資約束,分成三組
. bysort code: egen av_size = mean(size)
. sort av_size
. gen gg = group(3)
. gen FC = (gg==1) //小規(guī)模公司定義為 FC 組
. replace FC=. if gg==2 //丟棄中間組
. reg y x if FC==0
. est store m_FC
. reg y x if FC==1
. est store m_NFC
. esttab m_FC m_NFC
恐怖的事情就要發(fā)生了!
后續(xù)做分組回歸時,你會發(fā)現(xiàn):執(zhí)行相同的代碼,但兩次得到的結(jié)果居然不同!
原因何在??
一個小例子
我先虛構(gòu)一份數(shù)據(jù),讓各位了解 group()
函數(shù)的工作原理,搞明白這件事情后,上面的問題就迎刃而解了。
這份數(shù)據(jù)很簡單,只有 4 行觀察值。我們對變量 x 排序后再執(zhí)行 gen g = group(2)
命令,以便將樣本分成兩組。為了測試分組結(jié)果是否唯一\穩(wěn)定,我進(jìn)一步使用 tatstat
命令計算了兩組的均值。
clear
input x y
3 13
2 10
1 1
2 8
end
sort x \\ 由小到大排序
gen g = group(2) \\ 等分兩組
tabstat x y, by(g) f(%3.1f)
sort g x y
list, sepby(g) noobs
第一輪執(zhí)行的結(jié)果如下:
. tabstat x y, by(g) f(%3.1f)
Summary statistics: mean
by categories of: g
g | x y
---------+--------------------
1 | 1.5 5.5
2 | 2.5 10.5
---------+--------------------
Total | 2.0 8.0
------------------------------
. sort g x y
. list, sepby(g) noobs
+------------------+
| id x y g |
|------------------|
| 301 1 1 1 |
| 201 2 10 1 |
|------------------|
| 401 2 8 2 |
| 101 3 13 2 |
+------------------+
可以看到,g 取值為 1 和 2 時兩組的均值分別為 5.5 和 10.5,差為 5。
我又連續(xù)執(zhí)行了兩遍上述代碼,結(jié)果都沒有任何變化,似乎表明上述分組結(jié)果是穩(wěn)定的。
然而,當(dāng)我執(zhí)行第四次時,得到了如下結(jié)果:
. tabstat x y, by(g) f(%3.1f)
Summary statistics: mean
by categories of: g
g | x y
---------+--------------------
1 | 1.5 4.5
2 | 2.5 11.5
---------+--------------------
Total | 2.0 8.0
------------------------------
. sort g x y
. list, sepby(g) noobs
+------------------+
| id x y g |
|------------------|
| 301 1 1 1 |
| 401 2 8 1 |
|------------------|
| 201 2 10 2 |
| 101 3 13 2 |
+------------------+
此時,兩組的均值分比為 4.5 和 11.5,差為 7。
留給諸位 2 分鐘,對比一下兩組結(jié)果,然后想想為什么會出現(xiàn)結(jié)果不一致的現(xiàn)象?
2. 揭秘:group() 函數(shù)的工作原理
細(xì)心的讀者已經(jīng)發(fā)現(xiàn)了結(jié)果發(fā)生漂移的原因:id=201 和 id=401 的兩個觀察值的 x 變量具有相同的取值,x=2。然而,他們的 y 變量取值卻不同。當(dāng)我們執(zhí)行 sort x
命令對 x 變量進(jìn)行排序時,id=201 會隨機(jī)地被排在第二位或第三位。雖然這對 x 的排序結(jié)果沒有任何影響,但 y 變量中各個觀察值出現(xiàn)的順序卻存在差異。
讓我們更細(xì)致地解讀一下 group()
函數(shù)的工作原理。
上面的分析中我們用到了如下兩條核心命令:
sort x \\ 由小到大排序
gen g = group(2) \\ 等分兩組
也就是說,gen
命令下的 group()
函數(shù)按如下兩個步驟工作:
顯然,某個觀察值被分到第一組還是第二組,并不是由 group()
函數(shù)決定的,而是它之前的 sort
命令決定的。
如果諸位此時輸入 help sort
命令查看其幫助文件,就會發(fā)現(xiàn)他有一個唯一的選項——stable
(我用了十幾年的 Stata,今天才發(fā)現(xiàn)原來 sort
命令還有選項!)
執(zhí)行 sort x
時,如果不加入 stable
選項,那么就會隨機(jī)出現(xiàn)如下兩種情形中的一種:
CaseA Case_B
----------- -----------
x y | x y
1 1 | 1 1
2 10 | 2 8
2 8 | 2 10
3 13 | 3 13
----------- -----------
這就是我們此前看到的兩種情形。
加入 stable
選項后,每次執(zhí)行 sort x
后得到的結(jié)果都是相同的,即 Case A (它維持了原始數(shù)據(jù)中 y 變量各個觀察值的相對順序)。
其實,上述表述并不嚴(yán)謹(jǐn),sort x, stable
其實上只是幫助我們維持在執(zhí)行 sort
命令前一刻內(nèi)存中數(shù)據(jù)的相對狀態(tài)。然而,如果在 sort
命令之前執(zhí)行過會打亂樣本中各個觀察值相對位置的命令,即使在 sort
命令中附加 stable
選項,仍然無法保證排序結(jié)果的穩(wěn)定性,也就無法保證 group()
函數(shù)分組的唯一性。
有興趣的讀者可以執(zhí)行如下命令測試一下。
clear
input x y
3 13
2 10
1 1
2 8
end
rsort // 外部命令,隨機(jī)排序,使用 ssc install rsort 下載
sort x, stable
gen g = group(2)
tabstat x y, by(g) f(%3.1f)
sort g x y
list, sepby(g) noobs
當(dāng)然,實證分析中很少有人會使用上例中的 rsort
命令主動打亂觀察值順序 (一個典型的特例是在 PSM 分析中使用最近鄰匹配時,需要預(yù)先打亂觀察值順序)。更一般的情形是如下命令 (你在毫不自知的情況下打亂了樣本順序):
bysort industry year: egen av_x = mean(x)
sort av_x, stable
gen g_x = group(10)
……
2.1 同類問題
其實,當(dāng)分組變量本身存在較多重復(fù)值時,egen
命令提供的 pctile()
函數(shù),以及 quantiles
命令都存在上述問題,因為背后的道理都是相同的。
下面是針對 quantiles
命令的測試代碼,也會存在結(jié)果不穩(wěn)定的問題。
clear
input x y
3 13
2 10
1 1
2 8
end
quantiles x, gen(gg) n(2)
tabstat x y, by(g) f(%3.1f)
sort g x y
list, sepby(g) noobs
2.2 小結(jié)
如果用于分組變量存在諸多重復(fù)值,就非常容易導(dǎo)致上述問題;
上例中,x 變量只有一個重復(fù)值 (數(shù)值 2 重復(fù)出現(xiàn)了兩次),極端狀況是 x 的所有觀察值都集中于某一個取值,那么此時使用 group()
函數(shù)進(jìn)行分組,就相當(dāng)于隨機(jī)分組,可能每次的結(jié)果都會不同。有興趣的讀者可以反復(fù)運(yùn)行一下如下代碼:
clear
input x y
2 13
2 10
2 1
1 8
2 12
end
sort x
gen g = group(2)
tabstat x y, by(g) f(%3.1f)
sort g x y
list, sepby(g) noobs
3. 解決方法
狹義而言,這個問題無解。
實證分析中的建議就是:
如果分組變量本身有很多重復(fù)值,那么使用 group()
函數(shù)進(jìn)行分組是非常糟糕的選擇。Note:類別變量 (如教育水平)、計數(shù)變量 (如教育年限, 專利個數(shù)等) 都會存在很多重復(fù)值。此時最好是人為地事先設(shè)定分組界點,比如教育年限低于 12 年定義為「Low」,高于 12 年定義為「High」。
如果分組變量是連續(xù)變量,如公司規(guī)模 (ln(總資產(chǎn)))、負(fù)債率等,出現(xiàn)重復(fù)值的概率很小,此時可以使用 generate
命令下的 group()
函數(shù),但更好的辦法是使用 quantiles
命令,基于分位數(shù)進(jìn)行分組。但需要注意的是,quantiles
命令在樣本數(shù)太小或分組個數(shù)太小時都不適用。
更好的辦法是基于分位數(shù)分組 (但分組結(jié)果不再保證每組的樣本數(shù)相當(dāng)近似相等),此時可以開始用 xtile
,或 egen
命令下的 pctile()
函數(shù)。
使用 xtile 命令
由于 xtile
基于分位數(shù)分組,使用 sum x, detail
命令可知,x 變量的中位數(shù)是 2,因此,xitle gg=x, n(2)
會以 x=2 為分界點 (cutpoint) 將樣本分成兩組,用新生成的變量 gg 加以標(biāo)記。此時,分組結(jié)果并不均等,這在小樣本中是非常普遍的事情,對于大樣本而言,組間樣本數(shù)的差異基本上可以忽略。
對于前文提到的類別變量,或續(xù)別變量,我們可以使用 xtile
命令的 cutpoints()
選項人為設(shè)定分界點,此處不再贅述。也可以使用 egen
命令中的 cut()
函數(shù)實現(xiàn)相似的目的,缺陷是此時無法配合使用 bysort
前綴。
clear
input id x y
101 3 13
201 2 10
301 1 1
401 2 8
end
xtile gg = x, n(2) // New
tabstat x y, by(g) f(%3.1f)
sort g x y
list, sepby(g) noobs
結(jié)果如下:
. tabstat x y, by(g) f(%3.1f)
Summary statistics: mean
by categories of: gg (2 quantiles of x)
gg | x y
---------+--------------------
1 | 1.7 6.3
2 | 3.0 13.0
---------+--------------------
Total | 2.0 8.0
------------------------------
. sort g x y
. list, sepby(g) noobs
+-------------------+
| id x y gg |
|-------------------|
| 301 1 1 1 |
| 401 2 8 1 |
| 201 2 10 1 |
|-------------------|
| 101 3 13 2 |
+-------------------+