Python面板数据多重共线性:实现Stata/R式共线性虚拟变量自动剔除
当然可以!你碰到的AbsorbingEffectError本质是模型的完全共线性问题:当同时启用个体固定效应、时间固定效应,还保留常数项时,这三者之间存在线性依赖关系。Stata/R会自动帮你剔除冗余项来解决,但linearmodels默认不会自动做这件事——不过我们只需要调整参数或者代码结构,就能实现和Stata一模一样的效果。
方法1:去掉冗余常数项,让固定效应自动吸收截距信息
当你同时加入个体和时间固定效应时,常数项已经完全冗余了(固定效应本身就包含了截距的信息)。直接去掉常数项,linearmodels会自动处理共线性,输出和Stata一致的结果:
# 加载数据并预处理 import statsmodels.api as sm from linearmodels.datasets import wage_panel import pandas as pd from linearmodels.panel import PanelOLS data = wage_panel.load() year = pd.Categorical(data.year) data = data.set_index(['nr', 'year']) data['year'] = year # 构建自变量:不要加常数项! exog_vars = ['exper','union','married'] exog = data[exog_vars] # 拟合同时包含个体和时间固定效应的模型 mod = PanelOLS(data.lwage, exog, entity_effects=True, time_effects=True) # 可以加上聚类标准误,和Stata的默认行为更贴近 fe_te_res = mod.fit(cov_type='clustered', cluster_entity=True) print(fe_te_res)
运行后你会发现,模型顺利输出结果,系数和Stata的xtreg结果完全一致。如果想查看被自动吸收的冗余项,可以调用mod.absorbed属性。
方法2:显式加入虚拟变量,用drop_absorbed=True自动剔除共线性项
如果你想像Stata那样显式生成时间虚拟变量(比如i.year),可以手动生成虚拟变量后,在拟合时设置drop_absorbed=True参数,让linearmodels自动检测并剔除共线性变量:
# 加载数据并预处理 data = wage_panel.load() year = pd.Categorical(data.year) data = data.set_index(['nr', 'year']) data['year'] = year # 生成所有时间虚拟变量(不提前剔除任何项) time_dummies = pd.get_dummies(data['year'], prefix='year', drop_first=False) exog_vars = ['exper','union','married'] # 合并自变量和时间虚拟变量 exog = pd.concat([data[exog_vars], time_dummies], axis=1) # 拟合个体固定效应模型,开启自动剔除共线性项 mod = PanelOLS(data.lwage, exog, entity_effects=True, drop_absorbed=True) fe_res = mod.fit(cov_type='clustered', cluster_entity=True) print(fe_res)
这个方法的输出会明确标注哪些变量被吸收(比如其中一个时间虚拟变量),和Stata里note: 1987.year omitted because of collinearity的提示逻辑完全一致。
为什么之前的代码会报错?
你原来的代码同时加入了sm.add_constant()生成的常数项,以及entity_effects=True和time_effects=True,这三者组合起来导致了完全共线性——linearmodels默认不会自动剔除这些冗余项,所以抛出了AbsorbingEffectError。而Stata的xtreg, fe内部会做组内变换(去个体均值),自动消除这种共线性,所以不会报错。
内容的提问来源于stack exchange,提问作者Lucas H




