ArviZ Quickstart

In [1]:
%matplotlib inline
import arviz as az
import numpy as np

# ArviZ ships with style sheets!
az.style.use('arviz-darkgrid')

Get started with plotting

ArviZ is designed to be used with libraries like PyStan and PyMC3, but works fine with raw numpy arrays.

In [2]:
az.plot_posterior(np.random.randn(100_000));
../_images/notebooks_Introduction_3_0.png

Plotting a dictionary of arrays, ArviZ will interpret each key as the name of a different random variable. Each row of an array is treated as an independent series of draws from the variable, called a chain. Below, we have 10 chains of 50 draws each for four different distributions.

In [3]:
size = (10, 50)
az.plot_forest({
    'normal': np.random.randn(*size),
    'gumbel': np.random.gumbel(size=size),
    'student t': np.random.standard_t(df=6, size=size),
    'exponential': np.random.exponential(size=size)
});
../_images/notebooks_Introduction_5_0.png

Plotting with PyMC3 objects

ArviZ is designed to work well with high dimensional, labelled data. Consider the eight schools model, which roughly tries to measure the effectiveness of SAT classes at eight different schools. To show off ArviZ’s labelling, I give the schools the names of a different eight schools.

This model is small enough to write down, is hierarchical, uses labelling, and a centered parameterization causes divergences (which are interesting for illustration):

In [4]:
import pymc3 as pm

J = 8
y = np.array([28.,  8., -3.,  7., -1.,  1., 18., 12.])
sigma = np.array([15., 10., 16., 11.,  9., 11., 10., 18.])
schools = np.array(['Choate', 'Deerfield', 'Phillips Andover', 'Phillips Exeter',
                    'Hotchkiss', 'Lawrenceville', "St. Paul's", 'Mt. Hermon'])


with pm.Model() as centered_eight:
    mu = pm.Normal('mu', mu=0, sd=5)
    tau = pm.HalfCauchy('tau', beta=5)
    theta = pm.Normal('theta', mu=mu, sd=tau, shape=J)
    obs = pm.Normal('obs', mu=theta, sd=sigma, observed=y)

    # This pattern is useful in PyMC3
    prior = pm.sample_prior_predictive()
    centered_eight_trace = pm.sample()
    posterior_predictive = pm.sample_posterior_predictive(centered_eight_trace)
Auto-assigning NUTS sampler...
Initializing NUTS using jitter+adapt_diag...
Multiprocess sampling (4 chains in 4 jobs)
NUTS: [theta, tau, mu]
Sampling 4 chains: 100%|██████████| 4000/4000 [00:03<00:00, 1291.48draws/s]
There were 12 divergences after tuning. Increase `target_accept` or reparameterize.
The acceptance probability does not match the target. It is 0.6803070156848937, but should be close to 0.8. Try to increase the number of tuning steps.
There were 4 divergences after tuning. Increase `target_accept` or reparameterize.
There were 2 divergences after tuning. Increase `target_accept` or reparameterize.
There were 13 divergences after tuning. Increase `target_accept` or reparameterize.
The acceptance probability does not match the target. It is 0.6862081649203211, but should be close to 0.8. Try to increase the number of tuning steps.
The estimated number of effective samples is smaller than 200 for some parameters.
100%|██████████| 500/500 [00:00<00:00, 4097.94it/s]

Most ArviZ functions work fine with trace objects from PyMC3:

In [5]:
az.plot_autocorr(centered_eight_trace, var_names=['mu', 'tau']);
../_images/notebooks_Introduction_9_0.png

Convert to InferenceData

For much more powerful querying, analysis and plotting, we can use built-in ArviZ utilities to convert PyMC3 objects to xarray datasets. Note we are also giving some information about labelling.

ArviZ is built to work with InferenceData, and the more groups it has access to, the more powerful analyses it can perform. Here is a plot of the trace, which is common in PyMC3 workflows. Note the intelligent labels.

In [6]:
data = az.from_pymc3(trace=centered_eight_trace,
                     prior=prior,
                     posterior_predictive=posterior_predictive,
                     coords={'school': schools},
                     dims={'theta': ['school'], 'obs': ['school']})
data
Out[6]:
Inference data with groups:
    > posterior
    > sample_stats
    > posterior_predictive
    > prior
    > observed_data
In [7]:
az.plot_trace(data);
../_images/notebooks_Introduction_12_0.png

Plotting with PyStan objects

ArviZ is built with first class support for PyStan objects, and can plot raw fit objects in a reasonable manner. Here is the same centered eight schools model:

In [8]:
import pystan


schools_code = """
data {
  int<lower=0> J;
  real y[J];
  real<lower=0> sigma[J];
}

parameters {
  real mu;
  real<lower=0> tau;
  real theta[J];
}

model {
  mu ~ normal(0, 5);
  tau ~ cauchy(0, 5);
  theta ~ normal(mu, tau);
  y ~ normal(theta, sigma);
}
generated quantities {
    vector[J] log_lik;
    vector[J] y_hat;
    for (j in 1:J) {
        log_lik[j] = normal_lpdf(y[j] | theta[j], sigma[j]);
        y_hat[j] = normal_rng(theta[j], sigma[j]);
    }
}
"""

schools_dat = {'J': 8,
               'y': [28,  8, -3,  7, -1,  1, 18, 12],
               'sigma': [15, 10, 16, 11,  9, 11, 10, 18]}

sm = pystan.StanModel(model_code=schools_code, verbose=False)
fit = sm.sampling(data=schools_dat, iter=1000, chains=4)
INFO:pystan:COMPILING THE C++ CODE FOR MODEL anon_model_b0eada194ad938e30ed47926216f98ca NOW.
WARNING:pystan:38 of 2000 iterations ended with a divergence (1.9%).
WARNING:pystan:Try running with adapt_delta larger than 0.8 to remove the divergences.
In [9]:
az.plot_density(fit, var_names=['mu', 'tau']);
../_images/notebooks_Introduction_15_0.png

Again, converting to InferenceData (a netcdf datastore that loads data into xarray datasets), we can get much richer labelling and mixing of data. Here is a plot showing where the Hamiltonian sampler had divergences

In [10]:
data = az.from_pystan(fit=fit,
                      posterior_predictive='y_hat',
                      observed_data=['y'],
                      log_likelihood='log_lik',
                      coords={'school': schools},
                      dims={'theta': ['school'], 'y': ['school'], 'log_lik': ['school'], 'y_hat': ['school'], 'theta_tilde': ['school']})
data
Out[10]:
Inference data with groups:
    > posterior
    > sample_stats
    > posterior_predictive
    > observed_data
In [11]:
az.plot_pair(data, coords={'school': ['Choate', 'Deerfield', 'Phillips Andover']}, divergences=True);
/home/colin/miniconda3/envs/arviz3.6/lib/python3.6/site-packages/matplotlib/figure.py:2299: UserWarning: This figure includes Axes that are not compatible with tight_layout, so results might be incorrect.
  warnings.warn("This figure includes Axes that are not compatible "
../_images/notebooks_Introduction_18_1.png