def test_against_ols(ols_data):
    mod = AbsorbingLS(
        ols_data.y,
        ols_data.x,
        absorb=ols_data.absorb,
        interactions=ols_data.interactions,
        weights=ols_data.weights,
    )
    res = mod.fit()
    absorb = []
    has_dummy = False
    if ols_data.absorb is not None:
        absorb.append(ols_data.absorb.cont.to_numpy())
        if ols_data.absorb.cat.shape[1] > 0:
            dummies = dummy_matrix(ols_data.absorb.cat, precondition=False)[0]
            assert isinstance(dummies, sp.csc_matrix)
            absorb.append(dummies.A)
        has_dummy = ols_data.absorb.cat.shape[1] > 0
    if ols_data.interactions is not None:
        for interact in ols_data.interactions:
            absorb.append(interact.sparse.A)
    _x = ols_data.x
    if absorb:
        absorb = np.column_stack(absorb)
        if np.any(np.ptp(_x, 0) == 0) and has_dummy:
            if ols_data.weights is None:
                absorb = annihilate(absorb, np.ones((absorb.shape[0], 1)))
            else:
                root_w = np.sqrt(mod.weights.ndarray)
                wabsorb = annihilate(root_w * absorb, root_w)
                absorb = (1.0 / root_w) * wabsorb
        rank = np.linalg.matrix_rank(absorb)
        if rank < absorb.shape[1]:
            a, b = np.linalg.eig(absorb.T @ absorb)
            order = np.argsort(a)[::-1]
            a, b = a[order], b[:, order]
            z = absorb @ b
            absorb = z[:, :rank]
        _x = np.column_stack([_x, absorb])
    ols_mod = _OLS(ols_data.y, _x, weights=ols_data.weights)
    ols_res = ols_mod.fit()

    assert_results_equal(ols_res, res)
Exemple #2
0
    def wooldridge_score(self):
        r"""
        Wooldridge's score test of exogeneity

        Returns
        -------
        t : WaldTestStatistic
            Object containing test statistic, p-value, distribution and null

        Notes
        -----
        Wooldridge's test examines whether there is correlation between the
        errors produced when the endogenous variable are treated as
        exogenous so that the model can be fit by OLS, and the component of
        the endogenous variables that cannot be explained by the instruments.

        The test is implemented using a regression,

        .. math ::

          1 = \gamma_1 \hat{\epsilon}_1 \hat{v}_{1,i} + \ldots
            + \gamma_p \hat{\epsilon}_1 \hat{v}_{p,i} + \eta_i

        where :math:`\hat{v}_{j,i}` is the residual from regressing endogenous
        variable :math:`x_j` on the exogenous variables and instruments.

        The test is a :math:`n\times R^2 \sim \chi^2_{p}`.

        Implemented using the expression in Wooldridge (2002), Eq. 6.19
        """
        from linearmodels.iv.model import _OLS

        e = annihilate(self.model.dependent.ndarray, self.model._x)
        r = annihilate(self.model.endog.ndarray, self.model._z)
        nobs = e.shape[0]
        r = annihilate(r, self.model._x)
        res = _OLS(ones((nobs, 1)), r * e).fit(cov_type='unadjusted')
        stat = res.nobs - res.resid_ss
        df = self.model.endog.shape[1]
        null = 'Endogenous variables are exogenous'
        name = 'Wooldridge\'s score test of exogeneity'
        return WaldTestStatistic(stat, null, df, name=name)
Exemple #3
0
    def wooldridge_overid(self):
        r"""
        Wooldridge's score test of overidentification

        Returns
        -------
        t : WaldTestStatistic
            Object containing test statistic, p-value, distribution and null

        Notes
        -----
        Wooldridge's test examines whether there is correlation between the
        model residuals and the component of the instruments that is
        orthogonal to the endogenous variables. Define :math:`\tilde{z}`
        to be the residuals of the instruments regressed on the exogenous
        variables and the first-stage fitted values of the endogenous
        variables.  The test is computed as a regression

        .. math ::

          1 = \gamma_1 \hat{\epsilon}_i \tilde{z}_{i,1} + \ldots +
              \gamma_q \hat{\epsilon}_i \tilde{z}_{i,q}

        where :math:`q = n_{instr} - n_{endog}`.  The test is a
        :math:`n\times R^2 \sim \chi^2_{q}`.

        The order of the instruments does not affect this test.
        """
        from linearmodels.iv.model import _OLS
        exog, endog = self.model.exog, self.model.endog
        instruments = self.model.instruments
        nobs, nendog = endog.shape
        ninstr = instruments.shape[1]
        if ninstr - nendog == 0:
            import warnings
            warnings.warn(
                'Test requires more instruments than '
                'endogenous variables', UserWarning)
            return WaldTestStatistic(0,
                                     'Test is not feasible.',
                                     1,
                                     name='Infeasible test.')

        endog_hat = proj(endog.ndarray, c_[exog.ndarray, instruments.ndarray])
        q = instruments.ndarray[:, :(ninstr - nendog)]
        q_res = annihilate(q, c_[self.model.exog.ndarray, endog_hat])
        test_functions = q_res * self.resids.values[:, None]
        res = _OLS(ones((nobs, 1)), test_functions).fit('unadjusted')

        stat = res.nobs * res.rsquared
        df = ninstr - nendog
        null = 'Model is not overidentified.'
        name = 'Wooldridge\'s score test of overidentification'
        return WaldTestStatistic(stat, null, df, name=name)
Exemple #4
0
    def sargan(self):
        """
        Sargan test of overidentifying restrictions

        Returns
        -------
        t : WaldTestStatistic
            Object containing test statistic, p-value, distribution and null

        Notes
        -----
        Requires more instruments than endogenous variables

        Tests the ratio of re-projected IV regression residual variance to
        variance of the IV residuals.

        .. math ::

          n(1-\hat{\epsilon}^{\prime}M_{Z}\hat{\epsilon}/
          \hat{\epsilon}^{\prime}\hat{\epsilon})\sim\chi_{v}^{2}

        where :math:`M_{z}` is the annihilator matrix where z is the set of
        instruments and :math:`\hat{\epsilon}` are the residuals from the IV
        estimator.  The degree of freedom is the difference between the number
        of instruments and the number of endogenous regressors.

        .. math ::

          v = n_{instr} - n_{exog}
        """
        z = self.model.instruments.ndarray
        nobs, ninstr = z.shape
        nendog = self.model.endog.shape[1]
        name = 'Sargan\'s test of overidentification'
        if ninstr - nendog == 0:
            return InvalidTestStatistic(
                'Test requires more instruments than '
                'endogenous variables.',
                name=name)

        eps = self.resids.values[:, None]
        u = annihilate(eps, self.model._z)
        stat = nobs * (1 - (u.T @ u) / (eps.T @ eps)).squeeze()
        null = 'The model is not overidentified.'

        return WaldTestStatistic(stat, null, ninstr - nendog, name=name)
Exemple #5
0
    def wooldridge_regression(self):
        r"""
        Wooldridge's regression test of exogeneity

        Returns
        -------
        t : WaldTestStatistic
            Object containing test statistic, p-value, distribution and null

        Notes
        -----
        Wooldridge's test examines whether there is correlation between the
        components of the endogenous variables that cannot be explained by
        the instruments and the OLS regression residuals.

        The test is implemented as an OLS where

        .. math ::

          y_i = x_{1i}\beta_i + x_{2i}\beta_2 + \hat{e}_i\gamma + \epsilon_i

        where :math:`x_{1i}` are the exogenous regressors, :math:`x_{2i}` are
        the  endogenous regressors and :math:`\hat{e}_{i}` are the residuals
        from regressing the endogenous variables on the exogenous variables
        and instruments. The null is :math:`\gamma=0` and is implemented
        using a Wald test.  The covariance estimator used in the test is
        identical to the covariance estimator used with ``fit``.
        """
        from linearmodels.iv.model import _OLS
        r = annihilate(self.model.endog.ndarray, self.model._z)
        augx = c_[self.model._x, r]
        mod = _OLS(self.model.dependent, augx)
        res = mod.fit(self.cov_type, **self.cov_config)
        norig = self.model._x.shape[1]
        test_params = res.params.values[norig:]
        test_cov = res.cov.values[norig:, norig:]
        stat = test_params.T @ inv(test_cov) @ test_params
        df = len(test_params)
        null = 'Endogenous variables are exogenous'
        name = 'Wooldridge\'s regression test of exogeneity'
        return WaldTestStatistic(stat, null, df, name=name)