def test_inv_matrix_sqrt(data): y, x, sigma = data k = sigma.shape[0] sigma_m12 = inv_matrix_sqrt(sigma) assert_allclose(sigma_m12 - sigma_m12.T, np.zeros((k, k))) assert_allclose(np.linalg.inv(sigma_m12 @ sigma_m12), sigma) assert_allclose(sigma_m12 @ sigma @ sigma_m12, np.eye(k), atol=1e-14)
def test_ols_against_gls(data): mod = SUR(data) res = mod.fit(method='gls') sigma = res.sigma sigma_m12 = inv_matrix_sqrt(sigma) key = list(data.keys())[0] if isinstance(data[key], Mapping): y = [data[key]['dependent'] for key in data] x = [data[key]['exog'] for key in data] try: w = [data[key]['weights'] for key in data] except KeyError: w = [np.ones_like(data[key]['dependent']) for key in data] else: y = [data[key][0] for key in data] x = [data[key][1] for key in data] try: w = [data[key][2] for key in data] except IndexError: w = [np.ones_like(data[key][0]) for key in data] wy = [_y * np.sqrt(_w / _w.mean()) for _y, _w in zip(y, w)] wx = [_x * np.sqrt(_w / _w.mean()) for _x, _w in zip(x, w)] wy = blocked_column_product(wy, sigma_m12) wx = blocked_diag_product(wx, sigma_m12) ols_res = OLS(wy, wx).fit(debiased=False) assert_allclose(res.params, ols_res.params)
def _cov(self, gls): x = self._x eps = self._eps k = len(x) sigma = self.sigma weights = inv(sigma) if gls else eye(k) xpx = blocked_inner_prod(x, weights) weights = inv_matrix_sqrt(sigma) if gls else eye(k) bigx = blocked_diag_product(x, weights) nobs = eps.shape[0] e = eps.T.ravel()[:, None] bigxe = bigx * e m = bigx.shape[1] xeex = zeros((m, m)) for i in range(nobs): xe = bigxe[i::nobs].sum(0)[None, :] xeex += xe.T @ xe if self._constraints is None: xpxi = inv(xpx) cov = xpxi @ xeex @ xpxi else: cons = self._constraints xpx = cons.t.T @ xpx @ cons.t xpxi = inv(xpx) xeex = cons.t.T @ xeex @ cons.t cov = cons.t @ (xpxi @ xeex @ xpxi) @ cons.t.T cov = (cov + cov.T) / 2 return cov
def test_ols_against_gls(data): mod = SUR(data) res = mod.fit(method="gls") if isinstance(data[list(data.keys())[0]], dict): predictions = mod.predict(res.params, equations=data) predictions2 = mod.predict(np.asarray(res.params)[:, None], equations=data) assert_allclose(predictions, predictions2) sigma = res.sigma sigma_m12 = inv_matrix_sqrt(np.asarray(sigma)) key = list(data.keys())[0] if isinstance(data[key], Mapping): y = [data[key]["dependent"] for key in data] x = [data[key]["exog"] for key in data] try: w = [data[key]["weights"] for key in data] except KeyError: w = [np.ones_like(data[key]["dependent"]) for key in data] else: y = [data[key][0] for key in data] x = [data[key][1] for key in data] try: w = [data[key][2] for key in data] except IndexError: w = [np.ones_like(data[key][0]) for key in data] wy = [_y * np.sqrt(_w / _w.mean()) for _y, _w in zip(y, w)] wx = [_x * np.sqrt(_w / _w.mean()) for _x, _w in zip(x, w)] wy = blocked_column_product(wy, sigma_m12) wx = blocked_diag_product(wx, sigma_m12) ols_res = OLS(wy, wx).fit(debiased=False) assert_allclose(res.params, ols_res.params)
def _gls_estimate(self, eps, nobs, total_cols, ci, full_cov, debiased): """Core estimation routine for iterative GLS""" wx, wy = self._wx, self._wy sigma = self._sigma if sigma is None: sigma = eps.T @ eps / nobs sigma *= self._sigma_scale(debiased) if not full_cov: sigma = diag(diag(sigma)) sigma_inv = inv(sigma) k = len(wy) if self.constraints is not None: cons = self.constraints sigma_m12 = inv_matrix_sqrt(sigma) x = blocked_diag_product(wx, sigma_m12) y = blocked_column_product(wy, sigma_m12) xt = x @ cons.t xpx = xt.T @ xt xpy = xt.T @ (y - x @ cons.a.T) paramsc = solve(xpx, xpy) params = cons.t @ paramsc + cons.a.T else: xpx = blocked_inner_prod(wx, sigma_inv) xpy = zeros((total_cols, 1)) for i in range(k): sy = zeros((nobs, 1)) for j in range(k): sy += sigma_inv[i, j] * wy[j] xpy[ci[i]:ci[i + 1]] = wx[i].T @ sy params = solve(xpx, xpy) beta = params loc = 0 for j in range(k): _wx = wx[j] _wy = wy[j] kx = _wx.shape[1] eps[:, [j]] = _wy - _wx @ beta[loc:loc + kx] loc += kx return beta, eps, sigma
def fit(self, *, method=None, full_cov=True, iterate=False, iter_limit=100, tol=1e-6, cov_type='robust', **cov_config): """ Estimate model parameters Parameters ---------- method : {None, 'gls', 'ols'} Estimation method. Default auto selects based on regressors, using OLS only if all regressors are identical. The other two arguments force the use of GLS or OLS. full_cov : bool Flag indicating whether to utilize information in correlations when estimating the model with GLS iterate : bool Flag indicating to iterate GLS until convergence of iter limit iterations have been completed iter_limit : int Maximum number of iterations for iterative GLS tol : float Tolerance to use when checking for convergence in iterative GLS cov_type : str Name of covariance estimator. Valid options are * 'unadjusted', 'homoskedastic' - Classic covariance estimator * 'robust', 'heteroskedastic' - Heteroskedasticit robust covariance estimator **cov_config Additional parameters to pass to covariance estimator. All estimators support debiased which employs a small-sample adjustment Returns ------- results : SURResults Estimation results """ cov_type = cov_type.lower() if cov_type not in ('unadjusted', 'robust', 'homoskedastic', 'heteroskedastic'): raise ValueError('Unknown cov_type: {0}'.format(cov_type)) cov_type = 'unadjusted' if cov_type in ('unadjusted', 'homoskedastic') else 'robust' k = len(self._dependent) col_sizes = [0] + list(map(lambda v: v.ndarray.shape[1], self._exog)) col_idx = cumsum(col_sizes) total_cols = col_idx[-1] beta, eps = self._multivariate_ls_fit() nobs = eps.shape[0] debiased = cov_config.get('debiased', False) full_sigma = sigma = (eps.T @ eps / nobs) * self._sigma_scale(debiased) if (self._common_exog and method is None and self._constraints is None) or method == 'ols': return self._multivariate_ls_finalize(beta, eps, sigma, cov_type, **cov_config) beta_hist = [beta] nobs = eps.shape[0] iter_count = 0 delta = inf while ((iter_count < iter_limit and iterate) or iter_count == 0) and delta >= tol: beta, eps, sigma = self._gls_estimate(eps, nobs, total_cols, col_idx, full_cov, debiased) beta_hist.append(beta) delta = beta_hist[-1] - beta_hist[-2] delta = sqrt(np.mean(delta ** 2)) iter_count += 1 sigma_m12 = inv_matrix_sqrt(sigma) wy = blocked_column_product(self._wy, sigma_m12) wx = blocked_diag_product(self._wx, sigma_m12) gls_eps = wy - wx @ beta y = blocked_column_product(self._y, eye(k)) x = blocked_diag_product(self._x, eye(k)) eps = y - x @ beta return self._gls_finalize(beta, sigma, full_sigma, gls_eps, eps, cov_type, iter_count, **cov_config)