基准回归:OLS、固定效应与聚类标准误
从最朴素的 cross-section OLS 出发,一步步搭建面板数据上的双向固定效应(two-way FE)模型,理解 clustered standard errors 为什么是实证论文的"默认配置",并学会用 reghdfe + esttab 把结果干净地导出为三线表。
reghdfe、ftools、estout;基础 regress、xtreg、cluster 选项)。01 为什么需要固定效应:从 OLS 到面板
实证研究的第一步永远是问:"我手上的变异(variation)到底来自哪里?"如果你只有一期横截面数据,regress y x 就是全部武器。但当你拿到了面板数据(panel data)——同一个体 $i$ 在多期 $t$ 被重复观测——你立刻拥有了两样新东西:个体间变异(between variation)和个体内变异(within variation)。OLS 把这两种变异混在一起用,于是只要个体存在不随时间变化、但又与解释变量相关的不可观测特征(unobserved time-invariant heterogeneity),估计就会产生遗漏变量偏误(omitted variable bias)。
固定效应模型(fixed effects, FE)的核心思想极其朴素:与其去"控制"那些看不见的特质,不如直接给每个个体一个"专属截距" $\alpha_i$。这样一来,回归识别用的全部是同一个体在不同时点上的纵向变化(within transformation),任何不随时间变化的混淆因素(例如企业所在地的文化、个体的性别、创始人的能力)都被这个 $\alpha_i$ 一次性吸收掉了。进一步地,如果你还担心所有个体在同一时点受到共同冲击(year shock、宏观周期、政策大年),你再加一组时间固定效应 $\gamma_t$,这就是双向固定效应(two-way fixed effects, TWFE)。
需要立刻提醒的是:FE 只能吃掉不随时间变化的混淆变量。如果遗漏变量是时变的(time-varying confounder),FE 毫无办法——这正是后面 IV、DID、RDD 这些"识别策略"要登场的原因。
02 形式化:双向固定效应模型
本页最重要的一个回归方程,几乎所有现代面板实证论文的"主回归表"都是围绕它搭建的:
其中:$i$ 为个体(firm / county / state / person),$t$ 为年份;$\alpha_i$ 是个体固定效应(吸收一切个体层面不随时间变化的特征);$\gamma_t$ 是时间固定效应(吸收所有个体共同面临的年份冲击);$\mathbf{Z}_{it}$ 是一组时变控制变量;我们真正关心的系数是 $\beta_1$。
Stata 中实现这一模型,命令经历了三代:
xtreg y x i.year, fe:传统 FE 命令,但吸收大量虚拟变量时极慢,且标准误处理不够灵活;areg y x i.year, absorb(id):用 LSDV(least squares dummy variable)的思路一次性吸收 $\alpha_i$,比 xtreg 快;reghdfe y x, absorb(id year) vce(cluster id):目前论文中事实标准。它通过 Frisch–Waugh–Lovell 定理(FWL)把高维固定效应"扫出去",再对残差做 OLS,速度快、内存省,并且可以任意叠加多组高维 FE(例如 industry × year、firm × province)。
Frisch–Waugh–Lovell(FWL)定理:虚拟变量、交乘项与固定效应的统一视角
reghdfe 能"无形地"吸收上万个虚拟变量,背后的数学基石是 Frisch–Waugh–Lovell 定理(Frisch & Waugh 1933;Lovell 1963;Angrist & Pischke 2009 给出了现代因果解释)。定理说:在多元回归 $y = x\beta + D\gamma + \varepsilon$ 中($D$ 是一组虚拟变量,如个体 FE 或时间 FE),系数 $\hat{\beta}$ 等价于"先用 $D$ 把 $y$ 和 $x$ 分别投影取残差,再用 $x$ 的残差对 $y$ 的残差做一元 OLS":
其中 $M_D=I-D(D'D)^{-1}D'$ 是把 $D$ 张成空间投影出去的残差生成矩阵。这一视角把三件看似不同的事统一了起来:(1) 虚拟变量回归——加一组个体虚拟变量,本质上就是先把 $y$ 和 $x$ 都按组内均值"去掉"(within transformation);(2) 交乘项 / 调节效应——交互项系数同样可以理解为"把主效应残差化之后再估计";(3) 固定效应——$\alpha_i$、$\gamma_t$ 不过是更庞大的虚拟变量组,reghdfe 反复做的去均值就是 $M_D$ 投影。三者不是三套技巧,而是同一个 FWL 偏除定理在不同维度上的应用。
当你写 reghdfe y x, absorb(id year) 时,Stata 并没有真的生成 id×year 上万列虚拟变量再做 OLS,而是内部用迭代去均值(FWL 投影)把它们扫出去,只对剩下的 $\tilde{x}$、$\tilde{y}$ 做 OLS。这既是 reghdfe 又快又省内存的原因,也是理解"为什么加了固定效应后系数只用组内变异识别"的关键。
当你要在 3000 家企业 × 20 年的数据里同时吸收 firm FE、industry × year FE、province FE 时,构造 dummy variable 矩阵会产生数万个虚拟变量,直接 OLS 会慢到无法接受。reghdfe 用内部的 Mata 算法反复"去均值"(within transformation),不需要真正生成这些哑变量,所以再复杂的高维 FE 也能在秒级跑完。
03 聚类标准误的直觉与公式
教科书 OLS 假设误差项同方差、且观测之间相互独立。但在面板数据里,这两个假设几乎一定被违反:同一个体 $i$ 在 $t$ 期和 $t+1$ 期的扰动项高度相关(serial correlation),同一年份不同地区的扰动也相关(cross-sectional dependence)。如果继续用普通 OLS 标准误,你会把标准误算得过小,t 值虚高,从而把不显著的结果"洗"成显著——这是顶刊审稿人最容易一眼抓出来的硬伤。
Cluster-robust standard errors(Liang–Zeger 1986;Arellano 1987;后来 Cameron–Gelbach–Miller 2011 系统化为 multi-way clustering)的思想是:在同一 cluster 内部,误差可以任意相关;只要求不同 cluster 之间相互独立。对系数 $\hat{\beta}$ 的协方差矩阵,cluster-robust 估计为:
其中 $g$ 是 cluster index(例如 firm、county、state),$G$ 是 cluster 数量,$\hat{u}_g$ 是该 cluster 内所有观测的残差向量。注意最后那两个自由度修正因子——cluster 数量 $G$ 太少时(经验阈值 < 40–50),cluster robust 标准误会严重偏小,必须用 wild cluster bootstrap 做推断。
经验法则:聚类到"政策/处理"发生的层面。如果政策在州级层面实施,就 cluster 到 state;如果处理变量在企业层面变化,cluster 到 firm。Cameron & Miller (2015) 强烈建议同时报告多向聚类(例如同时 cluster firm 和 year,Stata 里写 vce(cluster firm year),需要 reghdfe 较新版本)。但 cluster 层级越多,每一层的 cluster 数量越少,渐近理论越不稳——cluster 到 year 时通常只有 20–30 个年份,必须配合 wild bootstrap。
04 FE / RE 选择:F 检验与 Hausman 检验
在写主回归之前,你需要决定用固定效应还是随机效应(random effects, RE)。两者的关键差异在于对 $\alpha_i$ 的假设:FE 允许 $\alpha_i$ 与 $x_{it}$ 任意相关;RE 则强制 $Cov(\alpha_i, x_{it})=0$。RE 更有效率(更省方差),但这个零相关假设极其强。
xtreg y x, fe 的输出末尾会给出 F test that all u_i=0。如果拒绝原假设,说明个体效应 $\alpha_i$ 联合显著存在,必须用 FE,不能用 pooled OLS。xtreg y x, fe 后 estimates store fe;xtreg y x, re 后 estimates store re;再 hausman fe re。显著拒绝原假设($H_0: Cov(\alpha_i,x)=0$)→ 选 FE;不拒绝 → 理论上 RE 更有效。05 完整 Stata 代码(reghdfe + esttab)
下面这段代码用 Stata 自带的 nlswork 面板数据(全国青年纵向调查)演示:从 OLS 起步,逐步加入个体 FE、时间 FE、聚类标准误,最后用 esttab 一键导出三线表。整段代码可以直接在 Stata 中运行。
*==============================================================*
* 基准回归完整演示:OLS -> FE -> TWFE -> 聚类标准误 -> esttab 导出
* 数据:Stata 自带 nlswork(面板:id 为工人,year 为年份)
*==============================================================*
clear all
set more off
capture log close
log using "baseline_regression.log", replace
* --- 0. 安装所需外部命令(首次运行取消注释) ---
* ssc install reghdfe, replace
* ssc install ftools, replace
* ssc install estout, replace
* ssc install esttab, replace
* --- 1. 加载数据并构造面板 ---
sysuse nlswork.dta, clear
xtset idcode year // 声明面板:个体 id,时间 year
* 关键变量:
* ln_wage 被解释变量:工资对数
* grade 个体受教育年限(时变程度小)
* age 年龄
* tenure 在当前雇主的 tenure
* south / smsa / race 常用控制变量
* --- 2. 模型 (1):朴素 Pooled OLS(不推荐,仅作对照) ---
regress ln_wage grade age i.south i.smsa
estimates store m1
* --- 3. 模型 (2):单向个体固定效应 xtreg, fe ---
xtreg ln_wage grade age i.south i.smsa i.year, fe
estimates store m2
* --- 4. 模型 (3):areg 吸收 id,加年份 FE ---
areg ln_wage grade age i.south i.smsa i.year, absorb(idcode)
estimates store m3
* --- 5. 模型 (4):reghdfe 双向固定效应 + 双向聚类 ---
reghdfe ln_wage grade age i.south i.smsa, ///
absorb(idcode year) vce(cluster idcode)
estimates store m4
* --- 6. 模型 (5):再加一维行业聚类(多向聚类) ---
reghdfe ln_wage grade age i.south i.smsa, ///
absorb(idcode year) vce(cluster idcode year)
estimates store m5
* --- 7. Hausman 检验:FE vs RE ---
xtreg ln_wage grade age i.south i.smsa i.year, fe
estimates store FE
xtreg ln_wage grade age i.south i.smsa i.year, re
estimates store RE
hausman FE RE, sigmamore
* --- 8. 用 esttab 导出论文级三线表 ---
* 横向并排展示 5 个模型;括号中放标准误;显示星号;删除虚拟变量行
esttab m1 m2 m3 m4 m5 using "table_baseline.rtf", replace ///
b(%9.3f) se(%9.3f) star(* 0.10 ** 0.05 *** 0.01) ///
stats(N r2 r2_a, fmt(0 3 3) labels("观测值" "R^2" "调整 R^2")) ///
drop(*.year *.smsa *.south) ///
mtitles("Pooled OLS" "xtreg FE" "areg" "reghdfe 单向聚类" "reghdfe 双向聚类") ///
title("表 X:受教育年限对工资的影响") ///
nogaps compress
log close
b() 指定系数格式;se() 在括号里放标准误(要放 t 值就写 t());star() 自定义星号阈值;stats() 在表底追加 N / R² 等;drop() 把虚拟变量从表里隐藏;mtitles() 给每一列起名字;nogaps compress 输出紧凑的三线表。导出为 .rtf 后可直接在 Word 里"选择性粘贴→无格式文本"贴进论文。
06 论文案例精读
07 常见错误与陷阱
面板数据的误差几乎必然存在组内相关。审稿人看到你 reg y x i.id i.year 后面没写 cluster,会直接怀疑你的 t 值是"虚高"。正确做法:在 reghdfe / xtreg 后立刻加上 vce(cluster id),并在表注中说明聚类层级。
例如处理变量是省级政策,却 cluster 到企业层面。企业层面 cluster 假设"同省不同企业之间误差独立",这显然不成立。经验法则:cluster 到处理变量被分配的层级(level of treatment assignment)。
如果你只有 10 个省份、20 个年份,cluster robust 渐近标准误会严重偏小。此时必须用 boottest(Roodman 2019)做 wild cluster bootstrap,而不是硬报 t 值。
性别、出生地这种变量在个体 FE 下会被 $\alpha_i$ 完全吸收,系数无法识别。Stata 会直接 omit。写论文时要意识到:FE 模型中只能识别"随个体和时间都变化"的变量。
加入海量 FE 后 within R² 会显著上升,但这并不意味着因果识别更好。读者关心的是 $\hat{\beta}_1$ 的因果解释,不是模型拟合度。
08 进阶资料
- Frisch, R. & F. V. Waugh (1933) / Lovell, M. C. (1963) — FWL 定理原始文献:残差化(partialing-out)视角统一理解虚拟变量、交乘项与固定效应;
- Cameron, A. C. & D. L. Miller (2015) — "A Practitioner's Guide to Cluster-Robust Inference", Journal of Human Resources:多向聚类的标准参考。
- Correia, S. (2017) — reghdfe 作者在 Stata Journal 的原文:讲解 FWL 定理与高维 FE 的算法。
- Roodman, D. et al. (2019) — "Fast and wild: Bootstrap inference in Stata using boottest", Stata Journal:cluster 数量少时的稳健推断。
- 伍德里奇《计量经济学导论:现代观点》第 14 章:面板数据 FE/RE 的中文教材。