ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Stata高维固定效应回归:从共线性报错到reghdfe实战

Stata高维固定效应回归:从共线性报错到reghdfe实战 1. 多重固定效应为什么总跟“共线性”过不去1.1 固定效应的本质一排排“开关”塞进回归矩阵先说一个我经常在答疑群里看到的问题有人跑企业面板数据想控制行业差异、地区差异、年份差异于是在模型里写了reg roa digital rd size age i.industry i.province i.year结果Stata直接报了一长串“omitted because of collinearity”然后他跑来问“是不是行业和省份不能同时放”我说你先别急着怀疑变量问题的根源在于你让Stata干了它最不擅长的事——在普通回归里硬塞几百个虚拟变量。固定效应在计量上等价于给每个类别发一个“开关”。行业有90个类别就放90个虚拟变量省份有31个类别就再放31个年份有20年就再放20个。加上常数项和解释变量设计矩阵一下子多了快150列。Stata的普通回归命令reg在设计矩阵上要执行矩阵求逆默认的矩阵大小上限通常是400。150列还能勉强活着但如果你再往里面加交互项比如行业×省份、行业×年份几千、上万个虚拟变量一次性压进来矩阵直接就炸了。这时候出现的报错不一定叫“matsize too small”很多时候先出现的就是“omitted because of collinearity”。因为当虚拟变量数量多到一定程度类别之间互相嵌套、空单元、线性组合等问题会频繁出现某个哑变量恰好可以被其它哑变量的线性组合表达出来OLS估计就找不到唯一解只能把其中某个变量默默丢弃。1.2 共线性报错到底在提示什么很多新手看到“omitted because of collinearity”就以为是自己变量选错了其实这句话翻译成人话是你给我的设计矩阵里有某一列或多个列的组合和另一列重复了我没法做唯一求逆所以我自作主张扔掉了多余的那一列。我常用一个生活类比来解释这件事三个人A、B、C你想分别估计他们三个人的“个人影响力”但模型里又加入了一个变量“三人总影响力”。三个人影响力之和等于总影响力这就有了一列是其它列的线性组合。此时不管你怎么回归总会有一个人被剔除这不是因为这个人没价值而是信息重复了。高维固定效应里出现这种重复很常见。比如某个行业只在某一个省份存在行业虚拟变量和省份虚拟变量在某些观测上就形成了一一对应关系。再比如你同时放“行业”和“年份”又放“行业×年份”交互那交互项天然包含了行业和年份的全部信息行业和年份单独的虚拟变量就会有一部分变成冗余。Stata能识别出冗余但识别得不够聪明它会简单粗暴地omitted而不会告诉你到底哪一列和哪一列冲突。所以我的建议是遇到这行报错不要急着删变量先想清楚你的固定效应结构里是否有嵌套、是否类别粒度重叠、是否样本在某些格子里是空的。如果数据规模不大可以用tab把两个维度的交叉表打出来看一眼。1.3 reg、areg、xtreg各自的能力边界既然普通reg加虚拟变量不靠谱那换areg和xtreg行不行这三个命令我都用过可以简单说说它们各自的边界。reg y x i.industry i.province i.year是LSDV最小二乘虚拟变量思路原理最简单直接估计所有虚拟变量的系数。优点是结果透明连每个行业、省份的截距都能看到缺点是虚拟变量一多就卡而且输出会刷屏看核心变量的系数要翻半天。areg只能吸收一个维度的固定效应比如areg roa digital rd, absorb(industry)。它比reg快但一个模型只能吸一个维度。有人想用egen group group(industry province)把行业和省份捏成一个维度塞给areg这确实能跑但代价是你再也分不清被吸收的到底是行业差异还是省份差异自由度计算也会跟着变。xtreg, fe是面板数据里最常用的个体固定效应估计但它本质上只能吸收一个维度就是面板个体本身。比如xtset firm_id year之后xtreg roa digital rd, fe吸收的是企业个体效应。如果你想同时控制行业和省份固定效应xtreg是不能直接做到的除非你自己把行业、省份的虚拟变量再加进去那就又回到了reg的老路。这三个命令的共性问题是它们都不是为“多个高维分类变量同时存在”设计的。真正为这个问题优化过的是下一章要讲的reghdfe。2. reghdfe的核心逻辑不建虚拟变量也能吸收固定效应2.1 安装reghdfe一行命令解决依赖reghdfe是Sergio Correia写的高维固定效应回归命令Stata里可以直接通过SSC安装。我第一次用的时候还是老版本需要先装ftools现在一般一条命令会把依赖都带下来ssc install ftools ssc install reghdfe安装完可以验证一下which reghdfe能看到命令路径就说明装好了。如果你是在受限服务器上不能访问外网也可以找管理员手动安装离线包但一般情况下ssc足够了。顺便说一句ftools这个包本身也值得关注它提供了很多快速处理因子变量的工具对大数据集很有用。2.2 组内去均值reghdfe高效运行的秘密很多人好奇reghdfe为什么能同时吸收行业、地区、年份三个甚至更多维度的固定效应还不报共线性答案不是它取消了共线性而是它根本不构造那些巨大的虚拟变量矩阵。它的核心思路叫“组内去均值”也叫within变换。假设你想控制行业固定效应传统做法是给每个行业设一个哑变量但reghdfe的做法是先把每个变量在行业内取均值然后用原始值减去这个均值。这样行业之间的差异被减掉了剩下的就是行业内变异。你不需要真正创建一个行业虚拟变量也能得到相同的系数估计。只对一个维度去均值很简单难的是同时对多个维度去均值。先按行业去一遍再按省份去一遍再按年份去一遍反复迭代直到收敛。这个过程在数学上等价于把所有固定效应虚拟变量全部放进模型里做OLS但计算量和内存消耗小了几个数量级。reghdfe还会做共线性检测自动识别冗余的固定效应类别并在输出中报告。我自己的理解是reghdfe等于把那些成百上千个“开关”先藏起来在后台偷偷把每个开关的效果减掉再让我们关心解释变量干干净净地进场估计。这就是它又快又稳的原因。2.3 第一次跑reghdfe命令写法与输出解读下面是我常用的一个示例数据是虚构的企业面板研究数字化投入digital对企业绩效roa的影响同时控制研发投入、规模、年龄并吸收行业、省份、年份三个固定效应use firm_panel.dta, clear reghdfe roa digital rd size age, absorb(industry province year) vce(cluster firm_id)几个关键点说一下。absorb()括号里写的是要被吸收的固定效应维度多个维度用空格隔开不需要加i.前缀。vce(cluster firm_id)是企业层面的聚类稳健标准误允许同一家企业在不同年份之间存在相关性这是面板数据里的标准操作。跑完之后输出和普通回归不太一样。最上面一栏照例是样本量、F统计量、P值。中间的系数表和reg长得差不多核心解释变量digital的系数、标准误、t值、置信区间都在。但请注意R-squared这一项这里报告的是“within R²”也就是固定效应被吸收后模型对组内变异的解释力。它和普通回归的总R²不是同一个概念别拿去比较。输出末尾会有一张“Absorbed degrees of freedom”表格这是很多人不会看但非常有用的部分。它会列出每个固定效应维度有多少个类别其中有多少个是被判定为冗余而吸收掉的。比如industry显示Category90、Redundant1就说明90个行业哑变量里有一个和别的固定效应线性相关了被自动剔除。这张表就是reghdfe帮你做共线性诊断的可视化结果。2.4 用xtreg、areg做交叉验证reghdfe跑得再顺我也建议你偶尔做一次交叉验证确认结果没跑偏。最简单的方法是用一个只含单一固定效应的模型对比reghdfe和xtreg, fe或areg的系数。比如只用企业个体固定效应时xtset firm_id year xtreg roa digital rd size age, fe reghdfe roa digital rd size age, absorb(firm_id)这两个命令的系数理论上应该一模一样标准误也会一致。我第一次做这个对比的时候心里是有点打鼓的毕竟reghdfe是迭代算法万一哪里收敛出问题呢但实测下来结果完全一致。从那以后我就敢放心用了。同理areg roa digital rd, absorb(industry)和reghdfe roa digital rd, absorb(industry)也应该得到相同的系数。如果哪天不一致优先检查数据排序、缺漏值处理和样本筛选是否一致再考虑是不是版本问题。3. 实战行业、地区、年份多重固定效应怎么做3.1 基础版三维独立固定效应大多数实证论文里的“行业、地区、年份”三重固定效应指的是三个相互独立的类别维度各自控制各自的截距。对应命令就是reghdfe roa digital rd size age, absorb(industry province year) vce(cluster firm_id)这个模型的意思是说在比较数字化投入对绩效的影响时我们会把行业之间普遍存在的差异、省份之间普遍存在的差异、年份之间普遍存在的宏观冲击全部拿掉。剩下的识别来源是同一行业、同一省份、同一年份里的不同企业之间数字化投入的差异如何导致绩效差异。这个设定是多数情况下的“默认配置”但它能不能成立取决于你的数据在“行业×省份×年份”这个格子里是否还有足够多不同digital水平的企业。如果某个行业在某个省份只有那么一两家企业样本就会被浪费标准误会偏大。所以跑之前用table industry province看一下交叉分布是个好习惯。3.2 进阶版行业×年份交互固定效应有时候独立的三维固定效应还不够。比如国家在某年针对某一行业出台了一项政策所有该行业的企业都受影响如果不控制“行业×年份”层面的冲击Digital的系数可能抓到政策的效应。这时候就需要吸收行业×年份交互固定效应reghdfe roa digital rd size age, absorb(industry#year province) vce(cluster firm_id)industry#year表示行业与年份的交互项等价于给每个行业、每一年都设一个单独的截距。这样行业层面的年度冲击比如行业景气度、行业政策、技术变革都被吸收掉了。代价是这个模型会消耗很多自由度而且行业层面不随时间变化的变量以及随时间变化但只存在于行业层面的变量都进不了模型。再往上一档可以同时吸收industry#year和province#yearreghdfe roa digital rd size age, absorb(industry#year province#year) vce(cluster firm_id)这就意味着行业一年份联合趋势和省份一年份联合趋势都被控制了。设定更严格但识别来源也变得更窄。我见过一些年轻研究者一上来就追求“最强固定效应”把所有能吸收的全部吸收掉结果核心解释变量要么消失要么变得很不显著。这不是命令的错是变异被吃干了。3.3 标准误聚类在哪个层级聚结果差异不小固定效应解决的是截距问题标准误解决的是推断问题。两者经常被混在一起但完全是两码事。固定效应吸收得再干净如果标准误聚类层级不对t值照样可能虚高。reghdfe里vce(cluster xxx)可以随便指定聚类变量。最常用的是聚类到企业层面reghdfe roa digital rd size age, absorb(industry province year) vce(cluster firm_id)这条命令允许同一家企业跨年份的扰动项任意相关。如果政策冲击在行业层面存在共同成分你还需要考虑聚类到行业层面reghdfe roa digital rd size age, absorb(industry province year) vce(cluster industry)聚类到更粗的层级通常会让标准误更大因为相当于放宽了组内相关性的假设这是一个更保守的选择。但聚类数太少也有问题如果行业只有20个聚类到行业做推断在渐近理论上不太可靠。实务中很多论文会聚类到省份或行业我个人的习惯是核心结论至少用企业和省份两个聚类层级各跑一遍结果方向一致再往下写。4. Stata报错与异常结果排查实录4.1 核心变量被absorb后消失问题出在哪有一个现象比报错更让人抓狂就是模型不报错但核心解释变量在结果表里不见了。用reghdfe时偶尔会遇到这种提示note: digital is constant within the fixed effect groups and is absorbed意思是你的核心解释变量在固定效应组内没有变异。比如研究“是否属于高科技行业”这个变量对企业绩效的影响同时又在模型里吸收行业固定效应。高科技行业标签在行业内是不变的行业固定效应已经把行业层面的所有常数吸收掉了这个变量自然就识别不出来。这不是命令的问题是模型设定问题。解决办法要么去掉吸收这个维度要么换企业层面有变异的解释变量。我建议在跑之前先对核心变量做一次简单诊断用xtsum看组内标准差和组间标准差的比例。组内标准差接近0的变量就没有资格进入带固定效应的模型。4.2 matsize too small、内存不足这类老大难matsize too small这个报错可以看作Stata普通回归面对高维固定效应时的典型崩溃方式。老办法是手动调大允许的矩阵大小set matsize 11000但这不是长久之计。设计矩阵维度超过几万就算矩阵上限允许内存也未必扛得住。reghdfe的意义就在于它不需要构建完整的设计矩阵所以很少会遇到矩阵容量问题。它的瓶颈更多出现在类别数极其庞大的场景比如一次性吸收几十万个个体固定效应但这类场景在行业、地区、年份维度里很少见。如果你真的遇到reghdfe内存不足优先检查数据里是否有大量无用的变量和超大的字符串变量先精简数据集再跑比盲目升级电脑实在得多。4.3 singleton组别一个组只有一条样本怎么处理所谓singleton组就是某个固定效应类别里只有一个观测值。比如某个行业在数据里只有一家企业那这家企业观测的行业固定效应就可以完美解释它的所有绩效残差为零它对核心系数的估计几乎贡献不了信息还会干扰方差估计。reghdfe在较新版本里会对这类组别自动检测并在输出中提示有多少个singleton组被识别。遇到这种情况我的建议是先检查数据处理逻辑是不是筛选样本时把公司大量drop了如果确实是真实数据那就要么把这个小类别合并到相近类别要么明确说明这部分样本被排除。更通用的检查方法是bysort industry: gen n_s _N tab n_s看每个行业内有多少企业。n_s等于1的行业就是singleton在该维度下这些样本基本是“陪跑”。4.4 逐层加固定效应观察系数变化的诊断习惯最后分享一个我踩过多次坑之后养成的习惯不要一步到位跑终极模型而是从基础模型开始一层一层往上加固定效应观察核心系数的变化路径。比如先跑reg roa digital rd size age reghdfe roa digital rd size age, absorb(industry) reghdfe roa digital rd size age, absorb(industry year) reghdfe roa digital rd size age, absorb(industry year province)每一步都记录digital的系数、标准误和显著性。如果系数在加入某一层固定效应后突然发生剧烈变化说明你的核心识别可能和这层固定效应高度相关你要能解释得通其中的因果机制。如果系数一路变化最后甚至变号那就要警惕是不是固定效应吸收过度把真正的效应也吃掉了。这个过程就像剥洋葱一层层剥开既能看到模型对设定的敏感性也能更好地向审稿人讲述你的识别策略。我见过太多人只汇报一个终极设定的结果一问中间步骤就哑掉了这是很吃亏的。5. 高维固定效应模型的几个设定心得5.1 固定效应不是越多越好讲了这么多命令技巧我更想强调一个观念上的问题固定效应是有代价的它消耗变异也改变解释变量的含义。每增加一个固定效应维度你就相当于把某一个层面的所有水平差异全部“清零”。识别区间被压得越来越小剩下的变异很可能只是一些局部噪声系数自然难以显著。比如你想识别企业数字化投入的效应但把行业×年份、省份×年份全部吸收掉之后识别来源就变成了“同一个行业同一年内、同一个省份同一年内不同企业的数字化差异”对企业绩效的影响。如果你的数字化变量在行业内有很强的共同趋势这种设定可能把一个真实存在的效应给吸收掉。所以在设定模型前先问自己三个问题我的研究问题主要依赖哪一层的变异哪些层级是必须控制的混杂因素哪些层级会误伤我的核心变量想清楚了再写absorb。5.2 多维度敢用但要会看识别来源reghdfe让多维固定效应变得太容易了这是个好事也可能是个陷阱。容易指的是它一行命令就能处理几千个虚拟变量陷阱指的是很多研究者不再思考固定效应的经济含义只把absorb()当成一个“更严格”的装饰。我以前帮一个学弟改论文他把行业、地区、年份、行业×年份、地区×年份全部放进absorb结果核心解释变量直接变成了行业内、地区内、年份内三层缝隙里的残差变异。他问我为什么结果不显著我说这不是你的故事变弱了是你把故事的舞台几乎拆光了。我建议每次跑完高维固定效应都在心里默念一遍现在我的系数识别的对比对象是谁如果答不上来说明模型设定已经偏离了你的研究问题。5.3 reghdfe之外的扩展更多高维命令与文献reghdfe是处理高维固定效应回归的主力但也不是唯一工具。如果你的场景涉及工具变量可以考虑ivreghdfe它是reghdfe和ivreg2的结合语法结构类似。如果你的固定效应维度大到连reghdfe都吃力可以关注Correia等人后续提出的更快的估计思路。不过对绝大多数实证文章来说reghdfe已经足够了。我在实际使用中凡是遇到需要同时控制行业、省份、年份或更多维度交叉效应的面板模型基本都优先用reghdfe跑了这么多年它是我在Stata里最信任的高维固定效应工具。唯一需要叮嘱的是永远不要为了显得“高级”而堆砌固定效应一定要让设定服从于你的识别故事。最后分享一个小技巧每次跑模型前先tab一下每个固定效应维度的类别数和组内观测分布再检查一下核心变量的组内变异最后从简单模型逐步加到复杂模型。这三步做完再复杂的固定效应结构也出不了大乱子。
返回列表