Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Section 5.2 — Bayesian inference computations

This notebook contains the code examples from Section 5.2 Bayesian inference computations from the No Bullshit Guide to Statistics.

See also:

Notebook setup

Note: you may need to restart the kernel to use updated packages.
<Figure size 640x480 with 0 Axes>

Definitions

TODO

Posterior inference using MCMC estimation

TODO: point-form definitions

Bayesian inference using Bambi

TODO: mention Bambi classes

Abstract specification of a term prior

    Parameters
    ----------
    name : str
        Name of prior distribution. Must be the name of a PyMC distribution
        (e.g., `"Normal"`, `"Bernoulli"`, etc.)
    auto_scale: bool
        Whether to adjust the parameters of the prior or use them as passed. Default to `True`.
    kwargs : dict
        Optional keywords specifying the parameters of the named distribution.
    dist : pymc.distributions.distribution.DistributionMeta or callable
        A callable that returns a valid PyMC distribution. The signature must contain `name`,
        `dims`, and `shape`, as well as its own keyworded arguments.
    
Specification of model class

    Parameters
    ----------
    formula : str or bambi.formula.Formula
        A model description written using the formula syntax from the `formulae` library.
    data : pandas.DataFrame
        A pandas dataframe containing the data on which the model will be fit, with column
        names matching variables defined in the formula.
    family : str or bambi.families.Family
        A specification of the model family (analogous to the family object in R). Either
        a string, or an instance of class `bambi.families.Family`. If a string is passed, a
        family with the corresponding name must be defined in the defaults loaded at `Model`
        initialization. Valid pre-defined families are `"bernoulli"`, `"beta"`,
        `"binomial"`, `"categorical"`, `"gamma"`, `"gaussian"`, `"negativebinomial"`,
        `"poisson"`, `"t"`, and `"wald"`. Defaults to `"gaussian"`.
    priors : dict
        Optional specification of priors for one or more terms. A dictionary where the keys are
        the names of terms in the model, "common," or "group_specific" and the values are
        instances of class `Prior`. If priors are unset, uses automatic priors inspired by
        the R rstanarm library.
    link : str or Dict[str, str]
        The name of the link function to use. Valid names are `"cloglog"`, `"identity"`,
        `"inverse_squared"`, `"inverse"`, `"log"`, `"logit"`, `"probit"`, and
        `"softmax"`. Not all the link functions can be used with all the families.
        If a dictionary, keys are the names of the target parameters and the values are the names
        of the link functions.

Example 1: estimating the probability of a bias of a coin

Let’s revisit the biased coin example from Section 5.1, where we want to estimate the probability the coin turns up heads.

Data

We have a sample that contains n=50n=50 observations (coin tosses) from the coin. The outcome 1 corresponds to heads, while the outcome 0 corresponds to tails. We package the data as the ctoss column of a new data frame ctosses.

Loading...

The proportion of heads outcomes is:

0.68

Model

The model is

C∼Bernoulli(P),P∼U(0,1).C \sim \textrm{Bernoulli}(P), \qquad P \sim \mathcal{U}(0,1).
Uniform(lower: 0.0, upper: 1.0)
Formula: ctoss ~ 1 Family: bernoulli Link: p = identity Observations: 50 Priors: target = p Common-level effects Intercept ~ Uniform(lower: 0.0, upper: 1.0)
Loading...

Fitting the model

Modeling the probability that ctoss==1
Initializing NUTS using jitter+adapt_diag...
Multiprocess sampling (4 chains in 4 jobs)
NUTS: [P]
Loading...
Loading...
Sampling 4 chains for 1_000 tune and 1_000 draw iterations (4_000 + 4_000 draws total) took 1 seconds.

Exploring InferenceData objects

Loading...
arviz.data.inference_data.InferenceData
['posterior', 'sample_stats', 'observed_data']
xarray.core.dataset.Dataset
['chain', 'draw']
['P']
xarray.core.dataarray.DataArray
Loading...
numpy.ndarray
array([[0.761, 0.569, 0.776, ..., 0.708, 0.629, 0.708], [0.689, 0.732, 0.676, ..., 0.602, 0.594, 0.663], [0.697, 0.674, 0.658, ..., 0.675, 0.675, 0.642], [0.72 , 0.754, 0.77 , ..., 0.706, 0.739, 0.646]])
(4, 1000)

Extracting the samples from the posterior

array([0.76122756, 0.56861221, 0.77616961, ..., 0.70605793, 0.73880719, 0.64569808])

Visualize the posterior

Histogram

<Figure size 500x300 with 1 Axes>

Kernel density plot

<Figure size 500x300 with 1 Axes>

Summarize the posterior

4000

Posterior mean

0.6747512974497554

Posterior standard deviation

0.06413160885365309

Posterior median

0.6780571467155877

Posterior quartiles

array([0.63207241, 0.67805715, 0.71976479])

Posterior percentiles

array([0.54664801, 0.78923245])

Posterior mode

0.6833825973512753

Credible interval

[0.5733806152569917, 0.7841482011374427]

Example 2: estimating the IQ score

Let’s return to the investigation of the smart drug effects on IQ scores.

Data

We have collected data from 30 individuals who took the smart drug, which we have packaged into the iq column of the data frame iqs.

107.82333333333334

Model

We will use the following Bayesian model:

X∼N(M,σ=15),M∼N(μM=100,σM=40).X \sim \mathcal{N}(M, \sigma=15), \qquad M \sim \mathcal{N}(\mu_M=100,\sigma_M=40).

We place a broad prior on the mean parameter MM, by choosing a large value for the standard deviation σM\sigma_M. We assume the IQ scores come from a population with standard deviation σ=15\sigma = 15.

Formula: iq ~ 1 Family: gaussian Link: mu = identity Observations: 30 Priors: target = mu Common-level effects Intercept ~ Normal(mu: 100.0, sigma: 40.0) Auxiliary parameters sigma ~ 15
Loading...

Fitting the model

This time we’ll generate N=2000N=2000 samples from each chain.

Initializing NUTS using jitter+adapt_diag...
Multiprocess sampling (4 chains in 4 jobs)
NUTS: [M]
Loading...
Loading...
Sampling 4 chains for 1_000 tune and 2_000 draw iterations (4_000 + 8_000 draws total) took 1 seconds.

Extract the samples from the posterior

8000
array([111.84188777, 111.84188777, 110.69558723, ..., 105.38269922, 106.5084091 , 107.49061702])

Visualize the posterior

Histogram

<Figure size 500x300 with 1 Axes>

Kernel density plot

<Figure size 500x300 with 1 Axes>

Summarize the posterior

Posterior mean

107.72704847150636

Posterior standard deviation

2.7150176274941304

Posterior median

107.71902676335739

Posterior quartiles

array([105.87041865, 107.71902676, 109.59653928])

Posterior percentiles

array([102.60648664, 112.88591885])

Posterior mode

107.7582939445229

Credible interval

[103.25275390621668, 112.12840034704796]

Visualizing and interpreting posteriors

Example 1 continued: inferences about the biased coin

Extracting samples (CUTTABLE)

For the purpose of our data analysis, we don’t care about the chain and draw information and are only interested in in the variable P, which are the actual samples from the posterior. The easiest way to extract the samples from the posterior is to use the ArviZ helper method az.extract shown below.

array([0.761, 0.569, 0.776, ..., 0.706, 0.739, 0.646])

The call to the function az.extract selected the posterior group, then selected the variable P within the posterior group.

/CUTTABLE

Summarizing the posterior

Loading...

Plotting the posterior

<Figure size 500x300 with 1 Axes>

Options:

  • If multiple variables, you specify a list to var_names to select only certain variables to plot

  • Set the option point_estimate to "mode" or "median"

  • Add the option rope to draw region of practical equivalence, e.g., rope=[97,103]

<Figure size 600x220 with 1 Axes>

Example 2 continued: inferences about the population mean

Summarizing the posterior

Loading...

Plotting the posterior

<Figure size 500x300 with 1 Axes>
<Figure size 500x300 with 1 Axes>
<Figure size 600x60 with 1 Axes>

Hypothesis testing

<Figure size 500x300 with 1 Axes>
<Figure size 500x300 with 1 Axes>

Explanations

Visualizing prior distributions

Sampling: [M]
<Figure size 500x300 with 1 Axes>

Bambi default priors

(107.82333333333334, 15.812119472803834, 39.53029868200959)
Formula: iq ~ 1 Family: gaussian Link: mu = identity Observations: 30 Priors: target = mu Common-level effects Intercept ~ Normal(mu: 107.8233, sigma: 39.5303) Auxiliary parameters sigma ~ HalfStudentT(nu: 4.0, sigma: 15.8121)
Sampling: [Intercept, sigma]
<Figure size 1150x345 with 2 Axes>

More about inference data objects

Loading...
arviz.data.inference_data.InferenceData
['posterior', 'sample_stats', 'observed_data']

Groups are Dataset objects

xarray.core.dataset.Dataset
Coordinates: * chain (chain) int64 32B 0 1 2 3 * draw (draw) int64 8kB 0 1 2 3 4 5 6 7 ... 993 994 995 996 997 998 999
Data variables: P (chain, draw) float64 32kB 0.7612 0.5686 0.7762 ... 0.7388 0.6457

Variables are DataArray objects

xarray.core.dataarray.DataArray
(4, 1000)
'P'
Loading...
array([[0.76122756, 0.56861221, 0.77616961, ..., 0.70772348, 0.62878475, 0.70789234], [0.68937002, 0.73226925, 0.67623114, ..., 0.60182373, 0.59438488, 0.6632119 ], [0.69674422, 0.67356423, 0.65844755, ..., 0.67517019, 0.67517019, 0.64238598], [0.72020439, 0.75444132, 0.7699058 , ..., 0.70605793, 0.73880719, 0.64569808]])
array([0.76122756, 0.56861221, 0.77616961, ..., 0.70605793, 0.73880719, 0.64569808])

MCMC diagnostics

Trace plots

There are several Arviz plots we can use to check if the Markov Chain Monte Carlo chains were sampling from the posterior as expected, or ...

<Figure size 1200x200 with 2 Axes>

Rank plots

<Figure size 500x300 with 1 Axes>
<Figure size 500x300 with 1 Axes>

Diagnostic summary

Loading...
Loading...

Prior predictive checks

Sampling: [M, iq]
<Figure size 500x300 with 1 Axes>
(1, 50, 30)
(1, 50, 30)

Posterior predictive checks

<Axes: xlabel='iq'>
<Figure size 500x300 with 1 Axes>

Fitting model to synthetic data

109.7132680142492
Initializing NUTS using jitter+adapt_diag...
Multiprocess sampling (4 chains in 4 jobs)
NUTS: [M]
Loading...
Loading...
Sampling 4 chains for 1_000 tune and 1_000 draw iterations (4_000 + 4_000 draws total) took 1 seconds.
Loading...
<Figure size 500x300 with 1 Axes>

Sensitivity analysis

Iterative model building

Discussion

Other types of priors

Conjugate priors

Uninformative priors

Software for Bayesian inference

Computational cost

Reporting Bayesian results

Model predictions (BONUS TOPIC)

Coin toss predictions

Let’s generate some observations form the posterior predictive distribution.

<Figure size 500x300 with 1 Axes>

IQ predictions

<Figure size 500x300 with 1 Axes>

Exercises

TODO: repeat exercises form Sec 5.1 using Bambi and ArviZ

Exercise A

Reproduce the analysis of the IQ scores data from Example 2, but this time use a model with Bambi default priors.

a) Plot the priors using plot_priors.
b) Compute the posterior mean, std, and a 90% hdi.
c) Compare your result in (b) to the results we obtained from Example 2.

Sampling: [M, sigma]
<Figure size 1150x345 with 2 Axes>
Initializing NUTS using jitter+adapt_diag...
Multiprocess sampling (4 chains in 4 jobs)
NUTS: [sigma, M]
Loading...
Loading...
Sampling 4 chains for 1_000 tune and 2_000 draw iterations (4_000 + 8_000 draws total) took 2 seconds.
Loading...
Loading...
<Figure size 700x200 with 1 Axes>

Exercise B

Repeat the analysis in Example 2, but this time use the exponential prior Expon(λ=0.1)\text{Expon}(\lambda=0.1) on the parameter sigma. Calculate:

a) Plot the priors using plot_priors.
b) Compute posterior mean of M and sigma.
c) Compute the posterior median of M and sigma.
d) Compute 90% credible interval for M and sigma.

Sampling: [M, sigma]
<Figure size 1150x345 with 2 Axes>

Exercise C

TODO