Code
library(bayesrules)
library(tidyverse)
library(rstanarm)
library(tidybayes)
library(bayesplot)
library(broom.mixed)
library(patchwork)
library(janitor)
data(bikes)
For the Normal regression model (9.6) with
Identify the response variable (
In each situation below, suppose that the typical relationship between the given response variable
Consider the Normal regression model (9.6). Explain in one or two sentences, in a way that one of your non-stats friends could understand, how
Our data’s variability is measured by
A researcher wants to use a person’s age (in years) to predict their annual orange juice consumption (in gallons). Here you’ll build up a relevant Bayesian regression model, step by step.
Lorem
Repeat the above exercise for the following scenario. A researcher wishes to predict tomorrow’s high temperature by today’s high temperature.
Lorem
Mark each statement about posterior regression simulation as True or False.
Lorem
For each situation, specify the appropriate stan_glm()
syntax for simulating the Normal regression model using 4 chains, each of length 10000. (You won’t actually run any code.)
age
; height
; dataset name: bunnies
.songs
.dogs
.Throughout this chapter, we explored how bike ridership fluctuates with temperature. But what about humidity? In the next exercises, you will explore the Normal regression model of rides
(humidity
(bikes
dataset. Based on past bikeshare analyses, suppose we have the following prior understanding of this relationship:
stan_glm()
syntax that you would use to simulate the posterior, but include prior_PD = TRUE
.$$
bikes %>%
add_epred_draws(bike_model_prior, ndraws = 100) %>%
ggplot(aes(humidity, rides)) +
geom_line(aes(y = .epred, group = .draw), size = 0.1)
set.seed(12)
bikes %>%
add_predicted_draws(bike_model_prior, ndraws = 4) %>%
ggplot(aes(humidity, rides)) +
geom_point(aes(y = .prediction, group = .draw), size = 0.2) +
facet_wrap(~ .draw)
With the priors in place, let’s examine the data.
ggplot(bikes, aes(x = humidity, y = rides)) +
geom_point(size = 0.5) +
geom_smooth(method = "lm", se = FALSE)
We can now simulate our posterior model of the relationship between ridership and humidity, a balance between our prior understanding and the data.
stan_glm()
to simulate the Normal regression posterior model. Do so with 5 chains run for 8000 iterations each. HINT: You can either do this from scratch or update()
your prior simulation from Exercise 9.9 using prior_PD = FALSE
.(Intercept) humidity sigma
0.97620 0.97205 0.98455
(Intercept) humidity sigma
0.9999065 0.9999237 0.9998410
# Trace plots of parallel chains
trace_plot <- mcmc_trace(bike_model, size = 0.1)
# Density plots of parallel chains
density_plot <- mcmc_dens_overlay(bike_model)
trace_plot / density_plot
Finally, let’s dig deeper into our posterior understanding of the relationship between ridership and humidity.
tidy()
summary of your posterior model, including 95% credible intervals.humidity
coefficient, # Posterior summary statistics
tidy(bike_model, effects = c("fixed", "aux"),
conf.int = TRUE, conf.level = 0.95)
# A tibble: 4 × 5
term estimate std.error conf.low conf.high
<chr> <dbl> <dbl> <dbl> <dbl>
1 (Intercept) 4019. 226. 3575. 4461.
2 humidity -8.42 3.38 -15.0 -1.83
3 sigma 1573. 49.6 1481. 1674.
4 mean_PPD 3483. 98.5 3292. 3676.
Based on the table above, we estimated that the
The 95% credible interval indicates that the humidity coefficient (
Yes, we have an ample evidence that there’s negative association between ridership and humidity. First, based on the visual inspection from the posterior we plotted above, we saw negative association between ridership and humidity. Had no association or positive association, the figure above would showed a flat or positive slope. Second, the posterior summary statistics for the humidity showed that the credible interval had no overlap with zero. Lastly, the quick tabulation from posterior probability showed that there’s almost certainly positive association between ridership and humidity.
Tomorrow is supposed to be 90% humidity in Washington, D.C. What levels of ridership should we expect?
posterior_predict()
shortcut function, simulate two posterior models:posterior_predict()
to confirm the results from your posterior predictive model of tomorrow’s ridership.predict_90 <- bike_model_df %>%
mutate(mu = `(Intercept)` + humidity * 90,
y_new = rnorm(20000, mean = mu, sd = sigma))
predict_90 %>%
summarize(
median_mu = quantile(mu, 0.5),
lower_mu = quantile(mu, 0.025),
upper_mu = quantile(mu, 0.975),
median_new = quantile(y_new, 0.5),
lower_new = quantile(y_new, 0.025),
upper_new = quantile(y_new, 0.975)
)
median_mu lower_mu upper_mu median_new lower_new upper_new
1 3260.318 3037.016 3482.108 3259.729 193.3223 6345.985
mu_plot <- predict_90 %>%
ggplot(aes(mu)) +
geom_density()
y_new_plot <- predict_90 %>%
ggplot(aes(y_new)) +
geom_density()
mu_plot + y_new_plot
Temperature and humidity aren’t the only possible weather factors in ridership. Let’s explore the relationship between ridership (windspeed
(
rides
versus windspeed
using the bikes data. How consistent are the observed patterns with your prior understanding of this relationship?windspeed
and rides
as follows:$$
bikes %>%
add_epred_draws(wind_model_prior, ndraws = 100) %>%
ggplot(aes(windspeed, rides)) +
geom_line(aes(y = .epred, group = .draw), size = 0.1)
set.seed(12)
bikes %>%
add_predicted_draws(wind_model_prior, ndraws = 4) %>%
ggplot(aes(windspeed, rides)) +
geom_point(aes(y = .prediction, group = .draw), size = 0.1) +
facet_wrap(~ .draw)
In this open-ended exercise, conduct a posterior analysis of the relationship between ridership (windspeed
(
(Intercept) windspeed sigma
0.98875 0.96925 0.94625
(Intercept) windspeed sigma
1.000475 1.001087 1.000832
# Trace plots of parallel chains
trace_plot <- mcmc_trace(wind_model, size = 0.1)
# Density plots of parallel chains
density_plot <- mcmc_dens_overlay(wind_model)
trace_plot / density_plot
bikes %>%
add_epred_draws(wind_model, ndraws = 100) %>%
ggplot(aes(windspeed, rides)) +
geom_line(aes(y = .epred, group = .draw), alpha = 0.15) +
geom_point(size = 0.1)
# A tibble: 4 × 5
term estimate std.error conf.low conf.high
<chr> <dbl> <dbl> <dbl> <dbl>
1 (Intercept) 4005. 123. 3769. 4241.
2 windspeed -40.0 7.74 -55.6 -24.0
3 sigma 1548. 48.0 1457. 1649.
4 mean_PPD 3483. 95.8 3299. 3671.
The penguins_bayes
dataset in the bayesrules package includes data on 344 penguins. In the next exercises, you will use this data to model the length of penguin flippers in mm (
flipper_length_mm
by bill_length_mm
using 4 chains for 10000 iterations each. HINT: You can use the same stan_glm()
syntax that you would use to simulate the posterior, but include prior_PD = TRUE
.prior_summary()
and use this to write out the complete structure of your Normal regression model (9.6).data(penguins_bayes)
flipper_prior <- stan_glm(
flipper_length_mm ~ bill_length_mm,
data = penguins_bayes,
family = gaussian,
prior_intercept = normal(200, 2.5, autoscale = TRUE),
prior = normal(0, 2.5, autoscale = TRUE),
prior_aux = exponential(1, autoscale = TRUE),
prior_PD = TRUE,
chains = 4,
iter = 10000
)
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 1).
Chain 1:
Chain 1: Gradient evaluation took 1e-05 seconds
Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 0.1 seconds.
Chain 1: Adjust your expectations accordingly!
Chain 1:
Chain 1:
Chain 1: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 1: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 1: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 1: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 1: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 1: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 1: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 1: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 1: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 1: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 1: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 1: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 1:
Chain 1: Elapsed Time: 0.051 seconds (Warm-up)
Chain 1: 0.064 seconds (Sampling)
Chain 1: 0.115 seconds (Total)
Chain 1:
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 2).
Chain 2:
Chain 2: Gradient evaluation took 5e-06 seconds
Chain 2: 1000 transitions using 10 leapfrog steps per transition would take 0.05 seconds.
Chain 2: Adjust your expectations accordingly!
Chain 2:
Chain 2:
Chain 2: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 2: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 2: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 2: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 2: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 2: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 2: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 2: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 2: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 2: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 2: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 2: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 2:
Chain 2: Elapsed Time: 0.052 seconds (Warm-up)
Chain 2: 0.08 seconds (Sampling)
Chain 2: 0.132 seconds (Total)
Chain 2:
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 3).
Chain 3:
Chain 3: Gradient evaluation took 4e-06 seconds
Chain 3: 1000 transitions using 10 leapfrog steps per transition would take 0.04 seconds.
Chain 3: Adjust your expectations accordingly!
Chain 3:
Chain 3:
Chain 3: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 3: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 3: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 3: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 3: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 3: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 3: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 3: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 3: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 3: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 3: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 3: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 3:
Chain 3: Elapsed Time: 0.053 seconds (Warm-up)
Chain 3: 0.05 seconds (Sampling)
Chain 3: 0.103 seconds (Total)
Chain 3:
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 4).
Chain 4:
Chain 4: Gradient evaluation took 2e-06 seconds
Chain 4: 1000 transitions using 10 leapfrog steps per transition would take 0.02 seconds.
Chain 4: Adjust your expectations accordingly!
Chain 4:
Chain 4:
Chain 4: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 4: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 4: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 4: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 4: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 4: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 4: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 4: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 4: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 4: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 4: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 4: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 4:
Chain 4: Elapsed Time: 0.052 seconds (Warm-up)
Chain 4: 0.051 seconds (Sampling)
Chain 4: 0.103 seconds (Total)
Chain 4:
Priors for model 'flipper_prior'
------
Intercept (after predictors centered)
Specified prior:
~ normal(location = 200, scale = 2.5)
Adjusted prior:
~ normal(location = 200, scale = 35)
Coefficients
Specified prior:
~ normal(location = 0, scale = 2.5)
Adjusted prior:
~ normal(location = 0, scale = 6.4)
Auxiliary (sigma)
Specified prior:
~ exponential(rate = 1)
Adjusted prior:
~ exponential(rate = 0.071)
------
See help('prior_summary.stanreg') for more details
penguins_bayes %>%
drop_na() %>%
add_epred_draws(flipper_prior, ndraws = 100) %>%
ggplot(aes(bill_length_mm, flipper_length_mm)) +
geom_line(aes(y = .epred, group = .draw), size = 0.1)
set.seed(12)
penguins_bayes %>%
drop_na() %>%
add_predicted_draws(flipper_prior, ndraws = 4) %>%
ggplot(aes(bill_length_mm, flipper_length_mm)) +
geom_point(aes(y = .prediction, group = .draw), size = 0.1) +
facet_wrap(~.draw)
With the priors in place, let’s examine the data a. Plot and discuss the observed relationship between flipper_length_mm
and bill_length_mm
among the 344 sampled penguins. b. Does simple Normal regression seem to be a reasonable approach to modeling this relationship? Explain.
ggplot(penguins_bayes, aes(bill_length_mm, flipper_length_mm)) +
geom_point() +
geom_smooth(method = lm, se = FALSE)