Skip to content

工具变量法(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 行截面:xendog=1.2z1+0.3x1+uy=1.5xendog+0.4x1+eue 相关(内生性,z1 为工具变量)。

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 因内生性会有偏)

Released under the AGPL-3.0 License.