First, let’s load the packages and data we will be using.

```
# Packages
library("learnB4SS")
library("dplyr")
library("ggplot2")
library("brms")
library("bayestestR")
# Data
data(polite)
mod_00 <- system.file("extdata/b_mod_00.rds", package = "learnB4SS")
mod_01 <- system.file("extdata/b_mod_01.rds", package = "learnB4SS")
```

The first tool we will consider for making statistical inferences in a Bayesian framework is the credible interval. If you have heard of Bayesian inference before, there is a good chance you have also heard of credible intervals. We could describe them as the Bayesian counterpart to confidence intervals under a frequentist framework.

All we need to calculate a credible interval is a probability distribution. In R, this can be as simple as a vector of values. We’ll illustrate by sampling fake data and calculating a CI using base R.

```
# Generate 'fake' posterior by sampling values from a normal distribution with
# mean of 5 and SD of 3
posterior <- rnorm(n = 1000, mean = 5, sd = 3)
# Use quantile function on posterior
quantile(posterior, c(0.025, 0.975))
#> 2.5% 97.5%
#> -0.8637163 10.7121259
```

We can see that the 95% CI for our posterior is -0.8637163, 10.7121259.

We can simplify the process even more using the `hdi`

function from the `bayestestR`

package. This has some other benefits that we will see in a bit.

```
# bayesTestR::hdi
hdi_ex1 <- hdi(posterior)
hdi_ex1
#> 95% HDI: [-0.74, 10.78]
```

Notice that the ranges are slightly different. This is because the HDI, highest density interval, is a special type of credible interval. There are several methods for calculating a CI, but we won’t go into that now. For our purposes we will stick with the HDI.

One advantage to using the `hdi`

function from the `bayestestR`

package is that it also has print methods. This means we can wrap the `plot()`

function around our `hdi`

object, like this:

```
# Generate a plot from the hdi object
plot(hdi_ex1)
```

Beautiful!

Now let’s repeat this using a real posterior from a model object.

Recall that we fit this intercept-only model previously:

```
# Intercept-only model
b_mod_00 <- brm(articulation_rate ~ 1, data = polite)
```

Let’s get the posterior distribution and calculate the HDI of the intercept.

```
# Get posterior samples
post_00 <- posterior_samples(b_mod_00)
# Calculate HDI
hdi_ex2 <- hdi(post_00$b_Intercept)
hdi_ex2
#> 95% HDI: [6.52, 6.83]
```

So we are 95% certain that the value of the intercept falls between about 6.5 and 6.8. Cool. Let’s plot this as well.

```
# Plot it
plot(hdi_ex2)
```

Now we repeat this process with yesterdays model that included the predictor `attitude`

.

Here is the model again, just in case:

```
# Specify priors
priors_simple <- c(
prior(normal(0, 15), class = Intercept),
prior(normal(0, 10), class = b, coef = attitudepol),
prior(cauchy(0, 1), class = sigma)
)
# Fit model
b_mod_01 <- brm(
formula = articulation_rate ~ attitude,
data = polite,
prior = priors_simple
)
# Get posterior samples
post_01 <- posterior_samples(b_mod_01)
```

Let’s calculate the CI for the parameter `b_attitudepol`

.

```
# Calculate HDI
hdi_ex3 <- hdi(post_01$b_attitudepol)
hdi_ex3
#> 95% HDI: [-0.71, -0.13]
```

It looks like the 95% CI does not encompass 0. Let’s take a look at a plot.

```
# Plot it
plot(hdi_ex3)
```

This is helpful. We can see that the 95% HDI does not encompass 0, but there is some posterior mass that is positive (in blue).

In other words, positive values are still a possibility, given the data, the model, and our prior assumptions.

**Bonus**:

We can also use the `hdi`

function directly on a model object.

```
# Get HDI of all paramters of model
hdi(b_mod_01)
#> Highest Density Interval
#>
#> Parameter | 95% HDI
#> ----------------------------
#> (Intercept) | [ 6.68, 7.09]
#> attitudepol | [-0.71, -0.13]
```

And, like before, we can use the built-in print methods to quickly generate a plot:

Another tool we have for decision making is the `probability of direction`

, also known as the *maximum probability of effect*. The probability of direction tells us the proportion of the posterior that has the same sign (that is, if its + or -) as the median of the distribution. This value can range from 50% to 100% (0.5 - 1.0).

To calculate the probability of direction we will again resort to the `bayestestR`

package and use the `p_direction`

function. The function will calculate the probability of direction on a vector,

```
# "Fake" posterior example
p_direction(posterior)
#> Probability of Direction: 0.95
```

on posterior samples taken from a model object,

```
# PD of intercept-only model
p_direction(post_00$b_Intercept)
#> Probability of Direction: 1.00
```

and directly on a model object:

```
# PD for all parameters in b_mod_01
p_direction(b_mod_01)
#> Probability of Direction
#>
#> Parameter | pd
#> --------------------
#> (Intercept) | 100%
#> attitudepol | 99.70%
```

Again, we can take advantage of the print methods and quickly generate a plot:

```
# Assign PD to object and print
pd_on_mod <- p_direction(b_mod_01)
plot(pd_on_mod, show_intercept = T)
```

To build intuition about how the probability of direction corresponds with a frequentist p-value we can use the `pd_to_p`

and `p_to_pd`

functions to convert between the two (not recommended).

```
# Calculate p-value from PD
pd_to_p(0.987)
#> [1] 0.026
# Calculate PD from p-value
p_to_pd(0.01)
#> [1] 0.995
```

This plot shows the linear relationship between the probability of direction and a frequentist p-value.

The next tool we are going to talk about combines the highest density credible interval with a *region of practical equivalence*, or a ROPE We can use the ROPE to calculate the proportion of the HDI of a posterior distribution that lies within its bounds. ROPEs are useful because they allow the researcher to define a range of values which they consider to be practically equivalent to a null effect

We will again use the `rope`

function from the `basyestestR`

package. By default, the `rope`

function will calculate the proportion of the 95% CI that falls within our ROPE range. Like before, we can operate on a single distribution stored in a vector

```
# Calculate % of HDI within rope using simulated data
rope(posterior)
#> # Proportion of samples inside the ROPE [-0.10, 0.10]:
#>
#> inside ROPE
#> -----------
#> 0.74 %
```

We can set the range of the ROPE and the size of the HDI using the arguments `range`

and `ci`

, respectively.

```
# Calculate % of HDI within rope w/ specific settings
rope(posterior, range = c(-0.1, 0.1), ci = 0.99)
#> # Proportion of samples inside the ROPE [-0.10, 0.10]:
#>
#> inside ROPE
#> -----------
#> 0.71 %
```

The default sets the CI to 95% and the ROPE range to ±0.1, unless the input is a Bayesian model. In that case, the function `rope_range`

is used to calculate a ROPE (following Kruschke 2018, see `?rope_range`

).

\[\color{black}{\frac{\mu_{1} - \mu_{2}}{\sqrt{\frac{\sigma^2_{1} + \sigma^2_{2}}{2}}}}\]

```
# Calculate an appropriate ROPE following Kruschke 2018
rope_range(b_mod_01)
#> [1] -0.1164812 0.1164812
# Run it on our model
rope_on_mod01 <- rope(b_mod_01, range = c(-0.2, 0.2), ci = 0.95)
rope_on_mod01
#> # Proportion of samples inside the ROPE [-0.20, 0.20]:
#>
#> Parameter | inside ROPE
#> -------------------------
#> Intercept | 0.00 %
#> attitudepol | 5.60 %
```

And again there are also print methods for rope objects.

`plot(rope_on_mod01, show_intercept = T)`

We can also use a ROPE with multiple CIs.

```
# Set more strict ROPE and several HDIs
rope_on_mod02 <- rope(b_mod_01, range = c(-0.2, 0.2), ci = c(0.9, 0.95, 0.99))
rope_on_mod02
#> # Proportions of samples inside the ROPE [-0.20, 0.20]:
#>
#> ROPE for the 90% HDI:
#>
#> Parameter | inside ROPE
#> -------------------------
#> Intercept | 0.00 %
#> attitudepol | 3.55 %
#>
#>
#> ROPE for the 95% HDI:
#>
#> Parameter | inside ROPE
#> -------------------------
#> Intercept | 0.00 %
#> attitudepol | 5.60 %
#>
#>
#> ROPE for the 99% HDI:
#>
#> Parameter | inside ROPE
#> -------------------------
#> Intercept | 0.00 %
#> attitudepol | 7.52 %
plot(rope_on_mod02)
```

Now let’s take some of these tools and use them to test different hypotheses using the `polite`

dataset.

Let’s fit the following model: `articulation_rate ~ musicstudent`

To simplify, you can use the same priors from above. Here is a hint, but you need to fill in the details.

```
# Specify priors
priors_simple <- c(
prior(normal(0, 15), class = Intercept),
prior(normal(0, 10), class = b),
prior(cauchy(0, 1), class = sigma)
)
b_mod_02 <- brm(
formula = ???,
prior = ???,
data = polite
)
```

- Using a credible interval, determine whether or not there is compelling evidence that the articulation rate between non-music students and music students is non-zero.

- What is the probability that the estimate of the difference between non-music students and music students, i.e.,
`musicstudentyes`

, is negative?

- Again, consider the non-music/music student difference, but quantify your uncertainty using a ROPE (use a range and CI width of your choice). Plot the result.

**Hint**:

You can calculate all of these metrics with a single function! Try `describe_posterior`

.

`describe_posterior(b_mod_02, rope_range = c(-0.15, 0.15), ci = 0.99)`