ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Stata实证分析:reghdfe如何化解高维固定效应与共线性难题

Stata实证分析:reghdfe如何化解高维固定效应与共线性难题 刚接触Stata实证分析的朋友十有八九都见过那行刺眼的红字reghdfe跑得正欢突然来一句convergence not achieved或者variable omitted because of collinearity瞬间心态就崩了。尤其是当你辛辛苦苦把行业、地区、年份的虚拟变量一股脑塞进回归方程想着把固定效应做全做细结果Stata直接给你扔出一堆omitted系数没出来标准误没出来整个回归结果跟报废没什么两样。这篇文章就围绕这个经典痛点展开讲讲为什么用传统方式做高维固定效应容易翻车以及reghdfe这个命令凭什么能帮你把行业、地区、年份多重固定效应稳稳跑出来。先给结论reghdfe是处理高维固定效应的利器它的核心卖点不是多了一个回归命令而是把固定效应从放进回归列表里逐个估计变成先行剔除再估计这样既避免了虚拟变量爆炸带来的计算灾难也从根源上绕开了一大批共线性问题。适合正在做面板数据、公司金融、区域经济这类需要控制行业和地区特征的实证研究者尤其是那些被共线性三个字折磨过的新手。1. 为什么行业地区年份三个固定效应一起加经常跑出来一团乱很多人一开始用的都是最直觉的思路既然要控制行业、地区、年份那就用reg y x i.industry i.province i.year把虚拟变量全部放进去。小样本、少类别的情况下这个做法还能勉强出结果但一旦行业分类到两位数编码、省份有31个、年份跨度十几年问题就接踵而至。第一层问题是虚拟变量爆炸。假设你有48个行业、31个省份、12个年份光这三维虚拟变量就是91个再算上常数项和核心解释变量回归矩阵的规模一下就上去了。Stata不是跑不动但计算效率会明显下降内存占用飙升跑一次回归够你喝两杯咖啡。而且行业和省份之间存在大量交叉单元格比如某个行业只在少数几个省份出现某些省份根本没有某些行业这些空单元格会让矩阵秩亏系数矩阵没法正常求逆结果就是整列虚拟变量被omitted。第二层问题是真正的共线性来源。行业虚拟变量、省份虚拟变量、年份虚拟变量三者之间本身就存在完全线性相关的可能。比如你的样本里某个行业只在某一年出现那么这个行业×年份的组合效应就和单独的行业虚拟变量、年份虚拟变量混在一起分不开。更常见的是所有行业虚拟变量加起来等于常数项所有省份虚拟变量加起来也等于常数项如果你在回归里同时放了常数项和全部虚拟变量必然撞车。Stata为了识别模型会自动剔除一组基准组但剔除的逻辑不受你控制经常剔除的不是你想要的那个于是关键变量的系数估计就变得怪异甚至彻底被吃掉。第三层问题是LSDV方式带来的标准误偏差。哪怕你的回归勉强跑出来了逐个估计一两百个虚拟变量的系数自由度消耗非常严重。每个虚拟变量都在吃掉样本信息核心解释变量的标准误会因此被放大t值不显著但这不是真实关系不显著而是你的估计方法把精度浪费在了那些你根本不关心的行业系数和省份系数上。所以问题的本质不是固定效应不该加而是加的方式不对。你真正想要的只是把行业差异、地区差异、时间差异从扰动项里清理掉并不Care行业48个系数各自是多少、省份31个系数各自是多少但传统做法把这堆无关系数全部估计了一遍既慢又容易出共线性。2. reghdfe的底层逻辑先把固定效应吸收掉再回归reghdfe命令的全称是regress with high-dimensional fixed effects由Sergio Correia开发。它解决上述问题的思路非常朴素既然不关心固定效应本身的系数那就把它们从方程里彻底消掉只估计剩余变量的系数。这个消掉的过程在计量经济学里叫组内去均值或者within transformation但在高维固定效应场景下不能简单地对一个维度去均值而是要同时对多个维度做交替投影alternating projections。通俗理解就是先把行业固定效应的影响从变量里剥掉再把地区固定效应的影响剥掉再剥年份然后重新回到行业维度继续剥循环往复直到收敛。这个过程类似把一块沾了多层颜料的白布反复漂洗每轮漂掉一层颜色最后剩下的就是纯净的扰动和解释变量信息然后用干净的数据跑一个普通最小二乘回归。reghdfe内部用的具体算法是Kloek1981提出的迭代去均值方法配合Convergence Criteria来控制迭代次数。对于绝大多数面板数据集几十次迭代内就能收敛速度远快于生成上百个虚拟变量后做矩阵求逆。这也是为什么你的数据里有几万个观测值、三位固定效应时reghdfe依然能秒出结果而reg i.year i.province i.industry可能要跑上几分钟甚至内存溢出。由此引出几个关键概念absorb()括号里写你要吸收掉的固定效应维度。这就是reghdfe最核心的选项。cluster()聚类标准误选项吸收完固定效应之后它会在选定的聚类维度上做稳健调整。vce(robust)异方差稳健标准误。keep()在吸收高维固定效应的同时保留某些虚拟变量不吸收比如某个年份虚拟变量的交互项。这个设计带来了一个直接好处因为固定效应不再显式进入回归矩阵所以行业、省份、年份三者之间的虚拟变量线性相关问题被绕开了。你根本不需要去关心Stata自动剔除了哪一组基准组因为reghdfe在吸收阶段就把这些维度上的共同信息全部剥离剩下的变异都是行业内随时间的变化、省内随时间的变化这类纯粹的组内变异。3. 实操全流程从数据准备到命令输出直接照抄纸上谈兵没意思直接上一份可以本地复现的实操流程。假设你在做一个制造业上市公司的面板数据核心解释变量是研发投入强度rd_intensity被解释变量是企业全要素生产率tfp需要控制行业industry_code、省份province_code、年份year。先安装命令。reghdfe不是Stata官方命令需要从scc仓库安装ssc install reghdfe, replace同时建议安装两个配套命令一个用于输出表格一个用于处理多维聚类ssc install estout, replace ssc install ftools, replaceftools是reghdfe早期版本依赖的工具包新版可能不再强制需要但装上没坏处。然后做数据预处理。建议把行业和省份的变量先转成数值型编码避免字符串变量带来麻烦encode industry_name, gen(industry_code) encode province_name, gen(province_code) xtset company_id yearxtset这行不是reghdfe必需的但如果你后面还要跑xtreg做对比或者用xttest0检验随机效应那就提前设好。核心回归只有一行reghdfe tfp rd_intensity size leverage age, absorb(industry_code province_code year) vce(cluster company_id)解释一下这行代码的意思tfp是被解释变量rd_intensity是核心解释变量size leverage age是控制变量absorb()里放了三个固定效应维度vce(cluster company_id)表示按公司聚类调整标准误允许同一家公司不同年份之间的扰动项相关。跑完以后Stata会输出一大张表。常见的结果展示包括项目含义tfp被解释变量企业全要素生产率rd_intensity核心解释变量研发投入强度size企业规模控制变量leverage杠杆率控制变量age企业年龄控制变量Absorbed显示被吸收的三个固定效应及对应的类别数量F test联合显著性检验检验所有解释变量是否整体显著R-squared模型解释力Number of obs观测值数量需要特别注意输出表底部的Absorbed行它会写industry_code absorbed48 categories这样的信息告诉你行业固定效应吸收了48个类别。如果这里显示的类别数量和你的数据编码一致说明吸收过程正常。跑完reghdfe后有人习惯用estat vif检查多重共线性这里要提醒一句reghdfe执行完之后estat vif很多时候是不能用的因为它基于的是吸收后残差数据的方差膨胀因子本质上只能反映解释变量之间在去除固定效应后的共线性跟你担心的行业地区虚拟变量共线性已经不是一个概念了。想检查原始解释变量之间的共线性应该在普通reg之后跑或者直接看相关系数矩阵。结果解释上rd_intensity的系数就是你要的核心结论。比如系数是0.032p值0.01意味着研发投入强度每提高1个百分点企业全要素生产率平均提高0.032个单位。注意这个解释必须放在控制了行业差异、地区差异、年份差异之后的语境下不能省略固定效应控制的限定语。4. 输出三线表与标准化处理让结果能直接进论文跑出结果只是第一步写论文的人都知道最后要的是规范的三线表。我用的是esttab配合reghdfe的组合这个流程自己走顺了之后效率很高。先给基础回归编号并存储结果* 模型1只有核心解释变量 reghdfe tfp rd_intensity, absorb(industry_code province_code year) vce(cluster company_id) est store m1 * 模型2加入控制变量 reghdfe tfp rd_intensity size leverage age, absorb(industry_code province_code year) vce(cluster company_id) est store m2 * 模型3换成二维聚类标准误 reghdfe tfp rd_intensity size leverage age, absorb(industry_code province_code year) vce(cluster company_id year) est store m3三个模型分别存储后一行代码输出表格esttab m1 m2 m3, b(3) se(3) star(* 0.10 ** 0.05 *** 0.01) /// title(Table 1: 固定效应回归结果) /// mtitles(基准模型 加入控制变量 二维聚类) /// keep(tfp rd_intensity size leverage age) /// stats(N r2, labels(样本量 R-squared))参数含义b(3)表示系数保留三位小数se(3)是标准误保留三位小数star指定显著性符号规则keep限制表格里只显示核心变量避免固定效应信息刷屏。stats控制表格底部报告什么统计量。如果你用的是中文环境标题和标签都可以写中文Stata对中文标签的支持在输出docx或tex时完全没问题但控制台显示可能乱码不影响最终导出。导出到外部文档esttab m1 m2 m3 using 固定效应结果.csv, replace b(3) se(3) star(* 0.10 ** 0.05 *** 0.01) /// mtitles(基准 加控制 二维聚类) keep(tfp rd_intensity size leverage age)推荐先导出csv在Excel里微调格式后再转成Word表格比直接输出rtf好用因为rtf表格的列宽控制比较费劲。关于标准误的问题多说一句。行业、地区双重固定效应模型里同一省份内的企业扰动项往往存在相关性同一行业内的企业也存在相关性所以单独按公司聚类可能不够稳健。如果你担心的是行业层面的相关性可以考虑vce(cluster industry_code)如果担心行业和省份两个维度同时存在聚类效应可以用双向聚类reghdfe tfp rd_intensity size leverage age, absorb(industry_code province_code year) vce(cluster industry_code province_code)不过双向聚类对数据量要求较高样本太少时协方差矩阵可能不是正定的跑出负方差不要慌先看看每个聚类维度的类别数够不够。5. reghdfe的边界什么情况它救不了你reghdfe不是万能药有几个场景它确实搞不定新手最容易被表面上的跑通迷惑实际模型已经出了问题。第一个是完全共线性问题并没有消失只是被隐藏了。如果你的核心解释变量是industry_code这个维度上的常量比如你想研究行业平均工资对企业生产率的影响但这个变量本来就是行业代码的直接映射那么它在吸收了行业固定效应之后就完全没有任何变异了reghdfe会直接把它drop掉输出一个系数为空的结果。这其实是一个重要信号你的变量和固定效应完全重合需要换个研究设计。同理某省的虚拟变量如果吸收了省份固定效应系数自然也是空的。很多人看到空结果以为reghdfe出bug了其实不是这是模型识别不了本质上是你的数据里这个变量的变异全部来自你已经吸收掉的那个维度。第二个是样本量太小或单元格太稀疏。假设你的样本里某行业在大多数省份都没有企业只有个别省份有少数企业那这个行业和省份的交叉效应就完全依赖几个孤点支撑。reghdfe虽然能跑但估计结果极不稳定标准误巨大。遇到这种情况建议合并行业分类或者把省份聚合成大区减少吸收维度里的类别数量。第三个是多重高维固定效应下的聚类标准误偏误。reghdfe的vce(cluster company_id)在固定效应完全吸收后其实是在做有限样本修正但当每个聚类组里只有一两个观测值时修正效果不可靠。我自己踩过的坑是把年份聚类和公司聚类同时放进去结果协方差矩阵不是正定的Stata直接报错convergence not achieved。解决思路是减少聚类维度或者检查是不是某个聚类组里样本量太少。另外很多人在跑reghdfe时看到singleton observations的提示这是说某些固定效应组合里只有一个观测值。Stata默认会报告这些singleton的数量但不会自动删除。有研究建议删除singleton因为它们实际上不提供识别信息还容易让标准误变小。想删除的话可以用reghdfe的keep(singletons)选项来控制是否保留默认是剔除。早期版本里如果保留singleton可能导致标准误下偏新版本已经做了处理但我个人习惯是保留默认剔除让估计更保守。6. 从reghdfe到更复杂的固定效应结构掌握了基础用法之后有几个进阶场景值得提一下实际研究中经常遇到。第一种是交互固定效应。有时候你要控制行业×年份的联合效应比如某年国家对特定行业出台了扶持政策这个政策同时随行业和时间变化如果你只放行业固定效应和年份固定效应政策效应会被混进扰动项。这时可以在absorb()里写交互项reghdfe tfp rd_intensity size leverage age, absorb(industry_code##year province_code) vce(cluster company_id)industry_code##year表示吸收行业—年份交互固定效应。这个操作在普通areg或xtreg里很难实现因为类别数会爆炸性增长reghdfe的优势就非常明显。需要注意的是当你把交互固定效应吸收掉之后所有随行业和年份同时变化的解释变量都没法识别了比如某行业平均补贴强度这种变量会跟交互固定效应完全共线直接被删掉。第二种是多维固定效应下的IV估计。如果你的核心解释变量有内生性需要工具变量可以结合ivreghdfe命令也是Correia写的ssc install ivreghdfe, replace ivreghdfe tfp (rd_intensity iv_rd), absorb(industry_code province_code year) cluster(company_id)ivreghdfe的用法跟reghdfe高度一致只是多了工具变量设定固定效应部分同样可以吸收多维度。做了IV之后输出表会报告第一阶段的F统计量判断工具变量是否弱识别这个值最好大于10。第三种是与ppmlhdfe的关系。如果你的被解释变量是贸易额、专利计数这种含有大量零值的数据应该考虑ppmlhdfeppml with high-dimensional fixed effects它处理的是泊松伪最大似然估计比reghdfe更适用于计数数据。但两者在固定效应吸收逻辑上完全一致学会reghdfe再转ppmlhdfe只用改估计方法absorb()语法不变。7. 几个新手最容易忽略的细节和实操心得最后写一点个人经验。这些细节看起来不起眼但都直接影响结果可信度。第一reghdfe的vce(cluster company_id)和xtreg, fe的聚类标准误不是一回事。xtreg, fe默认报告的是普通标准误如果没加vce(robust)或vce(cluster)标准误可能偏小。reghdfe默认不加聚类时报告的是异方差稳健标准误加了cluster才是聚类稳健。读论文时看到标准误在公司层面聚类你要确认对方用的是reghdfe还是xtreg两者在有限样本下的修正方式不同数字会有差别但不影响系数本身。第二跑reghdfe之前先确认变量没有缺失值。reghdfe对缺失值的处理是直接删掉任意一个变量缺失的观测如果你控制变量里有大量缺失它会在你毫无感知的情况下把样本量缩水。跑完后看一眼Number of obs和你原始数据量差多少如果缩水严重回头清洗缺失值别闷头解读结果。第三absorb()里每个维度的类别数不要太多否则内存占用会高得吓人。遇到过有人把几十万量级的个人编码放进去吸收结果Stata直接内存溢出。reghdfe对高维固定效应的处理极限取决于你的机器内存和Stata位数64位版能处理更大的矩阵如果你的个人编码有几十万类别建议用esttab导出结果之前先考虑一下类别维度是否合理。第四关于共线性报错如果是reghdfe (convergence not achieved)不要第一时间怀疑数据有问题先检查是不是迭代次数不够。可以用iterate(1000)显式指定最大迭代次数或者tolerance(1e-10)放宽收敛精度。更多时候这个报错是由两个固定效应维度在某个子样本上完全共线引起的比如某一年份只有某个行业有数据那年份和行业在这个子样本上就会撞车。解决思路是删掉那些在特定维度上没有变异的观测或者重新定义固定效应的粒度。第五新手容易混淆显著和有意义。reghdfe输出一行星号代表的是统计显著性如果你在几十个回归组合里反复搜索显著性组合那已经涉及多重假设检验问题了。固定效应模型的本质是更干净的对照组比较跑出不显著的结果不代表你的研究没有价值反而说明在控制了大量异质性之后核心关系依然稳健这本身就是有意义的结论。从实际使用体验来看reghdfe这套工具链已经成为我处理面板数据的标配。无论是两维固定效应、三维固定效应还是交互固定效应一行命令就能搞定速度和稳健性都比手动生成虚拟变量可靠得多。项目开始时多花十分钟把固定效应结构想清楚远比反复试错省时间。
返回列表