Up

A Simple Example of Python Script for WAIC

 

WAIC is a statistic, which assesses model fit. WAIC can be calculated by the following formula (Gelman et al., 2014, p. 174).

 is given by the following formula (Gelman et al. 2014, p. 169).

Gelman et al., (2014, p. 173) explain two formulas for , and recommend the following one  (p. 174).

A simple Python script to calculate WAIC in Listing 1 was developed, using the example in Gelman et al. 2014, p. 177. The data in the script was obtained by deleting the last row from the data file downloaded from the website explained in Gelman et al. 2021, p. XIII).

WAIC is calculated by the following code.

 

for i in range(n):

    for s in range(S):

        p_y_theta[i][s] = ss.norm.pdf(y[i], a[s] + b[s] * x[i], sgm[s])

 

lppd = np.sum(np.log(np.mean(p_y_theta, axis = 1)))

pWAIC2 = np.sum(np.var(np.log(p_y_theta), axis = 1, ddof = 1))

WAIC = -2 * (lppd - pWAIC2)

 

When you run the script in Listing 1, you will get ouput like this:

 

Inference for Stan model: anon_model_105ce2197a3e94689c866d927437a11f.

4 chains, each with iter=2000; warmup=1000; thin=1;

post-warmup draws per chain=1000, total post-warmup draws=4000.

 

          mean se_mean     sd   2.5%    25%    50%    75%  97.5%  n_eff   Rhat

a        45.88    0.05   1.89  42.22  44.68  45.85  47.06  49.78   1433    1.0

b         3.15    0.02   0.79   1.54   2.67   3.16   3.67   4.74   1394    1.0

log_sgm   1.38  4.9e-3    0.2   1.02   1.24   1.36    1.5   1.81   1714    1.0

sgm       4.05    0.02   0.85   2.76   3.44   3.91    4.5    6.1   1663    1.0

lp__    -28.18    0.04   1.37 -31.79  -28.8  -27.8 -27.18 -26.63   1153    1.0

 

Samples were drawn using NUTS at Tue Sep 14 10:04:00 2021.

For each parameter, n_eff is a crude measure of effective sample size,

and Rhat is the potential scale reduction factor on split chains (at

convergence, Rhat=1).

 

WAIC = 87.06883542066456

 

Actual output depends on the sample by MCMC sampling.

 

 

References

Gelman, A., Carlin, J. B., Stern, H. S., Dunson, J. B., Vehtari, A., & Rubin, D. B. (2014). Bayesian Data Analysis, 3rd ed. CRC Press.

Gelman, A., Hill, J., & Vehtari, A. (2021). Regression and Other Stories. Cambridge University Press.

 

 

Listing 1.

 

"""     

                    Yasuharu Okamoto

"""

import numpy as np

import pystan

import scipy.stats as ss

 

#

#    Simple Regression Model. See Gelman et al., 2014, p. 177

#

stan_code = """

    data {

        int N;

        real y[N];

        real x[N];

    }

    parameters {

        real a;

        real b;

        real log_sgm;

    }

    transformed parameters {

        real sgm;

        sgm = exp(log_sgm);

    }

    model {

        for (i in 1:N) {

            y[i] ~ normal(a + b*x[i], sgm);

        }

    }

"""

#

#       Data. See Gelman et al., 2014. p. 165

#

xy = [

[44.6, 2.4],

[57.76, 2.89],

[49.91, 0.85],

[61.34, 4.21],

[49.6, 3.02],

[61.79, 3.62],

[48.95, 1.08],

[44.7, -0.39],

[59.17, 3.86],

[53.94, 2.27],

[46.55, 0.38],

[54.74, 1.04],

[50.27, 2.36],

[51.24, 1.72],

[46.32, 0.1]]

x = np.array(xy).T[1]

y = np.array(xy).T[0]

 

sm = pystan.StanModel(model_code = stan_code) 

 

Data = {'N':len(y), 'y':y, 'x':x}

 

fit = sm.sampling(data = Data, n_jobs = 1)

 

print(fit)

 

n = len(y)

a = fit['a']

b = fit['b']

sgm = fit['sgm']

S = len(a)

p_y_theta = np.empty((n, S))   #   p(y_i|theta^is)

 

for i in range(n):

    for s in range(S):

        p_y_theta[i][s] = ss.norm.pdf(y[i], a[s] + b[s] * x[i], sgm[s])

 

lppd = np.sum(np.log(np.mean(p_y_theta, axis = 1)))

pWAIC2 = np.sum(np.var(np.log(p_y_theta), axis = 1, ddof = 1))

WAIC = -2 * (lppd - pWAIC2)

print('\nWAIC =', WAIC)

 

 

Up