外观
工具变量法(2SLS)
两阶段最小二乘:第一阶段以工具变量拟合内生解释变量,第二阶段用其拟合值回归,纠正内生性造成的 OLS 偏误;支持高维固定效应(pyhdfe 吸收)。
核心代码
py
def _fit_iv_model(self, decimals: int, title: str) -> Any:
if not self.y_var:
raise ValueError(_('请先选择因变量'))
exog_vars = self._unique_preserve_order(self.x_vars)
endog_vars = self._unique_preserve_order(self.endog_vars)
instrument_vars = self._unique_preserve_order(self.instrument_vars)
fe_vars = self._unique_preserve_order(self.fe_vars)
if not endog_vars:
raise ValueError(_('2SLS/GMM 至少需要选择一个内生解释变量'))
if not instrument_vars:
raise ValueError(_('2SLS/GMM 至少需要选择一个工具变量'))
overlap = [var for var in endog_vars if var in exog_vars]
if overlap:
warnings.warn(
_('以下变量同时被选为外生控制变量和内生变量,已自动按内生变量处理: %(columns)s') % {'columns': ', '.join(overlap)},
UserWarning
)
exog_vars = [var for var in exog_vars if var not in overlap]
redundant_instruments = [var for var in instrument_vars if var in exog_vars]
if redundant_instruments:
warnings.warn(
_('以下工具变量同时出现在外生控制变量中,已作为普通外生变量处理,不再重复计入排除型工具变量: %(columns)s') % {'columns': ', '.join(redundant_instruments)},
UserWarning
)
instrument_vars = [var for var in instrument_vars if var not in redundant_instruments]
bad_fe = sorted(set(fe_vars) & (set(endog_vars) | set(instrument_vars)))
if bad_fe:
raise ValueError(_('固定效应变量不能同时被设为内生变量或工具变量: %(columns)s') % {'columns': ', '.join(bad_fe)})
if len(instrument_vars) < len(endog_vars):
raise ValueError(_('工具变量数量不能少于内生变量数量,否则模型无法识别'))
cluster_var = self.se_options.get('cluster_var')
needed_cols = [self.y_var] + exog_vars + endog_vars + instrument_vars + fe_vars
if cluster_var:
needed_cols.append(cluster_var)
needed_cols = self._unique_preserve_order([col for col in needed_cols if col])
df = self.data[needed_cols].dropna().copy()
self._iv_complete_case_nobs = int(len(df))
self._iv_singletons_dropped = 0
self._iv_absorbed_dof = 0
self._iv_cluster_series = None
self._iv_identification_stats = {}
if len(df) <= len(exog_vars) + len(endog_vars) + len(fe_vars) + 5:
raise ValueError(_('有效样本量过少,无法稳定估计 2SLS/GMM 模型'))
if fe_vars:
self.fe_handling = 'HDFE absorption (pyhdfe)'
estimation_df, exog_vars, endog_vars, instrument_vars = self._prepare_absorbed_iv_data(
df=df,
exog_vars=exog_vars,
endog_vars=endog_vars,
instrument_vars=instrument_vars,
fe_vars=fe_vars
)
self._fit_iv_on_dataframe(
df=estimation_df,
exog_vars=exog_vars,
endog_vars=endog_vars,
instrument_vars=instrument_vars,
fe_vars=fe_vars,
use_formula=False
)
else:
self.fe_handling = 'None'
self._fit_iv_on_dataframe(
df=df,
exog_vars=exog_vars,
endog_vars=endog_vars,
instrument_vars=instrument_vars,
fe_vars=fe_vars,
use_formula=True
)
self.iv_exog_vars = exog_vars
self.endog_vars = endog_vars
self.instrument_vars = instrument_vars
self._finalize_iv_results(
decimals=decimals,
title=title,
exog_vars=exog_vars,
endog_vars=endog_vars,
instrument_vars=instrument_vars,
fe_vars=fe_vars
)
return self.result极小样本复现
样本 iv_cross.csv 共 100 行截面:
bash
python examples/run_iv_2sls.py期望输出:
============================================================
工具变量法(2SLS),内生变量: x_endog,工具变量: z1
============================================================
样本量 N = 100
------------------------------------------------------------
变量 系数 标准误
x_endog 1.4983*** (0.0513)
x1 0.4389*** (0.1362)
Constant -0.1196 (0.1466)
------------------------------------------------------------
(数据生成过程真实系数: x_endog = 1.5, x1 = 0.4;OLS 因内生性会有偏)