def _compute_betas(y, x): """ compute MLE coefficients using iwls routine Methods: p189, Iteratively (Re)weighted Least Squares (IWLS), Fotheringham, A. S., Brunsdon, C., & Charlton, M. (2002). Geographically weighted regression: the analysis of spatially varying relationships. """ xT = x.T xtx = spdot(xT, x) xtx_inv = la.inv(xtx) xtx_inv = sp.csr_matrix(xtx_inv) xTy = spdot(xT, y, array_out=False) betas = spdot(xtx_inv, xTy) return betas
def logp_lambda_prec(state, val): """ Compute the log likelihood of the upper-level spatial correlation parameter using sparse operations and the precision matrix, rather than the covariance matrix. """ st = state if (val < st.Lambda_min) or (val > st.Lambda_max): return np.array([-np.inf]) PsiLambdai = st.Psi_2i(val, st.M, sparse=True) logdet = -splogdet(PsiLambdai) #negative because precision kernel = spdot(spdot(st.Alphas.T, PsiLambdai), st.Alphas) / st.Tau2 return -.5 * logdet - .5 * kernel + st.Log_Lambda0(val)
def logp_rho_prec(state, val): """ This computes the logp of the spatial parameter using the precision, rather than the covariance. This results in fewer matrix operations in the case of a SE formulation, but not in an SMA formulation. """ st = state #must truncate in logp otherwise sampling gets unstable if (val < st.Rho_min) or (val > st.Rho_max): return np.array([-np.inf]) PsiRhoi = st.Psi_1i(val, st.W, sparse=True) logdet = splogdet(PsiRhoi) eta = st.Y - st.XBetas - st.DeltaAlphas kernel = spdot(spdot(eta.T, PsiRhoi), eta) / st.Sigma2 return .5*logdet -.5 * kernel + st.Log_Rho0(val) #since precision, no negative on ld
def logp_lambda_prec(state, val): """ The logp for upper level spatial parameters in this case has the same form as a multivariate normal distribution, sampled over the variance matrix, rather than over Y. """ st = state #must truncate if (val < st.Lambda_min) or (val > st.Lambda_max): return np.array([-np.inf]) PsiLambdai = st.Psi_2i(val, st.M) logdet = splogdet(PsiLambdai) kernel = spdot(spdot(st.Alphas.T, PsiLambdai), st.Alphas) / st.Tau2 return .5*logdet - .5*kernel + st.Log_Lambda0(val)
def logp_rho_prec(state, val): """ Compute the log likelihood of the lower-level spatial correlation parameter using sparse operations and the precision matrix, rather than the covariance matrix. """ st = state if (val < st.Rho_min) or (val > st.Rho_max): return np.array([-np.inf]) PsiRhoi = st.Psi_1i(val, st.W, sparse=True) logdet = -splogdet(PsiRhoi) eta = st.Y - st.XBetas - st.DeltaAlphas kernel = spdot(spdot(eta.T, PsiRhoi), eta) / st.Sigma2 return -.5 * logdet - .5 * kernel + st.Log_Rho0(val)
def logp_rho_prec(state, val): """ This computes the logp of the spatial parameter using the precision, rather than the covariance. This results in fewer matrix operations in the case of a SE formulation, but not in an SMA formulation. """ st = state #must truncate in logp otherwise sampling gets unstable if (val < st.Rho_min) or (val > st.Rho_max): return np.array([-np.inf]) PsiRhoi = st.Psi_1i(val, st.W, sparse=True) logdet = splogdet(PsiRhoi) eta = st.Y - st.XBetas - st.DeltaAlphas kernel = spdot(spdot(eta.T, PsiRhoi), eta) / st.Sigma2 return .5 * logdet - .5 * kernel + st.Log_Rho0( val) #since precision, no negative on ld
def logp_lambda_prec(state, val): """ The logp for upper level spatial parameters in this case has the same form as a multivariate normal distribution, sampled over the variance matrix, rather than over Y. """ st = state #must truncate if (val < st.Lambda_min) or (val > st.Lambda_max): return np.array([-np.inf]) PsiLambdai = st.Psi_2i(val, st.M) logdet = splogdet(PsiLambdai) kernel = spdot(spdot(st.Alphas.T, PsiLambdai), st.Alphas) / st.Tau2 return .5 * logdet - .5 * kernel + st.Log_Lambda0(val)
def logp_rho_cov(state, val): """ The logp for lower-level spatial parameters in this case has the same form as a multivariate normal distribution, sampled over the variance matrix, rather than over y. """ st = state #must truncate in logp otherwise sampling gets unstable if (val < st.Rho_min) or (val > st.Rho_max): return np.array([-np.inf]) PsiRho = st.Psi_1(val, st.W) logdet = splogdet(PsiRho) eta = st.Y - st.XBetas - st.DeltaAlphas kernel = spdot(eta.T, spsolve(PsiRho, eta)) / st.Sigma2 return -.5 * logdet - .5 * kernel + st.Log_Rho0(val)
def logp_rho_cov(state, val): """ The logp for lower-level spatial parameters in this case has the same form as a multivariate normal distribution, sampled over the variance matrix, rather than over y. """ st = state #must truncate in logp otherwise sampling gets unstable if (val < st.Rho_min) or (val > st.Rho_max): return np.array([-np.inf]) PsiRho = st.Psi_1(val, st.W) logdet = splogdet(PsiRho) eta = st.Y - st.XBetas - st.DeltaAlphas kernel = spdot(eta.T, spsolve(PsiRho, eta)) / st.Sigma2 return -.5*logdet -.5 * kernel + st.Log_Rho0(val)
def normalized_cov_params(self): return la.inv(spdot(self.w.T, self.w))
def _iteration(self): st = self.state ### Sample the Beta conditional posterior ### P(beta | . ) \propto L(Y|.) \dot P(\beta) ### is ### N(Sb, S) where ### S = (X' Sigma^{-1}_Y X + S_0^{-1})^{-1} ### b = X' Sigma^{-1}_Y (Y - Delta Alphas) + S^{-1}\mu_0 covm_update = st.X.T.dot(st.X) / st.Sigma2 covm_update += st.Betas_cov0i covm_update = la.inv(covm_update) resids = st.Y - st.Delta.dot(st.Alphas) XtSresids = st.X.T.dot(resids) / st.Sigma2 mean_update = XtSresids + st.Betas_cov0i.dot(st.Betas_mean0) mean_update = np.dot(covm_update, mean_update) st.Betas = chol_mvn(mean_update, covm_update) st.XBetas = np.dot(st.X, st.Betas) ### Sample the Random Effect conditional posterior ### P( Alpha | . ) \propto L(Y|.) \dot P(Alpha | \lambda, Tau2) ### \dot P(Tau2) \dot P(\lambda) ### is ### N(Sb, S) ### Where ### S = (Delta'Sigma_Y^{-1}Delta + Sigma_Alpha^{-1})^{-1} ### b = (Delta'Sigma_Y^{-1}(Y - X\beta) + 0) covm_update = st.Delta.T.dot(st.Delta) / st.Sigma2 covm_update += st.PsiLambdai / st.Tau2 covm_update = np.asarray(covm_update) covm_update = la.inv(covm_update) resids = st.Y - st.XBetas mean_update = st.Delta.T.dot(resids) / st.Sigma2 mean_update = np.dot(covm_update, mean_update) mean_update = np.asarray(mean_update) st.Alphas = chol_mvn(mean_update, covm_update) st.DeltaAlphas = np.dot(st.Delta, st.Alphas) ### Sample the Random Effect aspatial variance parameter ### P(Tau2 | .) \propto L(Y|.) \dot P(\Alpha | \lambda, Tau2) ### \dot P(Tau2) \dot P(\lambda) ### is ### IG(J/2 + a0, u'(\Psi(\lambda))^{-1}u * .5 + b0) bn = spdot(st.Alphas.T, spdot(st.PsiLambdai, st.Alphas)) * .5 + st.Tau2_b0 st.Tau2 = stats.invgamma.rvs(st.Tau2_an, scale=bn) ### Sample the response aspatial variance parameter ### P(Sigma2 | . ) \propto L(Y | .) \dot P(Sigma2) ### is ### IG(N/2 + a0, eta'Psi(\rho)^{-1}eta * .5 + b0) ### Where eta is the linear predictor, Y - X\beta + \DeltaAlphas eta = st.Y - st.XBetas - st.DeltaAlphas bn = eta.T.dot(eta) * .5 + st.Sigma2_b0 st.Sigma2 = stats.invgamma.rvs(st.Sigma2_an, scale=bn) ### P(Psi(\rho) | . ) \propto L(Y | .) \dot P(\rho) ### is ### |Psi(rho)|^{-1/2} exp(1/2(eta'Psi(rho)^{-1}eta * Sigma2^{-1})) * 1/(emax-emin) st.Lambda = self.configs.Lambda(st) st.PsiLambdai = st.Psi_2i(st.Lambda, st.M)
def iwls(y, x, family, offset, y_fix, ini_betas=None, tol=1.0e-8, max_iter=200, wi=None): """ Iteratively re-weighted least squares estimation routine Parameters ---------- y : array n*1, dependent variable x : array n*k, designs matrix of k independent variables family : family object probability models: Gaussian, Poisson, or Binomial offset : array n*1, the offset variable for each observation. y_fix : array n*1, the fixed intercept value of y for each observation ini_betas : array 1*k, starting values for the k betas within the iteratively weighted least squares routine tol : float tolerance for estimation convergence max_iter : integer maximum number of iterations if convergence not met wi : array n*1, weights to transform observations from location i in GWR Returns ------- betas : array k*1, estimated coefficients mu : array n*1, predicted y values wx : array n*1, final weights used for iwls for GLM n_iter : integer number of iterations that when iwls algorithm terminates w : array n*1, final weights used for iwls for GWR z : array iwls throughput v : array iwls throughput xtx_inv_xt : array iwls throughout to compute GWR hat matrix [X'X]^-1 X' """ n_iter = 0 diff = 1.0e6 if ini_betas is None: betas = np.zeros((x.shape[1], 1), np.float) else: betas = ini_betas if isinstance(family, Binomial): y = family.link._clean(y) if isinstance(family, Poisson): y_off = y / offset y_off = family.starting_mu(y_off) v = family.predict(y_off) mu = family.starting_mu(y) else: mu = family.starting_mu(y) v = family.predict(mu) while diff > tol and n_iter < max_iter: n_iter += 1 w = family.weights(mu) z = v + (family.link.deriv(mu) * (y - mu)) w = np.sqrt(w) if not isinstance(x, np.ndarray): w = sp.csr_matrix(w) z = sp.csr_matrix(z) wx = spmultiply(x, w, array_out=False) wz = spmultiply(z, w, array_out=False) if wi is None: n_betas = _compute_betas(wz, wx) else: n_betas, xtx_inv_xt = _compute_betas_gwr(wz, wx, wi) v = spdot(x, n_betas) mu = family.fitted(v) if isinstance(family, Poisson): mu = mu * offset diff = min(abs(n_betas - betas)) betas = n_betas if wi is None: return betas, mu, wx, n_iter else: return betas, mu, v, w, z, xtx_inv_xt, n_iter