def test_mvt_pdf(self): cov3 = self.cov3 mu3 = self.mu3 mvt = MVT((0,0), 1, 5) assert_almost_equal(mvt.logpdf(np.array([0.,0.])), -1.837877066409345, decimal=15) assert_almost_equal(mvt.pdf(np.array([0.,0.])), 0.1591549430918953, decimal=15) mvt.logpdf(np.array([1.,1.]))-(-3.01552989458359) mvt1 = MVT((0,0), 1, 1) mvt1.logpdf(np.array([1.,1.]))-(-3.48579549941151) #decimal=16 rvs = mvt.rvs(100000) assert_almost_equal(np.cov(rvs, rowvar=0), mvt.cov, decimal=1) mvt31 = MVT(mu3, cov3, 1) assert_almost_equal(mvt31.pdf(cov3), [0.0007276818698165781, 0.0009980625182293658, 0.0027661422056214652], decimal=17) mvt = MVT(mu3, cov3, 3) assert_almost_equal(mvt.pdf(cov3), [0.000863777424247410, 0.001277510788307594, 0.004156314279452241], decimal=17)
def test_mvt_pdf(self): cov3 = self.cov3 mu3 = self.mu3 mvt = MVT((0, 0), 1, 5) assert_almost_equal(mvt.logpdf(np.array([0., 0.])), -1.837877066409345, decimal=15) assert_almost_equal(mvt.pdf(np.array([0., 0.])), 0.1591549430918953, decimal=15) mvt.logpdf(np.array([1., 1.])) - (-3.01552989458359) mvt1 = MVT((0, 0), 1, 1) mvt1.logpdf(np.array([1., 1.])) - (-3.48579549941151) #decimal=16 rvs = mvt.rvs(100000) assert_almost_equal(np.cov(rvs, rowvar=0), mvt.cov, decimal=1) mvt31 = MVT(mu3, cov3, 1) assert_almost_equal(mvt31.pdf(cov3), [ 0.0007276818698165781, 0.0009980625182293658, 0.0027661422056214652 ], decimal=17) mvt = MVT(mu3, cov3, 3) assert_almost_equal( mvt.pdf(cov3), [0.000863777424247410, 0.001277510788307594, 0.004156314279452241], decimal=17)
class Diagnostic: R"""A class for quickly testing model checking methods discussed in Bastos & O'Hagan. """ def __init__(self, mean, cov, df=None, random_state=1): self.mean = mean self.cov = cov self.sd = sd = np.sqrt(np.diag(cov)) if df is None: self.dist = stats.multivariate_normal(mean=mean, cov=cov) self.udist = stats.norm(loc=mean, scale=sd) self.std_udist = stats.norm(loc=0., scale=1.) else: sigma = cov * (df - 2) / df self.dist = MVT(mean=mean, sigma=sigma, df=df) self.udist = stats.t(loc=mean, scale=sd, df=df) self.std_udist = stats.t(loc=0., scale=1., df=df) self.dist.random_state = random_state self.udist.random_state = random_state self.std_udist.random_state = random_state self._chol = cholesky(self.cov) self._pchol = pivoted_cholesky(self.cov) e, v = np.linalg.eigh(self.cov) # To match Bastos and O'Hagan definition # i.e., eigenvalues ordered from largest to smallest e, v = e[::-1], v[:, ::-1] ee = np.diag(np.sqrt(e)) self._eig = (v @ ee) # self._eig = ee @ v def samples(self, n): return self.dist.rvs(n).T def individual_errors(self, y): R"""Computes the scaled individual errors diagnostic .. math:: D_I(y) = \frac{y-m}{\sigma} Parameters ---------- y : array, shape = (n_samples, n_curves) Returns ------- array : shape = (n_samples, n_curves) """ return ((y.T - self.mean) / np.sqrt(np.diag(self.cov))).T def cholesky_errors(self, y): return cholesky_errors(y.T, self.mean, self._chol).T def pivoted_cholesky_errors(self, y): return solve(self._pchol, (y.T - self.mean).T) def eigen_errors(self, y): return solve(self._eig, (y.T - self.mean).T) def chi2(self, y): return np.sum(self.individual_errors(y), axis=0) def md_squared(self, y): R"""The squared Mahalanobis distance""" return mahalanobis(y.T, self.mean, self._chol)**2 def kl(self, mean, cov): R"""The Kullbeck-Leibler divergence""" m1, c1, chol1 = self.mean, self.cov, self._chol m0, c0 = mean, cov tr = np.trace(cho_solve((chol1, True), c0)) dist = self.md_squared(m0) k = c1.shape[-1] logs = 2 * np.sum(np.log(np.diag(c1))) - np.linalg.slogdet(c0)[-1] return 0.5 * (tr + dist - k + logs) def credible_interval(self, y, intervals): """The credible interval diagnostic. Parameters ---------- y : (n_c, d) shaped array intervals : 1d array The credible intervals at which to perform the test """ lower, upper = self.udist.interval(np.atleast_2d(intervals).T) def diagnostic(data_, lower_, upper_): indicator = (lower_ < data_) & (data_ < upper_ ) # 1 if in, 0 if out return np.average(indicator, axis=1) # The diagnostic dci = np.apply_along_axis(diagnostic, axis=1, arr=np.atleast_2d(y).T, lower_=lower, upper_=upper) dci = np.squeeze(dci) return dci @staticmethod def variogram(X, y, bin_bounds): v = VariogramFourthRoot(X, y, bin_bounds) bin_locations = v.bin_locations gamma, lower, upper = v.compute(rt_scale=False) return v, bin_locations, gamma, lower, upper