def weight_matrix(self, x, z, eps): """ Parameters ---------- x : ndarray Model regressors (exog and endog), (nobs by nvar) z : ndarray Model instruments (exog and instruments), (nobs by ninstr) eps : ndarray Model errors (nobs by 1) Returns ------- weight : ndarray Covariance of GMM moment conditions. """ nobs, nvar = x.shape ze = z * eps mu = ze.mean(axis=0) if self._center else 0 ze -= mu # TODO: Consider using optimal bandwidth here bw = self._bandwidth if self._bandwidth is not None else nobs - 2 self._bandwidth = bw w = self._kernels[self._kernel](bw, nobs - 1) s = _cov_kernel(ze, w) s *= 1 if not self._debiased else nobs / (nobs - nvar) return s
def weight_matrix(self, x, z, eps): """ Parameters ---------- x : ndarray Model regressors (exog and endog), (nobs by nvar) z : ndarray Model instruments (exog and instruments), (nobs by ninstr) eps : ndarray Model errors (nobs by 1) Returns ------- weight : ndarray Covariance of GMM moment conditions. """ nobs, nvar = x.shape ze = z * eps mu = ze.mean(axis=0) if self._center else 0 ze -= mu if self._orig_bandwidth is None and self._optimal_bw: g = ze / ze.std(0)[None, :] g = g.sum(1) self._bandwidth = kernel_optimal_bandwidth(g, self._kernel) elif self._orig_bandwidth is None: self._bandwidth = nobs - 2 bw = self._bandwidth w = self._kernels[self._kernel](bw, nobs - 1) s = _cov_kernel(ze, w) s *= 1 if not self._debiased else nobs / (nobs - nvar) return s
def _kernel_cov(self, z): nobs = z.shape[0] bw = self.bandwidth kernel = self._kernel kernel = KERNEL_LOOKUP[kernel] weights = kernel(bw, nobs - 1) out = _cov_kernel(z, weights) return (out + out.T) / 2
def _kernel_cov(self, z: NDArray) -> NDArray: nobs = z.shape[0] bw = self.bandwidth kernel = self._kernel assert kernel is not None kernel_estimator = KERNEL_LOOKUP[kernel] weights = kernel_estimator(bw, nobs - 1) out = _cov_kernel(z, weights) return (out + out.T) / 2
def cov(self): """Estimated covariance""" e = self._all_params - self._params.T e = e[np.all(np.isfinite(e), 1)] nobs = e.shape[0] bw = self.bandwidth w = KERNEL_LOOKUP[self._kernel](bw, nobs - 1) cov = _cov_kernel(e, w) return cov / (nobs - int(bool(self._debiased)))
def cov(self) -> NDArray: """Estimated covariance""" e = np.asarray(self._all_params) - self._params.T e = e[np.all(np.isfinite(e), 1)] nobs = e.shape[0] bw = self.bandwidth assert self._kernel is not None w = KERNEL_LOOKUP[self._kernel](bw, nobs - 1) cov = _cov_kernel(e, w) return cov / (nobs - int(bool(self._debiased)))
def s(self): """ Score/moment condition covariance Returns ------- s : ndarray Covariance of the scores or moment conditions """ xe = self._xe nobs = xe.shape[0] bw = self.bandwidth kernel = self._kernel kernel = KERNEL_LOOKUP[kernel] weights = kernel(bw, nobs - 1) out = _cov_kernel(xe, weights) return (out + out.T) / 2
def cov(self): x = self._x nobs = x.shape[0] xpxi = inv(x.T @ x / nobs) eps = self.eps xe = x * eps xe = DataFrame(xe, index=self._time_ids.squeeze()) xe = xe.groupby(level=0).sum() xe.sort_index(inplace=True) xe_nobs = xe.shape[0] bw = self._bandwidth if self._bandwidth is None: bw = int(np.floor(4 * (xe_nobs / 100)**(2 / 9))) w = KERNEL_LOOKUP[self._kernel](bw, xe_nobs - 1) xeex = _cov_kernel(xe.values, w) * (xe_nobs / nobs) xeex *= self._scale out = (xpxi @ xeex @ xpxi) / nobs return (out + out.T) / 2
def w(self, moments): """ Score/moment condition weighting matrix Parameters ---------- moments : ndarray Moment conditions (nobs by nmoments) Returns ------- w : ndarray Weighting matrix computed from moment conditions """ if self._center: moments = moments - moments.mean(0)[None, :] nobs = moments.shape[0] bw = self.bandwidth kernel = self._kernel kernel = KERNEL_LOOKUP[kernel] weights = kernel(bw, nobs - 1) out = _cov_kernel(moments, weights) return inv((out + out.T) / 2.0)
def test_linear_model_parameters(data): mod = LinearFactorModel(data.portfolios, data.factors) res = mod.fit() f = mod.factors.ndarray p = mod.portfolios.ndarray n = f.shape[0] moments = np.zeros( (n, p.shape[1] * (f.shape[1] + 1) + f.shape[1] + p.shape[1])) fc = np.c_[np.ones((n, 1)), f] betas = lstsq(fc, p)[0] eps = p - fc @ betas loc = 0 for i in range(eps.shape[1]): for j in range(fc.shape[1]): moments[:, loc] = eps[:, i] * fc[:, j] loc += 1 b = betas[1:, :].T lam = lstsq(b, p.mean(0)[:, None])[0] pricing_errors = p - (b @ lam).T for i in range(lam.shape[0]): lam_error = (p - (b @ lam).T) @ b[:, [i]] moments[:, loc] = lam_error.squeeze() loc += 1 alphas = pricing_errors.mean(0)[:, None] moments[:, loc:] = pricing_errors - alphas.T mod_moments = mod._moments(eps, b, lam, alphas, pricing_errors) assert_allclose(res.betas, b) assert_allclose(res.risk_premia, lam.squeeze()) assert_allclose(res.alphas, alphas.squeeze()) assert_allclose(moments, mod_moments) m = moments.shape[1] jac = np.eye(m) block1 = p.shape[1] * (f.shape[1] + 1) # 1,1 jac[:block1, :block1] = np.kron(np.eye(p.shape[1]), fc.T @ fc / n) # 2, 1 loc = 0 nport, nf = p.shape[1], f.shape[1] block2 = block1 + nf for i in range(nport): block = np.zeros((nf, nf + 1)) for j in range(nf): # rows for k in range(1, nf + 1): # cols block[j, k] = b[i][j] * lam[k - 1] if j + 1 == k: block[j, k] -= alphas[i] jac[block1:block2, loc:loc + nf + 1] = block loc += nf + 1 # 2, 2 jac[block1:block2, block1:block2] = b.T @ b # 3,1 block = np.zeros((nport, nport * (nf + 1))) row = col = 0 for i in range(nport): for j in range(nf + 1): if j != 0: block[row, col] = lam[j - 1] col += 1 row += 1 jac[-nport:, :(nport * (nf + 1))] = block # 3, 2 jac[-nport:, (nport * (nf + 1)):(nport * (nf + 1)) + nf] = b # 3, 3: already done since eye mod_jac = mod._jacobian(b, lam, alphas) assert_allclose(mod_jac[:block1], jac[:block1]) assert_allclose(mod_jac[block1:block2, :block1], jac[block1:block2, :block1]) assert_allclose(mod_jac[block1:block2, block1:block2], jac[block1:block2, block1:block2]) assert_allclose(mod_jac[block1:block2, block2:], jac[block1:block2, block2:]) assert_allclose(mod_jac[block2:], jac[block2:]) s = moments.T @ moments / (n - (nf + 1)) ginv = np.linalg.inv(jac) cov = ginv @ s @ ginv.T / n order = np.zeros((nport, nf + 1), dtype=np.int64) order[:, 0] = np.arange(block2, block2 + nport) for i in range(nf): order[:, i + 1] = (nf + 1) * np.arange(nport) + (i + 1) order = np.r_[order.ravel(), block1:block2] cov = cov[order][:, order] cov = (cov + cov.T) / 2 assert_allclose(cov, res.cov) acov = cov[:block1:(nf + 1), :block1:(nf + 1)] jstat = float(alphas.T @ np.linalg.pinv(acov) @ alphas) assert_allclose(res.j_statistic.stat, jstat) assert_allclose(res.j_statistic.pval, 1 - stats.chi2(nport - nf).cdf(jstat)) get_all(res) res = LinearFactorModel(data.portfolios, data.factors).fit(cov_type='kernel', debiased=False) std_mom = moments / moments.std(0)[None, :] mom = std_mom.sum(1) bw = kernel_optimal_bandwidth(mom) w = kernel_weight_bartlett(bw, n - 1) s = _cov_kernel(moments, w) cov = ginv @ s @ ginv.T / n cov = cov[order][:, order] cov = (cov + cov.T) / 2 assert_allclose(cov, res.cov)
def _single_cov(self, xe, bw): nobs = xe.shape[0] w = KERNEL_LOOKUP[self._kernel](bw, nobs - 1) return _cov_kernel(xe, w)
def test_cov_kernel(): with pytest.raises(ValueError): _cov_kernel(np.arange(100), 1 - np.arange(101) / 101)
def _single_cov(self, xe: NDArray, bw: float) -> NDArray: nobs = xe.shape[0] w = KERNEL_LOOKUP[self._kernel](bw, nobs - 1) return _cov_kernel(xe, w)