def cov(self) -> NDArray: """Estimated covariance""" x = self._x nobs = x.shape[0] xpxi = inv(x.T @ x / nobs) eps = self.eps xe = x * eps if self._clusters.ndim == 1: xeex = cov_cluster(xe, self._clusters) if self._group_debias: xeex *= group_debias_coefficient(self._clusters) else: clusters0 = self._clusters[:, 0] clusters1 = self._clusters[:, 1] xeex0 = cov_cluster(xe, clusters0) xeex1 = cov_cluster(xe, clusters1) clusters01 = cluster_union(self._clusters) xeex01 = cov_cluster(xe, clusters01) if self._group_debias: xeex0 *= group_debias_coefficient(clusters0) xeex1 *= group_debias_coefficient(clusters1) xeex01 *= group_debias_coefficient(clusters01) xeex = xeex0 + xeex1 - xeex01 xeex *= self._scale out = (xpxi @ xeex @ xpxi) / nobs return (out + out.T) / 2
def _xeex(self) -> NDArray: if self._clusters.shape[1] == 0: # Heteroskedastic but not clustered return super()._xeex() elif self._clusters.shape[1] == 1: s = cov_cluster(self._moments, self._clusters[:, 0]) if self._group_debias: s *= group_debias_coefficient(self._clusters[:, 0]) return s else: xeex0 = cov_cluster(self._moments, self._clusters[:, 0]) xeex1 = cov_cluster(self._moments, self._clusters[:, 1]) clusters01 = cluster_union(self._clusters) xeex01 = cov_cluster(self._moments, clusters01) if self._group_debias: xeex0 *= group_debias_coefficient(self._clusters[:, 0]) xeex1 *= group_debias_coefficient(self._clusters[:, 1]) xeex01 *= group_debias_coefficient(clusters01) return xeex0 + xeex1 - xeex01