def _draw_W11_Wishart(self, S, W, p, q, n, lambda_, T=1): """Draw from W11 Posterior scaled by the Temperature T: P(W11|W21,T_inv,...)^(T) DEPRECATED Arguments: S {[type]} -- [description] W {[type]} -- [description] p {[type]} -- [description] q {[type]} -- [description] n {[type]} -- [description] lambda_ {[type]} -- [description] Keyword Arguments: T {int} -- [description] (default: {1}) """ s11 = S[0:p, 0:p] s12 = S[0:p, p:(p + q)] s22 = S[p:(p + q), p:(p + q)] s22_lambda_inv = util.cholesky_invert(s22 + np.eye(N=q, M=q) * lambda_) n_ = (3 * n - 2 * q - 1) / 3 Sigma = s11 - s12 @ s22_lambda_inv @ s12.T + np.eye(p) # updated df due to SA cooling scale = T * Sigma df = (n_ - scale.shape[0] - 1) / T + scale.shape[0] + 1 W11 = stats.wishart.rvs(df=df, scale=scale) return (W11)
def draw_W22(self, S, W, p, q, n, lambda_): # W22 = Wishart(n, (S22+lambda*I)^-1) + W21*(W11)^-1 * W12 if (n < q): a = q - n + 1 else: a = 0 s22_lambda_inv = util.cholesky_invert(S[p:(p + q), p:(p + q)] + np.eye(N=q, M=q) * lambda_) tmp = stats.wishart.rvs(df=n + a, scale=s22_lambda_inv) W22 = tmp + \ W[0:p, p:(p+q)].T @ np.linalg.solve(W[0:p, 0:p], W[0:p, p:(p+q)]) return (W22)
def _draw_MGIG_inv(n_, A, B, num_its=10): """Returns the inverse of a MGIG draw via a continued fraction of Wishart draws. (X~MGIG(n'=0.5(n+n0+2p-2), W12*(S22+I)W21, S11+I) and W11 = X^-1) Arguments: n_ {int} -- [Degrees of Freedom] A {ndarray} -- [] B {ndarray} -- [] Keyword Arguments: num_its {int} -- Number of iterations (default: {20}) """ p = A.shape[0] B_inv = util.cholesky_invert(B) eigvals = np.linalg.eigvalsh(A) if (np.sum(eigvals > 1e-5) < p): A = A + (np.min(np.abs(eigvals)) + 0.01) * np.identity(p) A_inv = util.cholesky_invert(A) # draw from W(df = n + n_0 + 3p - 3, (W_12(S_22 + I)W_21)^-1 # As we are only given n' of the MGIG for W_11^-1, we need to express it in terms of this with # df = 2*n' + p - 1 df = 2 * n_ + p - 1 # MGIG dfs my version # df = 2*n_ X = np.zeros(shape=np.shape(A)) Y1 = stats.wishart.rvs(df=df, scale=A_inv, size=num_its) Y2 = stats.wishart.rvs(df=df, scale=B_inv, size=num_its) for i in range(0, num_its): # This would converge to W_11^-1, but we need W_11, so don't do the last inversion # (see notes at 6.2, "Sampling from the MGIG") if (i > 0): X = util.cholesky_invert(X) X = Y1[i] + util.cholesky_invert(Y2[i] + X) return (X)
def _draw_W12(self, S, W, p, q, T_inv, lambda_, T=1): """Draw from W12 Posterior scaled by the Temperature T: P(W12|W11,T_inv,...)^(T) Arguments: T_inv {[type]} -- [description] w11 {[type]} -- [description] s12 {[type]} -- [description] s22 {[type]} -- [description] p {[type]} -- [description] q {[type]} -- [description] T {float} -- SA cooling parameter """ w11 = W[0:p, 0:p] s12 = S[0:p, p:(p + q)] s22 = S[p:(p + q), p:(p + q)] w11_inv = util.cholesky_invert(w11) identity = np.eye(N=q, M=q) # block cholesky decomposition L_T = block_cholesky_BWD(s22 + lambda_ * identity, w11_inv, T_inv) L = L_T.T # method as in Notes, in my opinion a bit clearer than in initial R-code(both are ultimately similar) # NOTE: flatten is column major in numpy, so no need to transpose s12 prior to flattening. v = (s12).flatten() y = linalg.solve_triangular(a=L, b=-v, lower=True) mu = linalg.solve_triangular(a=L_T, b=y) r = sp.random.standard_normal(size=(p * q)) b = linalg.solve_triangular(a=L_T, b=r) # cooling parameter b = b * np.sqrt(T) w12 = (mu + b).reshape(p, q) return (w12)
def __init__(self, X, p, q, lambda_, burnin, NSCAN, DO_COPULA=True, plugin_threshold=40, TRUE_INVCOV=None, gig_seed=4321, use_w=False, Z_save_each=-1): """Set options, data and initial values for the BMB. Arguments: X {ndarray} -- Data p {int} -- Number of query variables q {int} -- number of non-query variables burnin {int} -- Burnin of MCMC sampler lambda_ {float} -- Sparsity hyperparameter Keyword Arguments: NSCAN {int} -- Number of MCMC iterations (default: {1000}) plugin_threshold {int} -- (default: {40}) TRUE_INVCOV {ndarray} -- If available, the true inverse covariance matrix. Used for diagnostics. (default: {None}) DO_COPULA {bool} -- Wrap semi-parametric copula around the Gibbs sampler (default: {False}) """ assert (np.shape(X)[1] == p + q) assert (q > 0 and p > 0 and lambda_ > 0) assert (burnin > 0 and NSCAN > 0) self.DO_COPULA = DO_COPULA self.TRUE_INVCOV = TRUE_INVCOV self.p = p self.q = q self.num_vars = self.p + self.q self.n = np.shape(X)[0] self.use_w = use_w self.lambda_ = lambda_ self.NSCAN = NSCAN self.burnin = burnin self.X = X self.gig_seed = gig_seed self.GIG = gig.GIG(gig_seed) # initialize S, W and T.inv self.T_inv = np.random.normal(size=p * q).reshape(p, q) if (DO_COPULA): self.Z, self.S = util.cov_from_normscores(X, scaled=False, fill_na=True) else: self.Z, self.S = util.cov_from_normscores(X, scaled=True, fill_na=False) self.S = self.S * self.n self.W0 = np.eye(p + q) * self.lambda_ if (self.n < self.S.shape[0]): a = self.S.shape[0] - self.n + 1 else: a = 0 self.W = stats.wishart.rvs(df=self.n + a, scale=util.cholesky_invert(self.S + self.W0)) # keep track of intermediate results self.W_list = np.zeros((NSCAN, self.W.shape[0], self.W.shape[1])) self.W_list_burnin = self.W_list[0:burnin, :, :] self.W_list_acc = self.W_list[burnin:NSCAN, :, :] self.T_inv_list = np.zeros((NSCAN, p, q)) self.T_inv_list_acc = self.T_inv_list[burnin:NSCAN, :, :] self.Z_save_each = Z_save_each if (self.Z_save_each > 0): self.Z_saves = np.zeros((np.floor_divide( (self.NSCAN - self.burnin - 1), self.Z_save_each), self.Z.shape[0], self.Z.shape[1])) self.Z_mean = np.zeros((self.Z.shape[0], self.Z.shape[1])) self.Z_ssd = np.zeros((self.Z.shape[0], self.Z.shape[1])) if (DO_COPULA): # get the levels and number of levels # for the copula self.R = BMB.calc_R(self.X) self.Rlevels = np.amax(self.R, axis=0) self.plugin_marginal = np.apply_along_axis( lambda col: np.unique(col).shape[0] > plugin_threshold, 0, X) * 1