Part2
by Laurent Smeets and Rens van der Schoot
Before estimating the model:
After estimation before inspecting results:
Understanding the exact influence of the priors
File called WAMBS_workflow_MarathonData.qmd (quarto document)
Click here for the Quarto version
Create your own project and project folder
Copy the template and rename it
We will go through the different parts in the slide show
You can apply/adapt the code in the template
To render the document properly with references, you also need the references.bib file
here packageIf you do not know how to use Projects in RStudio or the here package, these two sources might be helpfull:
Projects: https://youtu.be/MdTtTN8PUqU?si=mmQGlU063EMt86B2
here package: https://youtu.be/oh3b3k5uM7E?si=0-heLJXfFVLtTohh
Packages needed:
Load the dataset and the model:
Uninformative/Weakly informative
When objectivity is crucial and you want let the data speak for itself…
Informative
When including significant information is crucial
brms defaultsWeakly informative priors
If dataset is big, impact of priors is minimal
But, always better to know what you are doing!
Complex models might run into convergence issues \(\rightarrow\) specifying more informative priors might help!
So, how to deviate from the defaults?
brmsFunction: get_prior( )
Remember our model 2 for Marathon Times:
\[\begin{aligned} & \text{MarathonTimeM}_i \sim N(\mu,\sigma_e)\\ & \mu = \beta_0 + \beta_1*\text{km4week}_i + \beta_2*\text{sp4week}_i \end{aligned}\]
brmsprior: type of prior distributionclass: parameter class (with b being population-effects)coef: name of the coefficient within parameter classgroup: grouping factor for group-level parameters (when using mixed effects models)resp : name of the response variable when using multivariate modelslb & ub: lower and upper bound for parameter restrictionThe best way to make sense of the priors used is visualizing them!
Many options:
See WAMBS template!
There we demonstrate the use of ggplot2, metRology, ggtext and patchwork to visualize the priors.
library(metRology)
library(ggplot2)
library(ggtext)
library(patchwork)
# Setting a plotting theme
theme_set(theme_linedraw() +
theme(text = element_text(family = "Times", size = 8),
panel.grid = element_blank(),
plot.title = element_markdown())
)
# Generate the plot for the prior of the Intercept (mu)
Prior_mu <- ggplot( ) +
stat_function(
fun = dt.scaled, # We use the dt.scaled function of metRology
args = list(df = 3, mean = 199.2, sd = 24.9), #
xlim = c(120,300)
) +
scale_y_continuous(name = "density") +
labs(title = "Prior for the intercept",
subtitle = "student_t(3,199.2,24.9)")
# Generate the plot for the prior of the error variance (sigma)
Prior_sigma <- ggplot( ) +
stat_function(
fun = dt.scaled, # We use the dt.scaled function of metRology
args = list(df = 3, mean = 0, sd = 24.9), #
xlim = c(0,6)
) +
scale_y_continuous(name = "density") +
labs(title = "Prior for the residual variance",
subtitle = "student_t(3,0,24.9)")
# Generate the plot for the prior of the effects of independent variables
Prior_betas <- ggplot( ) +
stat_function(
fun = dnorm, # We use the normal distribution
args = list(mean = 0, sd = 10), #
xlim = c(-20,20)
) +
scale_y_continuous(name = "density") +
labs(title = "Prior for the effects of independent variables",
subtitle = "N(0,10)")
Prior_mu + Prior_sigma + Prior_betas +
plot_layout(ncol = 3)Experimental study (pretest - posttest design) with 3 conditions:
Model:
\[\begin{aligned} & Posttest_{i} \sim N(\mu,\sigma_{e_{i}})\\ & \mu = \beta_0 + \beta_1*\text{Pretest}_{i} + \beta_2*\text{Exp_cond1}_{i} + \beta_3*\text{Exp_cond2}_{i} \end{aligned}\]
Our job: coming up with priors that reflect that we expect both conditions to have a positive effect (hypothesis based on literature) and no indications that one experimental condition will outperform the other.
Remember Cohen’s d: 0.2 = small effect size; 0.5 = medium effect size; 0.8 or higher = large effect size
brmsSetting our custom priors can be done with set_prior( ) command
E.g., change the priors for the beta’s (effects of km4week and sp4week):
Did you set sensible priors?
brmsStep 1: Fit the model with custom priors with option sample_prior="only"
brmsStep 2: visualize the data with the pp_check( ) function
brmsHow are summary statistics of simulated datasets (e.g., median, min, max, …) distributed over the datasets?
How does that compare to our real data?
Use type = "stat" argument within pp_check()
Create custom trace-plots (aka caterpillar plots) with ggs( ) function from ggmcmc package
Model_chains <- ggs(MarathonTimes_Mod2)
Model_chains %>%
filter(Parameter %in% c(
"b_Intercept",
"b_km4week",
"b_sp4week",
"sigma"
)
) %>%
ggplot(aes(
x = Iteration,
y = value,
col = as.factor(Chain)))+
geom_line() +
facet_grid(Parameter ~ .,
scale = 'free_y',
switch = 'y') +
labs(title = "Caterpillar Plots for the parameters",
col = "Chains")Re-fit the model with more iterations
Check trace-plots again
Warning
First consider the need to do this! If you have a complex model that already took a long time to run, this check will take at least twice as much time…
Sampling of parameters done by:
If variance between chains is big \(\rightarrow\) NO CONVERGENCE
R-hat (\(\widehat{R}\)) : compares the between- and within-chain estimates for model parameters
\(\widehat{R}\) < 1.015 for each parameter estimate
at least 4 chains are recommended
Effective Sample Size (ESS) > 400 to rely on \(\widehat{R}\)
brmsmcmc_rhat() function from the bayesplot package
brmsSampling of parameter values are not independent!
So there is autocorrelation
But you don’t want too much impact of autocorrelation
2 approaches to check this:
Should be higher than 0.1 (Gelman et al., 2013)
Visualize making use of the mcmc_neff( ) function from bayesplot
mcmc_acf( ) functionadditional way to assess the convergence of MCMC
if the algorithm converged, plots of all chains look similar
Histogram of posterior for each parameter
Have clear peak and sliding slopes
Step 1: create a new object with ‘draws’ based on the final model
Step 2: create histogram making use of that object
post_intercept <-
posterior_PD %>%
select(b_Intercept) %>%
ggplot(aes(x = b_Intercept)) +
geom_histogram() +
ggtitle("Intercept")
post_km4week <-
posterior_PD %>%
select(b_km4week) %>%
ggplot(aes(x = b_km4week)) +
geom_histogram() +
ggtitle("Beta km4week")
post_sp4week <-
posterior_PD %>%
select(b_sp4week) %>%
ggplot(aes(x = b_sp4week)) +
geom_histogram() +
ggtitle("Beta sp4week") Step 3: print the plot making use of patchwork ’s workflow to combine plots
Generate data based on the posterior probability distribution
Create plot of distribution of y-values in these simulated datasets
Overlay with distribution of observed data
using pp_check() again, now with our model
Often we rely on ‘arbitrary’ chosen (default) weakly informative priors
What is the influence of the prior (and the likelihood) on our results?
You could ad hoc set new priors and re-run the analyses and compare (a lot of work, without strict sytematical guidelines)
Semi-automated checks can be done with priorsense package
priorsense packageRecently a package dedicated to prior sensibility analyses is launched
Key-idea: power-scaling (both prior and likelihood)
background reading:
YouTube talk:
First check is done by using the powerscale_sensitivity( ) function
column prior contains info on sensibility for prior (should be lower than 0.05)
column likelihood contains info on sensibility for likelihood (that we want to be high, ‘let our data speak’)
column diagnosis is a verbalization of potential problem (- if none)
Sensitivity based on cjs_dist
Prior selection: all priors
Likelihood selection: all data
variable prior likelihood diagnosis
b_Intercept 0.001 0.085 -
b_km4week 0.001 0.080 -
b_sp4week 0.000 0.083 -
sigma 0.006 0.151 -