- Bayesian estimation
- Overview of Stan
- Manipulating and plotting Stan output
- Examples of time series models
2 May 2023
Complex hierarchical models
Inference: what’s the probability that the data are less than some threshold?
No bootstrapping!
\[P({\theta}|\textbf{y})P(\textbf{y})=P(\theta)P(\textbf{y}|\theta)\]
\[P({\theta}|\textbf{y})=\frac{P(\theta)P(\textbf{y}|\theta)}{P(\textbf{y})}\]
Parameters are random, data are fixed
\[P({\theta}|\textbf{y})=P(\theta)P(\textbf{y}|\theta)\]
\(P({\theta}|\textbf{y})\) is the posterior
\(P(\textbf{y}|\theta)\) is the likelihood
\(P(\theta)\) is the prior
MLE seeks to find the combination of parameters that maximize the likelihood (e.g. find absolute best point)
Bayesian estimation uses integration to find the combination of parameters that are best on average
Goal of Bayesian estimation in drawing samples from the posterior \(P({\theta}|\textbf{y})\)
For very simple models, we can write the analytical solution for the posterior
But for 99% of the problems we work on, need to generate samples via simulation
Markov chain Monte Carlo
Run 3-4 MCMC chains in parallel
Discard first ~ 10-50% of each MCMC chain as a ‘burn-in’
Optionally apply MCMC thinning to reduce autocorrelation
Metropolis, Metropolis-Hastings
Sampling - Imporance - Resampling (SIR)
No-U-Turn Sampler (NUTS)
Monahan et al. 2016, Faster estimation of Bayesian models in ecology using Hamiltonian Monte Carlo
Powerful, cross-platform and cross-language (R, Julia, Matlab, etc) that allows users to write custom code that can be called directly from R
Estimation can be fully or approximate Bayesian inference, or maximum a posteriori optimization (BFGS)
Useful links:
Write your own code (based on examples in the manual, etc)
Use an existing package
Use our bundled code to get started with simple models (we’ll start here)
rstan::stan_lm rstan::stan_glm rstan::stan_glmer
Very flexible brms
includes autocorrelated errors, non-normal data, non-linear smooths (GAMs), etc.
Limitations related to this class:
allows multivariate data, but not multivariate time series models brms example
brms
offers notation that should be very familiar to run many classes of models,
brms::brm(y ~ x * z + (1|group), data=d) brms::brm(y01 ~ x * z + (1|group), data=d, family = binomial("logit")) brms::brm(bf(y ~ s(x)), data=d)
brms
allows ARMA correlation structures that we’re familiar with,
data("LakeHuron") LakeHuron <- as.data.frame(LakeHuron) fit <- brm(x ~ arma(p = 2, q = 1), data = LakeHuron)
lm_fit = brms::brm(log(airmiles) ~ year, data=df)
lm_ar= brms::brm(log(airmiles) ~ arma(p = 1, q = 0), data=df)
lm_ar
is a “brmsfit” object and has a bunch of convenient plotting functionsplot(lm_ar)
pairs(lm_ar)
pp_check(lm_ar)
shinystan::launch_shinystan(lm_ar)
bayesplot
mcmc_areas(lm_ar,c("sigma","b_Intercept","ar[1]"))
These plots only the tip of the iceberg for plotting. For more great examples of the kinds of plots avaialable, see these vignettes:
install.packages("rstan", repos = "https://cloud.r-project.org") install.packages("devtools", repos = "https://cloud.r-project.org")
devtools::install_github(repo="atsa-es/atsar") library("atsar")
atsar
package includes:This model should be familiar,
\[E\left[ { Y }_{ t } \right] =E\left[ { Y }_{ t-1 } \right] +{ e }_{ t-1 }\] * Note that the use of the argument model_name
and est_drift
. By not estimating drift, we assume the process is stationary with respect to the mean
rw = fit_stan(y = neon$oxygen, est_drift = FALSE, model_name = "rw")
rw = fit_stan(y = neon$oxygen, est_drift = FALSE, model_name = "rw", mcmc_list = list(n_mcmc = 2000, n_burn = 500, n_chain = 3, n_thin = 1))
State equation: \[{ x }_{ t }={ \phi x }_{ t-1 }+{ \varepsilon }_{ t-1 }\] where \({ \varepsilon }_{ t-1 } \sim Normal(0, q)\)
Observation equation: \[{ Y }_{ t } \sim Normal(x_{t}, r)\]
We can first run the model with \(\phi\),
ss_ar = fit_stan(y = neon$oxygen, est_drift=FALSE, model_name = "ss_ar", mcmc_list = list(n_mcmc = 2000, n_chain = 1, n_thin = 1,n_burn=1000))
then without,
ss_rw = fit_stan(y = neon$oxygen, est_drift=FALSE, model_name = "ss_rw", mcmc_list = list(n_mcmc = 2000, n_chain = 1, n_thin = 1,n_burn=1000))
Did the models converge?
rw_summary <- summary(ss_rw, pars = c("sigma_process","sigma_obs"), probs = c(0.1, 0.9))$summary print(rw_summary)
## mean se_mean sd 10% 90% ## sigma_process 0.25050137 0.001921004 0.008951147 0.23891867 0.26150841 ## sigma_obs 0.05251124 0.005040720 0.014999464 0.03513455 0.07474426 ## n_eff Rhat ## sigma_process 21.712052 1.128660 ## sigma_obs 8.854545 1.392187
rhats <- summary(ss_rw)$summary[,"Rhat"] print(max(rhats))
## [1] 1.401858
broom.mixed
package, we can also extract some tidy summaries of the outputcoef = broom.mixed::tidy(ss_ar) head(coef)
## # A tibble: 6 × 3 ## term estimate std.error ## <chr> <dbl> <dbl> ## 1 sigma_process 0.250 0.00845 ## 2 pred[1] 8.22 0.0575 ## 3 pred[2] 8.14 0.0600 ## 4 pred[3] 9.02 0.0578 ## 5 pred[4] 8.99 0.0546 ## 6 pred[5] 8.84 0.0536
##‘atsar’ package: raw samples
rstan::extract()
on to get raw posterior draws, by chainpars = extract(ss_ar)
summary(pars$sigma_process)
##‘atsar’ package: model selection
loo
packageloo_ar = (loo::loo(ss_ar)) loo_rw = (loo::loo(ss_rw))
mod = fit_stan(y = SalmonSurvCUI$logit.s, model_name="dlm-intercept", mcmc_list = list(n_mcmc = 2000, n_chain = 1, n_thin = 1,n_burn=1000))
mod_slope = fit_stan(y = SalmonSurvCUI$logit.s, x = SalmonSurvCUI$CUI.apr, model_name="dlm-slope", mcmc_list = list(n_mcmc = 2000, n_chain = 1, n_thin = 1,n_burn=1000))
Let’s look at predictions using the rstan::extract()
function
Let’s look at predictions using the rstan::extract()
function
family
argument in fit_stan
allows to have flexible familiesmod = fit_stan(y = SalmonSurvCUI$logit.s, model_name="dlm-intercept", family="binomial") mod = fit_stan(y = SalmonSurvCUI$logit.s, model_name="dlm-intercept", family="poisson")
Bayesian implementation of time series models in Stan can do everything that MARSS can do and more!
Very flexible language, great developer community
Widely used by students in SAFS / UW / QERM / etc
Please come to us with questions, modeling issues, or add to code in our packages to make them better!