Jump to main navigation


Tutorial 7.2b - Simple linear regression (Bayesian)

12 Jan 2018

Simple linear regression references

Many biologists and ecologists get a little twitchy and nervous around mathematical and statistical formulae and nomenclature. Whilst it is possible to perform basic statistics without too much regard for the actual equation (model) being employed, as the complexity of the analysis increases, the need to understand the underlying model becomes increasingly important. Moreover, model specification in BUGS (the language used to program Bayesian modelling) aligns very closely to the underlying formulae. Hence a good understanding of the underlying model is vital to be able to create a sensible Bayesian model. Consequently, I will always present the linear model formulae along with the analysis. If you start to feel some form of disorder starting to develop, you might like to run through the Tutorials and Workshops twice (the first time ignoring the formulae).

Overview

To introduce the philosophical and mathematical differences between classical (frequentist) and Bayesian statistics, Wade (2000) presented a provocative yet compelling trend analysis of two hypothetical populations. The temporal trend of one of the populations shows very little variability from a very subtle linear decline. By contrast, the second population appears to decline more dramatically, yet has substantially more variability.

Wade (2000) neatly illustrates the contrasting conclusions (particularly with respect to interpreting probability) that would be drawn by the frequentist and Bayesian approaches and in so doing highlights how and why the Bayesian approach provides outcomes that are more aligned with management requirements.

This tutorial will start by replicating the demonstration of Wade (2000). Thereafter, we will replicate the fabricated analysis of Tutorial 7.2a

plot of chunk PopA
plot of chunk PopB
plot of chunk PopC

n: 10
Slope: -0.1022
t: -2.3252
p: 0.0485

n: 10
Slope: -10.2318
t: -2.2115
p: 0.0579

n: 100
Slope: -10.4713
t: -6.6457
p: 0

From a traditional frequentist perspective, we would conclude that there is a 'significant' relationship in Population A and C ($p<0.05$), yet not in Population B ($p>0.05$). Note, Population B and C were both generated from the same random distribution, it is just that Population C has a substantially higher number of observations.

The above illustrates a couple of things

  • statistical significance does not necessarily translate into biological importance. The percentage of decline for Population A is 0.46 where as the percentage of decline for Population B is 45.26. That is Population B is declining at nearly 10 times the rate of Population A. That sounds rather important, yet on the basis of the hypothesis test, we would dismiss the decline in Population B.
  • that a p-value is just the probability of detecting an effect or relationship - what is the probability that the sample size is large enough to pick up a difference.

Let us now look at it from a Bayesian perspective. I will just provide the posterior distributions (densities scaled to 0-1 so that they can be plotted together) for the slope for each population.

plot of chunk tut7.2bS1.1a

Focusing on Populations A and B, we would conclude:

  • the mean (plus or minus CI) slopes for Population A and B are -0.1 (-0.21,0) and -10.08 (-20.32,0.57) respectively.
  • the Bayesian approach allows us to query the posterior distribution is many other ways in order to ask sensible biological questions. For example, we might consider that a rate of change of 5% or greater represents an important biological impact. For Population A and B, the probability that the rate is 5% or greater is 0 and 0.85 respectively.

Simple linear regression is a linear modelling process that models a continuous response against a single continuous predictor. The linear model is expressed as: $$y_i = \beta_0+ \beta_1 x_i+\epsilon_i \hspace{1cm}\epsilon\sim{}N(0,\sigma^2)$$ where:

  • $y_i$ is the response value for each of the $i$ observations
  • $\beta_0$ is the y-intercept (value of $y$ when $x=0$)
  • $\beta_1$ is the slope (rate of chance in $y$ per unit chance in $x$)
  • $x_i$ is the predictor value for each of the $i$ observations
  • $\epsilon_i$ is the residual value of each of the $i$ observations. A residual is the difference between the observed value and the value expected by the model.
  • $\epsilon\sim{}N(0,\sigma^2)$ indicates that the residuals are normally distributed with a constant amount of variance
plot of chunk regression

The parameters of the trendline ($\beta_0, \beta_1$) are determined by Ordinary Least Squares in which the sum of the squared residuals is minimized. A non-zero population slope is indicative of a relationship.

Scenario and Data

Lets say we had set up an experiment in which we applied a continuous treatment ($x$) ranging in magnitude from 0 to 16 to a total of 16 sampling units ($n=16$) and then measured a response ($y$) from each unit. As this section is mainly about the generation of artificial data (and not specifically about what to do with the data), understanding the actual details are optional and can be safely skipped. Consequently, I have folded (toggled) this section away.

Random data incorporating the following trends (effect parameters)
  • the sample size = 16
  • the continuous $x$ variable ranging from 0 to 16
  • when the value of $x$ is 0, $y$ is expected to be 40 ($\beta_0=40$)
  • a 1 unit increase in $x$ is associated with a 1.5 unit decline in $y$ ($\beta_1=-1.5$)
  • the data are drawn from normal distributions with a mean of 0 and standard deviation of 5 ($\sigma^2=25$)
set.seed(1)
n <- 16
a <- 40  #intercept
b <- -1.5  #slope
sigma2 <- 25  #residual variance (sd=5)
x <- 1:n  #values of the year covariate
eps <- rnorm(n, mean = 0, sd = sqrt(sigma2))  #residuals
y <- a + b * x + eps  #response variable
# OR
y <- (model.matrix(~x) %*% c(a, b)) + eps
data <- data.frame(y, x)  #dataset
head(data)  #print out the first six rows of the data set
         y x
1 35.36773 1
2 37.91822 2
3 31.32186 3
4 41.97640 4
5 34.14754 5
6 26.89766 6

With these sort of data, we are primarily interested in investigating whether there is a relationship between the continuous response variable and the linear predictor (single continuous predictor).

Centering data

When a linear model contains a covariate (continuous predictor variable) in addition to another predictor (continuous or categorical), it is nearly always advisable that the continuous predictor variables be centered prior to the analysis. Centering is a process by which the mean of a variable is subtracted from each of the values such that the scale of the variable is shifted so as to be centered around 0. Hence the mean of the new centered variable will be 0, yet it will retain the same variance.

Raw data
plot of chunk centering
Centred data
plot of chunk centering1

There are multiple reasons for this:

  • Firstly, it provides some biological meaning to the y-intercept. Recall that the y-intercept is the value of Y when X is equal to zero. If X is centered, then the y-intercept represents the value of Y at the mid-point of the X range. The y-intercept of an un-centered X typically represents a un-real value of Y (as an X of 0 is often beyond the reasonable range of values).
  • Secondly, in multiplicative models (in which predictors and their interactions are included), main effects and interaction terms built from centered predictors will not be correlated to one another (see below)
  • Thirdly, for more complex models, centering the covariates can increase the likelihood that the modelling engine converges (arrives at a numerically stable and reliable outcome).
Note, centering will not effect the slope estimates.

In R, centering is easily achieved with the scale function.

data <- within(data, {
    cx1 <- as.numeric(scale(x1, scale = FALSE))
    cx2 <- as.numeric(scale(x2, scale = FALSE))
})
head(data)

Exploratory data analysis and initial assumption checking

Normality

Estimation and inference testing in linear regression assumes that the response is normally distributed in each of the populations. In this case, the populations are all possible measurements that could be collected at each level of $x$ - hence there are 16 populations. Typically however, we only collect a single observation from each population (as is also the case here). How then can be evaluate whether each of these populations are likely to have been normal?

plot of chunk normality
plot of chunk normality1

For a given response, the population distributions should follow much the same distribution shapes. Therefore provided the single samples from each population are unbiased representations of those populations, a boxplot of all observations should reflect the population distributions.

The two figures above show the relationships between the individual population distributions and the overall distribution. The left hand figure shows a distribution drawn from single representatives of each of the 16 populations. Since the 16 individual populations were normally distributed, the distribution of the 16 observations is also normal.

By contrast, the right hand figure shows 16 log-normally distributed populations and the resulting distribution of 16 single observations drawn from these populations. The overall boxplot mirrors each of the individual population distributions.

Homogeneity of variance

Simple linear regression also assumes that each of the populations are equally varied. Actually, it is prospect of a relationship between the mean and variance of y-values across x-values that is of the greatest concern. Strictly the assumption is that the distribution of y values at each x value are equally varied and that there is no relationship between mean and variance.

However, as we only have a single y-value for each x-value, it is difficult to directly determine whether the assumption of homogeneity of variance is likely to have been violated (mean of one value is meaningless and variability can't be assessed from a single value). The figure below depicts the ideal (and almost never realistic) situation in which (left hand figure) the populations are all equally varied. The middle figure simulates drawing a single observation from each of the populations. When the populations are equally varied, the spread of observed values around the trend line is fairly even - that is, there is no trend in the spread of values along the line.

If we then plot the residuals (difference between observed values and those predicted by the trendline) against the predict values, there is a definite lack of pattern. This lack of pattern is indicative of a lack of issues with homogeneity of variance.

plot of chunk homogeneity
plot of chunk homogeneity3
plot of chunk homogeneity1

If we now contrast the above to a situation where the population variance is related to the mean (unequal variance), we see that the observations drawn from these populations are not evenly distributed along the trendline (they get more spread out as the mean predicted value increase). This pattern is emphasized in the residual plot which displays a characteristic "wedge"-shape pattern.

plot of chunk homogeneity4
plot of chunk homogeneity5
plot of chunk homogeneity6

Hence looking at the spread of values around a trendline on a scatterplot of $y$ against $x$ is a useful way of identifying gross violations of homogeneity of variance. Residual plots provide an even better diagnostic. The presence of a wedge shape is indicative that the population mean and variance are related.

Linearity

Linear regression fits a straight (linear) line through the data. Therefore, prior to fitting such a model, it is necessary to establish whether this really is the most sensible way of describing the relationship. That is, does the relationship appear to be linearly related or could some other non-linear function describe the relationship better. Scatterplots and residual plots are useful diagnostics

Explore assumptions

The assumptions are:
  1. All of the observations are independent - this must be addressed at the design and collection stages
  2. The response variable (and thus the residuals) should be normally distributed
  3. The response variable should be equally varied (variance should not be related to mean as these are supposed to be estimated separately)
  4. the relationship between the linear predictor (right hand side of the regression formula) and the link function should be linear. A scatterplot with smoother can be useful for identifying possible non-linearity.

So lets explore normality, homogeneity of variances and linearity by constructing a scatterplot of the relationship between the response ($y$) and the predictor ($x$). We will also include a range of smoothers (linear and lowess) and marginal boxplots on the scatterplot to assist in exploring linearity and normality respectively.

# scatterplot
library(car)
scatterplot(y ~ x, data)
plot of chunk tut7.2aaS1.2

Conclusions:

  • there is no evidence that the response variable is non-normal
  • the spread of values around the trendline seems fairly even (hence it there is no evidence of non-homogeneity
  • the data seems well represented by the linear trendline. Furthermore, the lowess smoother does not appear to have a consistent shift trajectory.
Obvious violations could be addressed either by:
  • consider a non-linear linear predictor (such as a polynomial, spline or other non-linear function)
  • transform the scale of the response variables (to address normality etc)

Model fitting or statistical analysis

As with Tutorial 6.2b we will explore Bayesian modelling of simple linear regression using a variety of tools (such as MCMCpack, JAGS, RSTAN, RSTANARM and BRMS). Whilst JAGS and RSTAN are extremely flexible and thus allow models to be formulated that contain not only the simple model, but also additional derivatives, the other approaches are more restrictive. Consequently, I will mostly restrict models to just the minimum necessary and all derivatives will instead be calculated in R itself from the returned posteriors. Hence for each model, I will generate a mcmc list (data.mcmc.list) containing the mcmc sample matrix for each chain. This mcmc list will be considered a standard starting point for all other manipulations.

The purpose of fitting a model in this case is to explore the relationship between y and x. Since both y and x are continuous, a simple regression line is a good start.

The observed response ($y_i$) are assumed to be drawn from a normal distribution with a given mean ($\mu$) and standard deviation ($\sigma$). The expected values ($\mu$) are themselves determined by the linear predictor ($\beta_0 + \beta x_i$). In this case, $\beta_0$ represents the y-intercept (value of $y$ when $x$ is equal to zero) and $\beta$ represents the rate of change in $y$ for every unit change in $x$ (the effect).

Note that in this form, the y-intercept is of little interest. Indeed for many applications, a value of $x$ would be outside the domain of the collected data, outside the logical bounds of the actual variable or else outside the domain of interest. If however, we center the predictor variable (by subtracting the mean of $x$ from each $x$, then the y-intercept represents the value of $y$ at the average value of $x$. This certainly has more meaning. Note that centering the predictor does not effect the estimate of slope.

MCMC sampling requires priors on all parameters. We will employ weakly informative priors. Specifying 'uninformative' priors is always a bit of a balancing act. If the priors are too vague (wide) the MCMC sampler can wander off into nonscence areas of likelihood rather than concentrate around areas of highest likelihood (desired when wanting the outcomes to be largely driven by the data). On the other hand, if the priors are too strong, they may have an influence on the parameters. In such a simple model, this balance is very forgiving - it is for more complex models that prior choice becomes more important.

For this simple model, we will go with zero-centered Gaussian (normal) priors with relatively large standard deviations (1000) for both the intercept and the treatment effect and a wide half-cauchy (scale=25) for the standard deviation. $$ \begin{align} y_i &\sim{} N(\mu, \sigma)\\ \mu &= \beta_0 + \beta x_i\\[1em] \beta_0 &\sim{} N(0,1000)\\ \beta &\sim{} N(0,1000)\\ \sigma &\sim{} cauchy(0,25)\\ \end{align} $$

library(MCMCpack)
data.mcmcpack <- MCMCregress(y ~ x, data = data)

Structure of the JAGS model

Define the model

We now translate the likelihood model into BUGS/JAGS code and store the code in an external file.
$y_i\sim{}N(\mu_i, \tau)\\ \mu_i = \beta_0+\beta_1 x_i\\ \beta_0\sim{}N(0,1.0{E-6}) \hspace{1cm}\mathsf{non-informative~prior}\\ \beta_1\sim{}N(0,1.0{E-6}) \hspace{1cm}\mathsf{non-informative~prior}\\ \tau = 1/\sigma^2\\ \sigma\sim{}U(0,100)\\ $

In addition, we will derive the following:
  • the percentage decline ($100*\frac{((max(x)-min(x))*\beta)+min(y)}{min{y}}$) and the probability that $y$ decline by more than 25%.
  • the finite-population variance components
modelString = "
  model {
  #Likelihood
  for (i in 1:n) {
  y[i]~dnorm(mu[i],tau)
  mu[i] <- beta0+beta1*x[i]
  y.err[i] <- y[i] - mu[i]
  }
  
  #Priors
  beta0 ~ dnorm(0.01,1.0E-6)
  beta1 ~ dnorm(0,1.0E-6)
  tau <- 1 / (sigma * sigma)
  sigma~dunif(0,100)
  }
  "
## write the model to <a href=''></a> text file (I
## suggest you alter the path to somewhere more
## relevant to your system!)
writeLines(modelString, con = "../downloads/BUGSscripts/tut7.2bS4.1.txt")
Or a more complex version that has some derivatives
modelString = "
  model {
  #Likelihood
  for (i in 1:n) {
  y[i]~dnorm(mu[i],tau)
  mu[i] <- beta0+beta1*x[i]
  y.err[i] <- y[i] - mu[i]
  }
  
  #Priors
  beta0 ~ dnorm(0.01,1.0E-6)
  beta1 ~ dnorm(0,1.0E-6)
  tau <- 1 / (sigma * sigma)
  sigma~dunif(0,100)
  
  #Other Derived parameters 
  p.decline <- 1-step(beta1)
  ymin<-beta0+beta1*min(x)                  
  xrange <- max(x) - min(x)       
  decline <- 100*((xrange*beta1)+ymin)/ymin 
  p.decline25 <- step(decline-25)
  
  #finite-population variance components
  sd.x <- abs(beta1)*sd(x[])
  sd.resid <- sd(y.err)
  }
  "
## write the model to <a href=''></a> text file (I
## suggest you alter the path to somewhere more
## relevant to your system!)
writeLines(modelString, con = "../downloads/BUGSscripts/tut7.2bS4.1a.txt")

Define the data list

Arrange the data as a list (as required by BUGS). As input, JAGS will need to be supplied with:

  • the response variable (y)
  • the predictor variable (x)
  • the total number of observed items (n)
This all needs to be contained within a list object. We will create two data lists, one for each of the hypotheses.

data.list <- with(data, list(y = y, x = x, n = nrow(data)))
data.list
$y
 [1] 35.367731 37.918217 31.321857 41.976404
 [5] 34.147539 26.897658 31.937145 31.691624
 [9] 29.378907 23.473058 31.058906 23.949216
[13] 17.393797  7.926501 23.124655 15.775332

$x
 [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
[16] 16

$n
[1] 16

Define the initial values

Define the initial values ($\beta_0$, $\beta_1$ and $\sigma^2$ for the chain. Reasonable starting points can be gleaned from the data themselves. Note, this step is not absolutely necessary for simple models as the R2jags interface will automatically create sensible initial values for the parameters based on simple data summaries.

inits <- rep(list(list(beta0 = mean(data$y), beta1 = diff(tapply(data$y,
    data$x, mean)), sigma = sd(data$y))), 3)

Define the MCMC chain parameters

Next we should define the behavioural parameters of the MCMC sampling chains. Include the following:

  • the nodes (estimated parameters) to monitor (return samples for)
  • the number of MCMC chains (3)
  • the number of burnin steps (1000)
  • the thinning factor (10)
  • the number of MCMC iterations - determined by the number of samples to save, the rate of thinning and the number of chains

params <- c("beta0", "beta1", "sigma")
nChains = 3
burnInSteps = 3000
thinSteps = 10
numSavedSteps = 15000  #across all chains
nIter = ceiling(burnInSteps + (numSavedSteps * thinSteps)/nChains)
nIter
[1] 53000

Fit the model

Now run the JAGS code via the R2jags interface. Note that the first time jags is run after the R2jags package is loaded, it is often necessary to run any kind of randomization function just to initiate the .Random.seed variable.

## load the R2jags package
library(R2jags)
data.r2jags <- jags(data = data.list, inits = NULL, parameters.to.save = params, model.file = "../downloads/BUGSscripts/tut7.2bS4.1.txt",
    n.chains = nChains, n.iter = nIter, n.burnin = burnInSteps, n.thin = thinSteps)
Compiling model graph
   Resolving undeclared variables
   Allocating nodes
Graph information:
   Observed stochastic nodes: 16
   Unobserved stochastic nodes: 3
   Total graph size: 119

Initializing model
print(data.r2jags)
Inference for Bugs model at "../downloads/BUGSscripts/tut7.2bS4.1.txt", fit using jags,
 3 chains, each with 53000 iterations (first 3000 discarded), n.thin = 10
 n.sims = 15000 iterations saved
         mu.vect sd.vect   2.5%    25%    50%     75%   97.5%  Rhat n.eff
beta0     40.776   3.012 34.771 38.854 40.754  42.700  46.732 1.001  6500
beta1     -1.536   0.309 -2.155 -1.739 -1.534  -1.339  -0.917 1.001  8800
sigma      5.612   1.198  3.825  4.765  5.433   6.244   8.454 1.001 15000
deviance  98.913   2.916 95.586 96.795 98.131 100.243 106.547 1.001 15000

For each parameter, n.eff is a crude measure of effective sample size,
and Rhat is the potential scale reduction factor (at convergence, Rhat=1).

DIC info (using the rule, pD = var(deviance)/2)
pD = 4.3 and DIC = 103.2
DIC is an estimate of expected predictive error (lower deviance is better).
data.mcmc.list <- as.mcmc(data.r2jags)

Whilst Gibbs sampling provides an elegantly simple MCMC sampling routine, very complex hierarchical models can take enormous numbers of iterations (often prohibitory large) to converge on a stable posterior distribution.

To address this, Andrew Gelman (and other collaborators) have implemented a variation on Hamiltonian Monte Carlo (HMC: a sampler that selects subsequent samples in a way that reduces the correlation between samples, thereby speeding up convergence) called the No-U-Turn (NUTS) sampler. All of these developments are brought together into a tool called Stan ("Sampling Through Adaptive Neighborhoods").

By design (to appeal to the vast BUGS users), Stan models are defined in a manner reminiscent of BUGS. Stan first converts these models into C++ code which is then compiled to allow very rapid computation.

Consistent with the use of C++, the model must be accompanied by variable declarations for all inputs and parameters.

One important difference between Stan and JAGS is that whereas BUGS (and thus JAGS) use precision rather than variance, Stan uses variance.

Stan itself is a stand-alone command line application. However, conveniently, the authors of Stan have also developed an R interface to Stan called Rstan which can be used much like R2jags.

Structure of a stan model

Note the following important characteristics of stan code:

  • A stan model file comprises a number of blocks (not all of which are compulsory).
  • The stan language is an intermediary between (R/BUGS and c++), stan requires all types (integers, vectors, matrices etc) to be declared prior to use and it uses c++ commenting (// and /* */)
  • Code order is important, objects must be declared before they are used. When a type is declared in one block, it is available in subsequent blocks.

					  data {
					  // declare the input data / parameters
					  }
					  transformed data {
					  // optional - for transforming/scaling input data
					  }
					  parameters {
					  // define model parameters
					  }
					  transformed parameters {
					  // optional - for deriving additional non-model parameters
					  //            note however, as they are part of the sampling chain
					  //            transformed parameters slow sampling down.
					  }
					  model {
					  // specifying priors and likelihood as well as the linear predictor
					  }
					  generated quantities {
					  // optional - derivatives (posteriors) of the samples
					  }
				  

Define the model

The minimum model in Stan required to fit the above simple regression follows. Note the following modifications from the model defined in JAGS:
  • the normal distribution is defined by variance rather than precision
  • rather than using a uniform prior for sigma, I am using a half-Cauchy

We now translate the likelihood model into STAN code.
$y_i\sim{}N(\mu_i, \sigma)\\ \mu_i = \beta_0+\beta_1 x_i\\ \beta_0\sim{}N(0,1000)\\ \beta_1\sim{}N(0,1000)\\ \sigma\sim{}Cauchy(0,5)\\ $

modelString = "
  data {
  int<lower=0> n;
  vector [n] y;
  vector [n] x;
  }
  parameters {
  real beta0;
  real beta;
  real<lower=0> sigma;
  }
  model {
  vector [n] mu;
  #Priors
  beta0 ~ normal(0,10000);
  beta ~ normal(0,10000);
  sigma ~ cauchy(0,5);
 
  mu = beta0+beta*x;
  
  #Likelihood
  y~normal(mu,sigma);
  }
  "
## write the model to a text file (I suggest you alter the path to somewhere more relevant to your
## system!)
writeLines(modelString, con = "../downloads/BUGSscripts/tut7.2bS11.1.txt")
Another model specification
modelString1 = " 
  data {
  int<lower=0> n;
  real y[n];
  real x[n];
  }
  parameters {
  real beta0;
  real beta;
  real<lower=0> sigma;
  } 
  transformed parameters {
  real mu[n];
  for (i in 1:n)
  mu[i] = beta0+beta*x[i];
  }
  model {
  #Likelihood
  y~normal(mu,sigma);
  
  #Priors
  beta0 ~ normal(0,10000);
  beta ~ normal(0,10000);
  sigma~uniform(0,100);
  }
  "
Note, in the above, mu is defined in the transformed parameters block. As a result, the returned model will contain posteriors for each mu.

The No-U-Turn sampler operates much more efficiently if all predictors are centered. Although it is possible to pre-center all predictors that are passed to STAN, it is then often necessary to later convert back to the original scale for graphing and further analyses. Since centering is a routine procedure, arguably it should be built into the STAN we generate. Furthermore, we should also include the back-scaling as well. The following code is inspired by the code generated by the BRMS package.

					  data { 
					  int<lower=1> n;   // total number of observations 
					  vector[n] Y;      // response variable 
					  int<lower=1> nX;  // number of effects 
					  matrix[n, nX] X;   // model matrix 
					  } 
					  transformed data { 
					  matrix[n, nX - 1] Xc;  // centered version of X 
					  vector[nX - 1] means_X;  // column means of X before centering 
					  
					  for (i in 2:nX) { 
					  means_X[i - 1] = mean(X[, i]); 
					  Xc[, i - 1] = X[, i] - means_X[i - 1]; 
					  } 
					  }  
					  parameters { 
					  vector[nX-1] beta;  // population-level effects 
					  real cbeta0;  // center-scale intercept 
					  real<lower=0> sigma;  // residual SD 
					  } 
					  transformed parameters { 
					  } 
					  model { 
					  vector[n] mu; 
					  mu = Xc * beta + cbeta0; 
					  // prior specifications 
					  beta ~ normal(0, 100); 
					  cbeta0 ~ normal(0, 100); 
					  sigma ~ cauchy(0, 5); 
					  // likelihood contribution 
					  Y ~ normal(mu, sigma); 
					  } 
					  generated quantities { 
					  real beta0;  // population-level intercept 
					  beta0 = cbeta0 - dot_product(means_X, beta); 
					  }

In this version, the data are to be supplied as a model matrix (so as to leverage various vectorized and matrix multiplier routines). The transformed data block is used to center the non-intercept columns of the predictor model matrix. The model is fit on centered data thereby generating a slope and intercept. This intercept parameter is also expressed back on the non-centered scale (generated properties block).

Define the data list

Arrange the data as a list (as required by BUGS). As input, Stan (like WinBUGS/JAGS) will need to be supplied with:

  • the response variable (y)
  • the predictor variable (x)
  • the total number of observed items (n)
This all needs to be contained within a list object. We will create two data lists, one for each of the hypotheses.

Xmat <- model.matrix(~x, data = data)
data.list <- with(data, list(Y = y, X = Xmat, nX = ncol(Xmat), n = nrow(data)))
data.list
$Y
 [1] 35.367731 37.918217 31.321857 41.976404 34.147539 26.897658 31.937145 31.691624 29.378907
[10] 23.473058 31.058906 23.949216 17.393797  7.926501 23.124655 15.775332

$X
   (Intercept)  x
1            1  1
2            1  2
3            1  3
4            1  4
5            1  5
6            1  6
7            1  7
8            1  8
9            1  9
10           1 10
11           1 11
12           1 12
13           1 13
14           1 14
15           1 15
16           1 16
attr(,"assign")
[1] 0 1

$nX
[1] 2

$n
[1] 16

Define the MCMC chain parameters

Next we should define the behavioural parameters of the No-U-Turn sampling chains. Include the following:

  • the nodes (estimated parameters) to monitor (return samples for)
  • the number of MCMC chains (3)
  • the number of burnin steps (1000)
  • the thinning factor (10)
  • the number of MCMC iterations - determined by the number of samples to save, the rate of thinning and the number of chains

nChains = 3
burnInSteps = 1000
thinSteps = 3
numSavedSteps = 3000  #across all chains
nIter = ceiling(burnInSteps + (numSavedSteps * thinSteps)/nChains)
nIter
[1] 4000

Fit the model

Now compile and run the Stan code via the rstan interface. Note that the first time jags is run after the rstan package is loaded, it is often necessary to run any kind of randomization function just to initiate the .Random.seed variable.

During the warmup stage, the No-U-Turn sampler (NUTS) attempts to determine the optimum stepsize - the stepsize that achieves the target acceptance rate (0.8 or 80% by default) without divergence (occurs when the stepsize is too large relative to the curvature of the log posterior - and results in approximations that are likely to diverge and be biased) and without hitting the maximum treedepth (10). At each iteration of the NUTS algorithm, the number of leapfrog steps doubles (as it increases the treedepth) and only terminates when either the NUTS criterion are satisfied or the tree depth reaches the maximum (10 by default).

## load the rstan package
library(rstan)
data.rstan <- stan(data = data.list, model_code = modelString, chains = nChains, iter = nIter, warmup = burnInSteps,
    thin = thinSteps, save_dso = TRUE)
In file included from /usr/local/lib/R/site-library/BH/include/boost/config.hpp:39:0,
                 from /usr/local/lib/R/site-library/BH/include/boost/math/tools/config.hpp:13,
                 from /usr/local/lib/R/site-library/StanHeaders/include/stan/math/rev/core/var.hpp:7,
                 from /usr/local/lib/R/site-library/StanHeaders/include/stan/math/rev/core/gevv_vvv_vari.hpp:5,
                 from /usr/local/lib/R/site-library/StanHeaders/include/stan/math/rev/core.hpp:12,
                 from /usr/local/lib/R/site-library/StanHeaders/include/stan/math/rev/mat.hpp:4,
                 from /usr/local/lib/R/site-library/StanHeaders/include/stan/math.hpp:4,
                 from /usr/local/lib/R/site-library/StanHeaders/include/src/stan/model/model_header.hpp:4,
                 from file6ff34d65b11c.cpp:8:
/usr/local/lib/R/site-library/BH/include/boost/config/compiler/gcc.hpp:186:0: warning: "BOOST_NO_CXX11_RVALUE_REFERENCES" redefined
 #  define BOOST_NO_CXX11_RVALUE_REFERENCES
 ^
<command-line>:0:0: note: this is the location of the previous definition

SAMPLING FOR MODEL 'e7d4e08d9f1bbcf9d6d79f126f9e56c7' NOW (CHAIN 1).

Gradient evaluation took 1.4e-05 seconds
1000 transitions using 10 leapfrog steps per transition would take 0.14 seconds.
Adjust your expectations accordingly!


Iteration:    1 / 4000 [  0%]  (Warmup)
Iteration:  400 / 4000 [ 10%]  (Warmup)
Iteration:  800 / 4000 [ 20%]  (Warmup)
Iteration: 1001 / 4000 [ 25%]  (Sampling)
Iteration: 1400 / 4000 [ 35%]  (Sampling)
Iteration: 1800 / 4000 [ 45%]  (Sampling)
Iteration: 2200 / 4000 [ 55%]  (Sampling)
Iteration: 2600 / 4000 [ 65%]  (Sampling)
Iteration: 3000 / 4000 [ 75%]  (Sampling)
Iteration: 3400 / 4000 [ 85%]  (Sampling)
Iteration: 3800 / 4000 [ 95%]  (Sampling)
Iteration: 4000 / 4000 [100%]  (Sampling)

 Elapsed Time: 0.018545 seconds (Warm-up)
               0.045305 seconds (Sampling)
               0.06385 seconds (Total)


SAMPLING FOR MODEL 'e7d4e08d9f1bbcf9d6d79f126f9e56c7' NOW (CHAIN 2).

Gradient evaluation took 5e-06 seconds
1000 transitions using 10 leapfrog steps per transition would take 0.05 seconds.
Adjust your expectations accordingly!


Iteration:    1 / 4000 [  0%]  (Warmup)
Iteration:  400 / 4000 [ 10%]  (Warmup)
Iteration:  800 / 4000 [ 20%]  (Warmup)
Iteration: 1001 / 4000 [ 25%]  (Sampling)
Iteration: 1400 / 4000 [ 35%]  (Sampling)
Iteration: 1800 / 4000 [ 45%]  (Sampling)
Iteration: 2200 / 4000 [ 55%]  (Sampling)
Iteration: 2600 / 4000 [ 65%]  (Sampling)
Iteration: 3000 / 4000 [ 75%]  (Sampling)
Iteration: 3400 / 4000 [ 85%]  (Sampling)
Iteration: 3800 / 4000 [ 95%]  (Sampling)
Iteration: 4000 / 4000 [100%]  (Sampling)

 Elapsed Time: 0.017913 seconds (Warm-up)
               0.04733 seconds (Sampling)
               0.065243 seconds (Total)


SAMPLING FOR MODEL 'e7d4e08d9f1bbcf9d6d79f126f9e56c7' NOW (CHAIN 3).

Gradient evaluation took 6e-06 seconds
1000 transitions using 10 leapfrog steps per transition would take 0.06 seconds.
Adjust your expectations accordingly!


Iteration:    1 / 4000 [  0%]  (Warmup)
Iteration:  400 / 4000 [ 10%]  (Warmup)
Iteration:  800 / 4000 [ 20%]  (Warmup)
Iteration: 1001 / 4000 [ 25%]  (Sampling)
Iteration: 1400 / 4000 [ 35%]  (Sampling)
Iteration: 1800 / 4000 [ 45%]  (Sampling)
Iteration: 2200 / 4000 [ 55%]  (Sampling)
Iteration: 2600 / 4000 [ 65%]  (Sampling)
Iteration: 3000 / 4000 [ 75%]  (Sampling)
Iteration: 3400 / 4000 [ 85%]  (Sampling)
Iteration: 3800 / 4000 [ 95%]  (Sampling)
Iteration: 4000 / 4000 [100%]  (Sampling)

 Elapsed Time: 0.018588 seconds (Warm-up)
               0.043631 seconds (Sampling)
               0.062219 seconds (Total)

The STAN team has put together pre-compiled modules (functions) to make specifying and applying STAN models much simpler. Each function offers a consistent interface that is Also reminiscent of major frequentist linear modelling routines in R.

Whilst it is not necessary to specify priors when using rstanarm functions (as defaults will be generated), there is no guarantee that the routines for determining these defaults will persist over time. Furthermore, it is always better to define your own priors if for no other reason that it forces you to thing about what you are doing. Consistent with the pure STAN version, we will employ the following priors:

  • weakly informative Gaussian prior for the intercept $\beta_0 \sim{} N(0, 1000)$
  • weakly informative Gaussian prior for the treatment effect $\beta_1 \sim{} N(0, 1000)$
  • half-cauchy prior for the variance $\sigma \sim{} Cauchy(0, 25)$

Note, I am using the refresh=0 option so as to suppress the larger regular output in the interest of keeping output to what is necessary for this tutorial. When running outside of a tutorial context, the regular verbose output is useful as it provides a way to gauge progress.

library(rstanarm)
data.rstanarm = stan_glm(y ~ x, data = data, iter = 2000, warmup = 200,
    chains = 3, thin = 2, refresh = 0, prior_intercept = normal(0, 1000),
    prior = normal(0, 1000), prior_aux = cauchy(0, 25))
Gradient evaluation took 2.2e-05 seconds
1000 transitions using 10 leapfrog steps per transition would take 0.22 seconds.
Adjust your expectations accordingly!



 Elapsed Time: 1.80628 seconds (Warm-up)
               0.807009 seconds (Sampling)
               2.61329 seconds (Total)


Gradient evaluation took 1e-05 seconds
1000 transitions using 10 leapfrog steps per transition would take 0.1 seconds.
Adjust your expectations accordingly!



 Elapsed Time: 1.98795 seconds (Warm-up)
               1.66692 seconds (Sampling)
               3.65488 seconds (Total)


Gradient evaluation took 9e-06 seconds
1000 transitions using 10 leapfrog steps per transition would take 0.09 seconds.
Adjust your expectations accordingly!



 Elapsed Time: 1.52452 seconds (Warm-up)
               0.845179 seconds (Sampling)
               2.36969 seconds (Total)
print(data.rstanarm)
stan_glm
 family:  gaussian [identity]
 formula: y ~ x
------

Estimates:
            Median MAD_SD
(Intercept) 40.8    2.9  
x           -1.5    0.3  
sigma        5.4    1.1  

Sample avg. posterior predictive 
distribution of y (X = xbar):
         Median MAD_SD
mean_PPD 27.7    2.0  

------
For info on the priors used see help('prior_summary.stanreg').
library(broom)
library(coda)
tidyMCMC(data.rstanarm, conf.int = TRUE, conf.method = "HPDinterval")
         term  estimate std.error  conf.low  conf.high
1 (Intercept) 40.734015 3.0668570 34.412462 46.3425366
2           x -1.531248 0.3148917 -2.123538 -0.8981083
3       sigma  5.619764 1.1740461  3.604894  7.9675118

The brms package serves a similar goal to the rstanarm package - to provide a simple user interface to STAN. However, unlike the rstanarm implementation, brms simply converts the formula, data, priors and family into STAN model code and data before executing stan with those elements.

Whilst it is not necessary to specify priors when using brms functions (as defaults will be generated), there is no guarantee that the routines for determining these defaults will persist over time. Furthermore, it is always better to define your own priors if for no other reason that it forces you to thing about what you are doing. Consistent with the pure STAN version, we will employ the following priors:

  • weakly informative Gaussian prior for the intercept $\beta_0 \sim{} N(0, 1000)$
  • weakly informative Gaussian prior for the treatment effect $\beta_1 \sim{} N(0, 1000)$
  • half-cauchy prior for the variance $\sigma \sim{} Cauchy(0, 25)$

Note, I am using the refresh=0. option so as to suppress the larger regular output in the interest of keeping output to what is necessary for this tutorial. When running outside of a tutorial context, the regular verbose output is useful as it provides a way to gauge progress.

library(brms)
data.brms = brm(y ~ x, data = data, iter = 2000, warmup = 200, chains = 3,
    thin = 2, refresh = 0, prior = c(prior(normal(0, 1000), class = "Intercept"),
        prior(normal(0, 1000), class = "b"), prior(cauchy(0, 25), class = "sigma")))
Gradient evaluation took 1.2e-05 seconds
1000 transitions using 10 leapfrog steps per transition would take 0.12 seconds.
Adjust your expectations accordingly!



 Elapsed Time: 0.006342 seconds (Warm-up)
               0.02702 seconds (Sampling)
               0.033362 seconds (Total)


Gradient evaluation took 2.5e-05 seconds
1000 transitions using 10 leapfrog steps per transition would take 0.25 seconds.
Adjust your expectations accordingly!



 Elapsed Time: 0.006317 seconds (Warm-up)
               0.026596 seconds (Sampling)
               0.032913 seconds (Total)


Gradient evaluation took 5e-06 seconds
1000 transitions using 10 leapfrog steps per transition would take 0.05 seconds.
Adjust your expectations accordingly!



 Elapsed Time: 0.005054 seconds (Warm-up)
               0.028559 seconds (Sampling)
               0.033613 seconds (Total)
print(data.brms)
 Family: gaussian(identity) 
Formula: y ~ x 
   Data: data (Number of observations: 16) 
Samples: 3 chains, each with iter = 2000; warmup = 200; thin = 2; 
         total post-warmup samples = 2700
    ICs: LOO = Not computed; WAIC = Not computed
 
Population-Level Effects: 
          Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
Intercept    40.85      3.07    34.90    47.24       2310    1
x            -1.55      0.32    -2.18    -0.90       2408    1

Family Specific Parameters: 
      Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
sigma     5.63      1.19      3.9     8.48       2091    1

Samples were drawn using sampling(NUTS). For each parameter, Eff.Sample 
is a crude measure of effective sample size, and Rhat is the potential 
scale reduction factor on split chains (at convergence, Rhat = 1).
library(broom)
library(coda)
tidyMCMC(data.brms$fit, conf.int = TRUE, conf.method = "HPDinterval")
         term  estimate std.error  conf.low  conf.high
1 b_Intercept 40.853729 3.0714471 34.407211 46.6638946
2         b_x -1.545095 0.3205355 -2.141672 -0.8693169
3       sigma  5.631356 1.1888245  3.779939  8.2153548

MCMC diagnostics

In addition to the regular model diagnostic checks (such as residual plots), for Bayesian analyses, it is necessary to explore the characteristics of the MCMC chains and the sampler in general. Recall that the purpose of MCMC sampling is to replicate the posterior distribution of the model likelihood and priors by drawing a known number of samples from this posterior (thereby formulating a probability distribution). This is only reliable if the MCMC samples accurately reflect the posterior.

Unfortunately, since we only know the posterior in the most trivial of circumstances, it is necessary to rely on indirect measures of how accurately the MCMC samples are likely to reflect the likelihood. I will breifly outline the most important diagnostics, however, please refer to Tutorial 4.3, Secton 3.1: Markov Chain Monte Carlo sampling for a discussion of these diagnostics.

  • Traceplots for each parameter illustrate the MCMC sample values after each successive iteration along the chain. Bad chain mixing (characterized by any sort of pattern) suggests that the MCMC sampling chains may not have completely traversed all features of the posterior distribution and that more iterations are required to ensure the distribution has been accurately represented.
    plot of chunk sim7
  • Autocorrelation plot for each paramter illustrate the degree of correlation between MCMC samples separated by different lags. For example, a lag of 0 represents the degree of correlation between each MCMC sample and itself (obviously this will be a correlation of 1). A lag of 1 represents the degree of correlation between each MCMC sample and the next sample along the Chain and so on. In order to be able to generate unbiased estimates of parameters, the MCMC samples should be independent (uncorrelated). In the figures below, this would be violated in the top autocorrelation plot and met in the bottom autocorrelation plot.
    plot of chunk sim7 plot of chunk sim9
  • Rhat statistic for each parameter provides a measure of sampling efficiency/effectiveness. Ideally, all values should be less than 1.05. If there are values of 1.05 or greater it suggests that the sampler was not very efficient or effective. Not only does this mean that the sampler was potentiall slower than it could have been, more importantly, it could indicate that the sampler spent time sampling in a region of the likelihood that is less informative. Such a situation can arise from either a misspecified model or overly vague priors that permit sampling in otherwise nonscence parameter space.

Prior to inspecting any summaries of the parameter estimates, it is prudent to inspect a range of chain convergence diagnostics

  • Trace plots
    View trace plots
    library(MCMCpack)
    plot(data.mcmcpack)
    
    plot of chunk tut7_2bMCMCpackTrace
    Trace plots show no evidence that the chains have not reasonably traversed the entire multidimensional parameter space.
  • Raftery diagnostic
    View Raftery diagnostic
    library(MCMCpack)
    raftery.diag(data.mcmcpack)
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
                                                       
                 Burn-in  Total Lower bound  Dependence
                 (M)      (N)   (Nmin)       factor (I)
     (Intercept) 3        4028  3746         1.080     
     x           2        3851  3746         1.030     
     sigma2      2        3680  3746         0.982     
    
    The Raftery diagnostics estimate that we would require about 3900 samples to reach the specified level of confidence in convergence. As we have 10,000 samples, we can be confidence that convergence has occurred.
  • Autocorrelation diagnostic
    View autocorrelations
    library(MCMCpack)
    autocorr.diag(data.mcmcpack)
    
            (Intercept)            x       sigma2
    Lag 0   1.000000000  1.000000000  1.000000000
    Lag 1   0.011287106 -0.000965701  0.162987189
    Lag 5  -0.004110531  0.004773571  0.008242103
    Lag 10 -0.015174763 -0.012219328  0.002405411
    Lag 50 -0.003762082 -0.007068066 -0.009647390
    
    A lag of 1 appears to be mainly sufficient to avoid autocorrelation (except for sigma2, which is over 0.1). The diagnostic suggests that a lag of 5 would potentially correct this.

Again, prior to examining the summaries, we should have explored the convergence diagnostics.

library(coda)
data.mcmc = as.mcmc(data.r2jags)
  • Trace plots
    plot(data.mcmc)
    
    plot of chunk tut7.2bJAGSTrace
    Trace plots show no evidence that the chains have not reasonably traversed the entire multidimensional parameter space.

    When there are a lot of parameters, this can result in a very large number of traceplots. To focus on just certain parameters (such as $\beta$s)

    preds <- c("beta0", "beta1")
    plot(as.mcmc(data.r2jags)[, preds])
    
    plot of chunk tut7.2bJAGSTrace1
  • Raftery diagnostic
    raftery.diag(data.mcmc)
    
    [[1]]
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
                                                    
              Burn-in  Total Lower bound  Dependence
              (M)      (N)   (Nmin)       factor (I)
     beta0    20       38660 3746         10.30     
     beta1    20       36200 3746          9.66     
     deviance 20       36800 3746          9.82     
     sigma    20       36200 3746          9.66     
    
    
    [[2]]
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
                                                    
              Burn-in  Total Lower bound  Dependence
              (M)      (N)   (Nmin)       factor (I)
     beta0    20       37410 3746          9.99     
     beta1    20       38660 3746         10.30     
     deviance 20       36800 3746          9.82     
     sigma    20       36800 3746          9.82     
    
    
    [[3]]
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
                                                    
              Burn-in  Total Lower bound  Dependence
              (M)      (N)   (Nmin)       factor (I)
     beta0    20       38030 3746         10.20     
     beta1    20       38030 3746         10.20     
     deviance 20       36200 3746          9.66     
     sigma    20       35610 3746          9.51     
    
    The Raftery diagnostics for each chain estimate that we would require no more than 5000 samples to reach the specified level of confidence in convergence. As we have 16,667 samples, we can be confidence that convergence has occurred.
  • Autocorrelation diagnostic
    autocorr.diag(data.mcmc)
    
                   beta0        beta1     deviance         sigma
    Lag 0    1.000000000  1.000000000  1.000000000  1.0000000000
    Lag 10   0.002343329 -0.006499521 -0.005759350  0.0008347558
    Lag 50  -0.009224921 -0.010877289 -0.003269510  0.0022530505
    Lag 100 -0.004536817  0.002460483  0.007360297  0.0108817122
    Lag 500 -0.002154409  0.003107960 -0.004786948 -0.0052312783
    
    A lag of 10 appears to be sufficient to avoid autocorrelation (poor mixing).

Again, prior to examining the summaries, we should have explored the convergence diagnostics. There are numerous ways of working with STAN model fits (for exploring diagnostics and summarization).

  • extract the mcmc samples and convert them into a mcmc.list to leverage the various coda routines
  • use the numerous routines that come with the rstan package
  • use the routines that come with the bayesplot package
  • explore the diagnostics interactively via shinystan

We will explore all of these:
  • via coda
    • Traceplots
    • library(coda)
      s = as.array(data.rstan)
      mcmc <- do.call(mcmc.list, plyr:::alply(s[, , -(length(s[1, 1, ]))], 2, as.mcmc))
      plot(mcmc)
      
      plot of chunk tut7.2bSTANcodaTraceplots
      Trace plots show no evidence that the chains have not reasonably traversed the entire multidimensional parameter space.
    • Autocorrelation
    • library(coda)
      s = as.array(data.rstan)
      mcmc <- do.call(mcmc.list, plyr:::alply(s[, , -(length(s[1, 1, ]))], 2, as.mcmc))
      autocorr.diag(mcmc)
      
                  beta[1]       cbeta0        sigma       beta0
      Lag 0   1.000000000  1.000000000  1.000000000  1.00000000
      Lag 1   0.016316577  0.020651289  0.036121993  0.00965383
      Lag 5  -0.006799616 -0.039385336 -0.006821465 -0.02197035
      Lag 10  0.012913933  0.006045351 -0.018816878  0.01012661
      Lag 50 -0.028343488  0.015861053  0.007679815 -0.00919722
      
      Trace plots show no evidence that the chains have not reasonably traversed the entire multidimensional parameter space.
  • via rstan
    • Traceplots
      stan_trace(data.rstan)
      
      plot of chunk tut7.2bSTANTrace
      Trace plots show no evidence that the chains have not reasonably traversed the entire multidimensional parameter space.
    • Raftery diagnostic
      raftery.diag(data.rstan)
      
      Quantile (q) = 0.025
      Accuracy (r) = +/- 0.005
      Probability (s) = 0.95 
      
      You need a sample size of at least 3746 with these values of q, r and s
      
      The Raftery diagnostics for each chain estimate that we would require no more than 5000 samples to reach the specified level of confidence in convergence. As we have 16,667 samples, we can be confidence that convergence has occurred.
    • Autocorrelation diagnostic
      stan_ac(data.rstan)
      
      plot of chunk tut7.2bSTANAuto
      A lag of 2 appears broadly sufficient to avoid autocorrelation (poor mixing).
    • Rhat values. These values are a measure of sampling efficiency/effectiveness. Ideally, all values should be less than 1.05. If there are values of 1.05 or greater it suggests that the sampler was not very efficient or effective. Not only does this mean that the sampler was potentiall slower than it could have been, more importantly, it could indicate that the sampler spent time sampling in a region of the likelihood that is less informative. Such a situation can arise from either a misspecified model or overly vague priors that permit sampling in otherwise nonscence parameter space.
      stan_rhat(data.rstan)
      
      plot of chunk tut7.2bSTANRhat
      In this instance, all rhat values are well below 1.05 (a good thing).
    • Another measure of sampling efficiency is Effective Sample Size (ess). ess indicate the number samples (or proportion of samples that the sampling algorithm deamed effective. The sampler rejects samples on the basis of certain criterion and when it does so, the previous sample value is used. Hence while the MCMC sampling chain may contain 1000 samples, if there are only 10 effective samples (1%), the estimated properties are not likely to be reliable.
      stan_ess(data.rstan)
      
      plot of chunk tut7.2bSTANess
      In this instance, most of the parameters have reasonably high effective samples and thus there is likely to be a good range of values from which to estimate paramter properties.
  • via bayesplot
    • Trace plots and density plots
      library(bayesplot)
      mcmc_trace(as.array(data.rstan), regex_pars = "beta|sigma")
      
      plot of chunk tut7.2bSTANMCMCTrace
      library(bayesplot)
      mcmc_combo(as.array(data.rstan))
      
      plot of chunk tut7.2bSTANTrace1
      Trace plots show no evidence that the chains have not reasonably traversed the entire multidimensional parameter space.
    • Density plots
      library(bayesplot)
      mcmc_dens(as.array(data.rstan))
      
      plot of chunk tut7.2bSTANdens
      Density plots sugggest mean or median would be appropriate to describe the fixed posteriors and median is appropriate for the sigma posterior.
  • via shinystan
    						  library(shinystan)    
    						  launch_shinystan(data.rstan))      
    
  • It is worth exploring the influence of our priors.

Again, prior to examining the summaries, we should have explored the convergence diagnostics. There are numerous ways of working with STAN model fits (for exploring diagnostics and summarization).

  • extract the mcmc samples and convert them into a mcmc.list to leverage the various coda routines
  • use the numerous routines that come with the rstan package
  • use the routines that come with the bayesplot package
  • explore the diagnostics interactively via shinystan

We will explore all of these:
  • via coda
    • Traceplots
    • library(coda)
      s = as.array(data.rstanarm)
      mcmc <- do.call(mcmc.list, plyr:::alply(s[, , -(length(s[1, 1, ]))], 2, as.mcmc))
      plot(mcmc)
      
      plot of chunk tut7.2bRSTANARMcodaTraceplots
      Trace plots show no evidence that the chains have not reasonably traversed the entire multidimensional parameter space.
    • Autocorrelation
    • library(coda)
      s = as.array(data.rstanarm)
      mcmc <- do.call(mcmc.list, plyr:::alply(s[, , -(length(s[1, 1, ]))], 2, as.mcmc))
      autocorr.diag(mcmc)
      
              (Intercept)           x
      Lag 0   1.000000000  1.00000000
      Lag 1   0.053211483 -0.02917861
      Lag 5   0.004975124  0.01941260
      Lag 10 -0.033296048 -0.04010251
      Lag 50 -0.032866968 -0.01348437
      
      Trace plots show no evidence that the chains have not reasonably traversed the entire multidimensional parameter space.
  • via rstan
    • Traceplots
      stan_trace(data.rstanarm)
      
      plot of chunk tut7.2bRSTANARMTrace
      Trace plots show no evidence that the chains have not reasonably traversed the entire multidimensional parameter space.
    • Raftery diagnostic
      raftery.diag(data.rstanarm)
      
      Quantile (q) = 0.025
      Accuracy (r) = +/- 0.005
      Probability (s) = 0.95 
      
      You need a sample size of at least 3746 with these values of q, r and s
      
      The Raftery diagnostics for each chain estimate that we would require no more than 5000 samples to reach the specified level of confidence in convergence. As we have 16,667 samples, we can be confidence that convergence has occurred.
    • Autocorrelation diagnostic
      stan_ac(data.rstanarm)
      
      plot of chunk tut7.2bRSTANARMAuto
      A lag of 2 appears broadly sufficient to avoid autocorrelation (poor mixing).
    • Rhat values. These values are a measure of sampling efficiency/effectiveness. Ideally, all values should be less than 1.05. If there are values of 1.05 or greater it suggests that the sampler was not very efficient or effective. Not only does this mean that the sampler was potentiall slower than it could have been, more importantly, it could indicate that the sampler spent time sampling in a region of the likelihood that is less informative. Such a situation can arise from either a misspecified model or overly vague priors that permit sampling in otherwise nonscence parameter space.
      stan_rhat(data.rstanarm)
      
      plot of chunk tut7.2bRSTANARMRhat
      In this instance, all rhat values are well below 1.05 (a good thing).
    • Another measure of sampling efficiency is Effective Sample Size (ess). ess indicate the number samples (or proportion of samples that the sampling algorithm deamed effective. The sampler rejects samples on the basis of certain criterion and when it does so, the previous sample value is used. Hence while the MCMC sampling chain may contain 1000 samples, if there are only 10 effective samples (1%), the estimated properties are not likely to be reliable.
      stan_ess(data.rstanarm)
      
      plot of chunk tut7.2bRSTANARMess
      In this instance, most of the parameters have reasonably high effective samples and thus there is likely to be a good range of values from which to estimate paramter properties.
  • via bayesplot
    • Trace plots and density plots
      library(bayesplot)
      mcmc_trace(as.array(data.rstanarm), regex_pars = "Intercept|x|sigma")
      
      plot of chunk tut7.2bRSTANARMMCMCTrace
      library(bayesplot)
      mcmc_combo(as.array(data.rstanarm))
      
      plot of chunk tut7.2bRSTANARMTrace1
      Trace plots show no evidence that the chains have not reasonably traversed the entire multidimensional parameter space.
    • Density plots
      library(bayesplot)
      mcmc_dens(as.array(data.rstanarm))
      
      plot of chunk tut7.2bRSTANARMdens
      Density plots sugggest mean or median would be appropriate to describe the fixed posteriors and median is appropriate for the sigma posterior.
  • via rstanarm The rstanarm package provides additional posterior checks.
    • Posterior vs Prior - this compares the posterior estimate for each parameter against the associated prior. If the spread of the priors is small relative to the posterior, then it is likely that the priors are too influential. On the other hand, overly wide priors can lead to computational issues.
      library(rstanarm)
      posterior_vs_prior(data.rstanarm, color_by = "vs", group_by = TRUE,
          facet_args = list(scales = "free_y"))
      
      Gradient evaluation took 2.8e-05 seconds
      1000 transitions using 10 leapfrog steps per transition would take 0.28 seconds.
      Adjust your expectations accordingly!
      
      
      
       Elapsed Time: 1.96278 seconds (Warm-up)
                     0.039246 seconds (Sampling)
                     2.00202 seconds (Total)
      
      
      Gradient evaluation took 9e-06 seconds
      1000 transitions using 10 leapfrog steps per transition would take 0.09 seconds.
      Adjust your expectations accordingly!
      
      
      
       Elapsed Time: 2.48823 seconds (Warm-up)
                     0.054196 seconds (Sampling)
                     2.54242 seconds (Total)
      
      plot of chunk tut7.2bRSTANARMposterorvsprior
  • via shinystan
    						  library(shinystan) 
    						  launch_shinystan(data.rstanarm))      
    
  • It is worth exploring the influence of our priors.

Again, prior to examining the summaries, we should have explored the convergence diagnostics. There are numerous ways of working with STAN model fits (for exploring diagnostics and summarization).

  • extract the mcmc samples and convert them into a mcmc.list to leverage the various coda routines
  • use the numerous routines that come with the rstan package
  • use the routines that come with the bayesplot package
  • explore the diagnostics interactively via shinystan

We will explore all of these:
  • via coda
    • Traceplots
    • library(coda)
      mcmc = as.mcmc(data.brms)
      plot(mcmc)
      
      plot of chunk tut7.2bBRMScodaTraceplots
      Trace plots show no evidence that the chains have not reasonably traversed the entire multidimensional parameter space.
    • Autocorrelation
    • library(coda)
      mcmc = as.mcmc(data.brms)
      autocorr.diag(mcmc)
      
      Error in ts(x, start = start(x), end = end(x), deltat = thin(x)): invalid time series parameters specified
      
      Trace plots show no evidence that the chains have not reasonably traversed the entire multidimensional parameter space.
  • via rstan
    • Traceplots
      stan_trace(data.brms$fit)
      
      plot of chunk tut7.2bBRMSTrace
      Trace plots show no evidence that the chains have not reasonably traversed the entire multidimensional parameter space.
    • Raftery diagnostic
      raftery.diag(data.brms)
      
      Quantile (q) = 0.025
      Accuracy (r) = +/- 0.005
      Probability (s) = 0.95 
      
      You need a sample size of at least 3746 with these values of q, r and s
      
      The Raftery diagnostics for each chain estimate that we would require no more than 5000 samples to reach the specified level of confidence in convergence. As we have 16,667 samples, we can be confidence that convergence has occurred.
    • Autocorrelation diagnostic
      stan_ac(data.brms$fit)
      
      plot of chunk tut7.2bBRMSAuto
      A lag of 2 appears broadly sufficient to avoid autocorrelation (poor mixing).
    • Rhat values. These values are a measure of sampling efficiency/effectiveness. Ideally, all values should be less than 1.05. If there are values of 1.05 or greater it suggests that the sampler was not very efficient or effective. Not only does this mean that the sampler was potentiall slower than it could have been, more importantly, it could indicate that the sampler spent time sampling in a region of the likelihood that is less informative. Such a situation can arise from either a misspecified model or overly vague priors that permit sampling in otherwise nonscence parameter space.
      stan_rhat(data.brms$fit)
      
      plot of chunk tut7.2bBRMSRhat
      In this instance, all rhat values are well below 1.05 (a good thing).
    • Another measure of sampling efficiency is Effective Sample Size (ess). ess indicate the number samples (or proportion of samples that the sampling algorithm deamed effective. The sampler rejects samples on the basis of certain criterion and when it does so, the previous sample value is used. Hence while the MCMC sampling chain may contain 1000 samples, if there are only 10 effective samples (1%), the estimated properties are not likely to be reliable.
      stan_ess(data.brms$fit)
      
      plot of chunk tut7.2bBRMSess
      In this instance, most of the parameters have reasonably high effective samples and thus there is likely to be a good range of values from which to estimate paramter properties.

Model validation

Model validation involves exploring the model diagnostics and fit to ensure that the model is broadly appropriate for the data. As such, exploration of the residuals should be routine.

For more complex models (those that contain multiple effects, it is also advisable to plot the residuals against each of the individual predictors. For sampling designs that involve sample collection over space or time, it is also a good idea to explore whether there are any temporal or spatial patterns in the residuals.

There are numerous situations (e.g. when applying specific variance-covariance structures to a model) where raw residuals do not reflect the interior workings of the model. Typically, this is because they do not take into account the variance-covariance matrix or assume a very simple variance-covariance matrix. Since the purpose of exploring residuals is to evaluate the model, for these cases, it is arguably better to draw conclusions based on standardized (or studentized) residuals.

Unfortunately the definitions of standardized and studentized residuals appears to vary and the two terms get used interchangeably. I will adopt the following definitions:


Standardized residuals:the raw residuals divided by the true standard deviation of the residuals (which of course is rarely known).
Studentized residuals:the raw residuals divided by the standard deviation of the residuals.
Note that externally studentized residuals are calculated by dividing the raw residuals by a unique standard deviation for each observation that is calculated from regressions having left each successive observation out.
Pearson residuals:the raw residuals divided by the standard deviation of the response variable.

The mark of a good model is being able to predict well. In an ideal world, we would have sufficiently large sample size as to permit us to hold a fraction (such as 25%) back thereby allowing us to train the model on 75% of the data and then see how well the model can predict the withheld 25%. Unfortunately, such a luxury is still rare in ecology.

The next best option is to see how well the model can predict the observed data. Models tend to struggle most with the extremes of trends and have particular issues when the extremes approach logical boundaries (such as zero for count data and standard deviations). We can use the fitted model to generate random predicted observations and then explore some properties of these compared to the actual observed data.

Residuals are not computed directly within MCMCpack. However, we can calculate them manually form the posteriors.

mcmc = as.data.frame(data.mcmcpack)
# generate a model matrix
newdata = data.frame(x = data$x)
Xmat = model.matrix(~x, newdata)
## get median parameter estimates
coefs = apply(mcmc[, 1:2], 2, median)
fit = as.vector(coefs %*% t(Xmat))
resid = data$y - fit
ggplot() + geom_point(data = NULL, aes(y = resid, x = fit))
plot of chunk tut7.2bMCMCpackresid

Residuals against predictors

mcmc = as.data.frame(data.mcmcpack)
# generate a model matrix
newdata = data.frame(x = data$x)
Xmat = model.matrix(~x, newdata)
## get median parameter estimates
coefs = apply(mcmc[, 1:2], 2, median)
fit = as.vector(coefs %*% t(Xmat))
resid = data$y - fit
ggplot() + geom_point(data = NULL, aes(y = resid, x = data$x))
plot of chunk tut7.2bMCMCpackresid1

And now for studentized residuals

mcmc = as.data.frame(data.mcmcpack)
# generate a model matrix
newdata = data.frame(x = data$x)
Xmat = model.matrix(~x, newdata)
## get median parameter estimates
coefs = apply(mcmc[, 1:2], 2, median)
fit = as.vector(coefs %*% t(Xmat))
resid = data$y - fit
sresid = resid/sd(resid)
ggplot() + geom_point(data = NULL, aes(y = sresid, x = fit))
plot of chunk tut7.2bMCMCpackresid2

Conclusions: for this simple model, the studentized residuals yield the same pattern as the raw residuals (or the Pearson residuals for that matter).

Lets see how well data simulated from the model reflects the raw data

mcmc = as.matrix(data.mcmcpack)
# generate a model matrix
Xmat = model.matrix(~x, data)
## get median parameter estimates
coefs = mcmc[, 1:2]
fit = coefs %*% t(Xmat)
## draw samples from this model
yRep = sapply(1:nrow(mcmc), function(i) rnorm(nrow(data), fit[i,
    ], sqrt(mcmc[i, "sigma2"])))
ggplot() + geom_density(data = NULL, aes(x = as.vector(yRep),
    fill = "Model"), alpha = 0.5) + geom_density(data = data,
    aes(x = y, fill = "Obs"), alpha = 0.5)
plot of chunk tut7.2bMCMCpackFit

Although residuals can be computed directly within R2jags, we can calculate them manually from the posteriors to be consistent across other approaches.

mcmc = data.r2jags$BUGSoutput$sims.matrix[, c("beta0", "beta1")]
# generate a model matrix
newdata = data.frame(x = data$x)
Xmat = model.matrix(~x, newdata)
## get median parameter estimates
coefs = apply(mcmc, 2, median)
fit = as.vector(coefs %*% t(Xmat))
resid = data$y - fit
ggplot() + geom_point(data = NULL, aes(y = resid, x = fit))
plot of chunk tut7.2bR2JAGSresid

Residuals against predictors

mcmc = data.r2jags$BUGSoutput$sims.matrix[, c("beta0", "beta1")]
# generate a model matrix
newdata = data.frame(x = data$x)
Xmat = model.matrix(~x, newdata)
## get median parameter estimates
coefs = apply(mcmc, 2, median)
fit = as.vector(coefs %*% t(Xmat))
resid = data$y - fit
ggplot() + geom_point(data = NULL, aes(y = resid, x = data$x))
plot of chunk tut7.2bR2JAGSresid1

And now for studentized residuals

mcmc = data.r2jags$BUGSoutput$sims.matrix[, c("beta0", "beta1")]
# generate a model matrix
newdata = data.frame(x = data$x)
Xmat = model.matrix(~x, newdata)
## get median parameter estimates
coefs = apply(mcmc, 2, median)
fit = as.vector(coefs %*% t(Xmat))
resid = data$y - fit
sresid = resid/sd(resid)
ggplot() + geom_point(data = NULL, aes(y = sresid, x = fit))
plot of chunk tut7.2bR2JAGSresid2

Conclusions: for this simple model, the studentized residuals yield the same pattern as the raw residuals (or the Pearson residuals for that matter).

Lets see how well data simulated from the model reflects the raw data

mcmc = data.r2jags$BUGSoutput$sims.matrix
# generate a model matrix
Xmat = model.matrix(~x, data)
## get median parameter estimates
coefs = mcmc[, c("beta0", "beta1")]
fit = coefs %*% t(Xmat)
## draw samples from this model
yRep = sapply(1:nrow(mcmc), function(i) rnorm(nrow(data), fit[i,
    ], mcmc[i, "sigma2"]))
Error in mcmc[i, "sigma2"]: subscript out of bounds
ggplot() + geom_density(data = NULL, aes(x = as.vector(yRep),
    fill = "Model"), alpha = 0.5) + geom_density(data = data,
    aes(x = y, fill = "Obs"), alpha = 0.5)
plot of chunk tut7.2bJAGSFit

Although residuals can be computed directly within Rstan, we can calculate them manually from the posteriors to be consistent across other approaches.

mcmc = as.matrix(data.rstan)[, c("beta0", "beta[1]")]
# generate a model matrix
newdata = data.frame(x = data$x)
Xmat = model.matrix(~x, newdata)
## get median parameter estimates
coefs = apply(mcmc, 2, median)
fit = as.vector(coefs %*% t(Xmat))
resid = data$y - fit
ggplot() + geom_point(data = NULL, aes(y = resid, x = fit))
plot of chunk tut7.2bRSTANresid

Residuals against predictors

mcmc = as.matrix(data.rstan)[, c("beta0", "beta[1]")]
# generate a model matrix
newdata = data.frame(x = data$x)
Xmat = model.matrix(~x, newdata)
## get median parameter estimates
coefs = apply(mcmc, 2, median)
fit = as.vector(coefs %*% t(Xmat))
resid = data$y - fit
ggplot() + geom_point(data = NULL, aes(y = resid, x = data$x))
plot of chunk tut7.2bRSTANresid1

And now for studentized residuals

mcmc = as.matrix(data.rstan)[, c("beta0", "beta[1]")]
# generate a model matrix
newdata = data.frame(x = data$x)
Xmat = model.matrix(~x, newdata)
## get median parameter estimates
coefs = apply(mcmc, 2, median)
fit = as.vector(coefs %*% t(Xmat))
resid = data$y - fit
sresid = resid/sd(resid)
ggplot() + geom_point(data = NULL, aes(y = sresid, x = fit))
plot of chunk tut7.2bRSTANresid2

Conclusions: for this simple model, the studentized residuals yield the same pattern as the raw residuals (or the Pearson residuals for that matter).

Lets see how well data simulated from the model reflects the raw data

mcmc = as.matrix(data.rstan)
# generate a model matrix
Xmat = model.matrix(~x, data)
## get median parameter estimates
coefs = mcmc[, c("beta0", "beta[1]")]
fit = coefs %*% t(Xmat)
## draw samples from this model
yRep = sapply(1:nrow(mcmc), function(i) rnorm(nrow(data), fit[i, ], mcmc[i,
    "sigma"]))
ggplot() + geom_density(data = NULL, aes(x = as.vector(yRep), fill = "Model"),
    alpha = 0.5) + geom_density(data = data, aes(x = y, fill = "Obs"),
    alpha = 0.5)
plot of chunk tut7.2bRSTANFit

Residuals can be computed directly within RSTANARM.

resid = resid(data.rstanarm)
fit = fitted(data.rstanarm)
ggplot() + geom_point(data = NULL, aes(y = resid, x = fit))
plot of chunk tut7.2bRSTANARMresid

Residuals against predictors

resid = resid(data.rstanarm)
fit = fitted(data.rstanarm)
ggplot() + geom_point(data = NULL, aes(y = resid, x = data$x))
plot of chunk tut7.2bRSTANARMresid1

And now for studentized residuals

resid = resid(data.rstanarm)
sresid = resid/sd(resid)
fit = fitted(data.rstanarm)
ggplot() + geom_point(data = NULL, aes(y = sresid, x = fit))
plot of chunk tut7.2bRSTANARMresid2

Conclusions: for this simple model, the studentized residuals yield the same pattern as the raw residuals (or the Pearson residuals for that matter).

Lets compare draws (predictions) from the posterior (in blue) with the distributions of observed data (red) via violin plots. Violin plots are similar to boxplots except that they display more visual information about the density distribution.

y_pred = posterior_predict(data.rstanarm)
newdata = data %>% cbind(t(y_pred)) %>% gather(key = "Rep", value = "Value",
    -y, -x)
ggplot(newdata, aes(Value, x = x)) + geom_violin(color = "blue",
    fill = "blue", alpha = 0.5) + geom_violin(data = data, aes(y = y,
    x = x), fill = "red", color = "red", alpha = 0.5)
plot of chunk tut7.2bRSTANARMposteriorpredict
Conclusions - the posterior predictions match the observed data very well.

Yet another way to approach validation is to explore trends in posteriors in the context of the observed data.

## Calculate the fitted values
newdata = data.frame(x = seq(min(data$x, na.rm = TRUE), max(data$x,
    na.rm = TRUE), len = 1000))
fit = posterior_predict(data.rstanarm, newdata = newdata)
newdata = newdata %>% cbind(tidyMCMC(as.mcmc(fit), conf.int = TRUE,
    conf.method = "HPDinterval"))

ggplot(newdata, aes(y = estimate, x = x)) + geom_point(data = data,
    aes(y = y)) + geom_line() + geom_ribbon(aes(ymin = conf.low,
    ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_continuous("Y") +
    scale_x_continuous("X") + theme_classic()
plot of chunk tut7.2bRSTANARMGraphicalSummariesPosteriors

Conclusions the predicted trends do encapsulate the actual data, suggesting that the model is a reasonable representation of the underlying processes. Note, these are prediction intervals rather than confidence intervals as we are seeking intervals within which we can predict individual observations rather than means.

Residuals can be computed directly within BRMS. By default, the residuals and fitted extractor functions in brms return summarized versions (means, SE and credibility intervals). We are only interested in the mean (Estimate) estimates.

resid = resid(data.brms)[, "Estimate"]
fit = fitted(data.brms)[, "Estimate"]
ggplot() + geom_point(data = NULL, aes(y = resid, x = fit))
plot of chunk tut7.2bBRMSresid

Residuals against predictors

resid = resid(data.brms)[, "Estimate"]
fit = fitted(data.brms)[, "Estimate"]
ggplot() + geom_point(data = NULL, aes(y = resid, x = data$x))
plot of chunk tut7.2bBRMSresid1

And now for studentized residuals

resid = resid(data.brms)[, "Estimate"]
sresid = resid/sd(resid)
fit = fitted(data.brms)[, "Estimate"]
ggplot() + geom_point(data = NULL, aes(y = sresid, x = fit))
plot of chunk tut7.2bBRMSresid2

Conclusions: for this simple model, the studentized residuals yield the same pattern as the raw residuals (or the Pearson residuals for that matter).

Lets compare draws (predictions) from the posterior (in blue) with the distributions of observed data (red) via violin plots. Violin plots are similar to boxplots except that they display more visual information about the density distribution.

y_pred = posterior_predict(data.brms)
newdata = data %>% cbind(t(y_pred)) %>% gather(key = "Rep", value = "Value",
    -y, -x)
ggplot(newdata, aes(Value, x = x)) + geom_violin(color = "blue",
    fill = "blue", alpha = 0.5) + geom_violin(data = data, aes(y = y,
    x = x), fill = "red", color = "red", alpha = 0.5)
plot of chunk tut7.2bBRMSposteriorpredict
Conclusions - the posterior predictions match the observed data very well.

Yet another way to approach validation is to explore trends in posteriors in the context of the observed data.

## Calculate the fitted values
newdata = data.frame(x = seq(min(data$x, na.rm = TRUE), max(data$x,
    na.rm = TRUE), len = 1000))
fit = posterior_predict(data.brms, newdata = newdata)
newdata = newdata %>% cbind(tidyMCMC(as.mcmc(fit), conf.int = TRUE,
    conf.method = "HPDinterval"))

ggplot(newdata, aes(y = estimate, x = x)) + geom_point(data = data,
    aes(y = y)) + geom_line() + geom_ribbon(aes(ymin = conf.low,
    ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_continuous("Y") +
    scale_x_continuous("X") + theme_classic()
plot of chunk tut7.2bBRMSGraphicalSummariesPosteriors

Conclusions the predicted trends do encapsulate the actual data, suggesting that the model is a reasonable representation of the underlying processes. Note, these are prediction intervals rather than confidence intervals as we are seeking intervals within which we can predict individual observations rather than means.

Notwithstanding the slight issue of autocorrelation in the sigma2 samples, there is no evidence that the mcmc chain did not converge on a stable posterior distribution. We are now in a position to examine the summaries of the parameters.

Parameter estimates (posterior summaries)

Although all parameters in a Bayesian analysis are considered random and are considered a distribution, rarely would it be useful to present tables of all the samples from each distribution. On the other hand, plots of the posterior distributions are do have some use. Nevertheless, most workers prefer to present simple statistical summaries of the posteriors. Popular choices include the median (or mean) and 95% credibility intervals.

summary(data.mcmcpack)
Iterations = 1001:11000
Thinning interval = 1 
Number of chains = 1 
Sample size per chain = 10000 

1. Empirical mean and standard deviation for each variable,
   plus standard error of the mean:

              Mean      SD Naive SE Time-series SE
(Intercept) 40.788  2.9157 0.029157       0.028679
x           -1.538  0.3026 0.003026       0.003026
sigma2      30.453 14.0296 0.140296       0.162065

2. Quantiles for each variable:

              2.5%    25%    50%    75%   97.5%
(Intercept) 35.087 38.949 40.802 42.620 46.6754
x           -2.148 -1.729 -1.537 -1.349 -0.9395
sigma2      14.015 21.183 27.281 35.757 64.8614
# OR
library(broom)
tidyMCMC(data.mcmcpack, conf.int = TRUE, conf.method = "HPDinterval")
         term  estimate  std.error  conf.low  conf.high
1 (Intercept) 40.787840  2.9156846 34.694040 46.2035365
2           x -1.538321  0.3026426 -2.133656 -0.9323802
3      sigma2 30.452600 14.0295572 10.955592 56.7338303
Conclusions: a one unit increase in x is associated with a -1.5383211 change in y. That is, y declines at a rate of -1.5383211 per unit increase in x. The 95% confidence interval for the slope does not overlap with 0 implying a significant effect of x on y.

While workers attempt to become comfortable with a new statistical framework, it is only natural that they like to evaluate and comprehend new structures and output alongside more familiar concepts. One way to facilitate this is via Bayesian p-values that are somewhat analogous to the frequentist p-values for investigating the hypothesis that a parameter is equal to zero.

library(coda)
mcmcpvalue <- function(samp) {
    ## elementary version that creates an empirical p-value for the
    ## hypothesis that the columns of samp have mean zero versus a general
    ## multivariate distribution with elliptical contours.

    ## differences from the mean standardized by the observed
    ## variance-covariance factor

    ## Note, I put in the bit for single terms
    if (length(dim(samp)) == 0) {
        std <- backsolve(chol(var(samp)), cbind(0, t(samp)) - mean(samp),
            transpose = TRUE)
        sqdist <- colSums(std * std)
        sum(sqdist[-1] > sqdist[1])/length(samp)
    } else {
        std <- backsolve(chol(var(samp)), cbind(0, t(samp)) - colMeans(samp),
            transpose = TRUE)
        sqdist <- colSums(std * std)
        sum(sqdist[-1] > sqdist[1])/nrow(samp)
    }

}
## since values are less than zero
mcmcpvalue(data.mcmcpack[, 2])
[1] 2e-04

With a p-value of essentially 0, we would conclude that there is almost no evidence that the slope was likely to be equal to zero, suggesting there is a relationship.

print(data.r2jags)
Inference for Bugs model at "../downloads/BUGSscripts/tut7.2bS4.1.txt", fit using jags,
 3 chains, each with 53000 iterations (first 3000 discarded), n.thin = 10
 n.sims = 15000 iterations saved
         mu.vect sd.vect   2.5%    25%    50%     75%   97.5%  Rhat n.eff
beta0     40.776   3.012 34.771 38.854 40.754  42.700  46.732 1.001  6500
beta1     -1.536   0.309 -2.155 -1.739 -1.534  -1.339  -0.917 1.001  8800
sigma      5.612   1.198  3.825  4.765  5.433   6.244   8.454 1.001 15000
deviance  98.913   2.916 95.586 96.795 98.131 100.243 106.547 1.001 15000

For each parameter, n.eff is a crude measure of effective sample size,
and Rhat is the potential scale reduction factor (at convergence, Rhat=1).

DIC info (using the rule, pD = var(deviance)/2)
pD = 4.3 and DIC = 103.2
DIC is an estimate of expected predictive error (lower deviance is better).
# OR
library(broom)
tidyMCMC(as.mcmc(data.r2jags), conf.int = TRUE, conf.method = "HPDinterval")
      term  estimate std.error  conf.low   conf.high
1    beta0 40.776236 3.0118914 34.644637  46.5544619
2    beta1 -1.535883 0.3094887 -2.117052  -0.8847727
3 deviance 98.913094 2.9160662 95.342003 104.6398121
4    sigma  5.611529 1.1977617  3.510032   7.8862896
Conclusions: a one unit increase in x is associated with a -1.535883 change in y. That is, y declines at a rate of -1.535883 per unit increase in x. The 95% confidence interval for the slope does not overlap with 0 implying a significant effect of x on y.

While workers attempt to become comfortable with a new statistical framework, it is only natural that they like to evaluate and comprehend new structures and output alongside more familiar concepts. One way to facilitate this is via Bayesian p-values that are somewhat analogous to the frequentist p-values for investigating the hypothesis that a parameter is equal to zero.

library(coda)
mcmcpvalue <- function(samp) {
    ## elementary version that creates an empirical p-value for the
    ## hypothesis that the columns of samp have mean zero versus a general
    ## multivariate distribution with elliptical contours.

    ## differences from the mean standardized by the observed
    ## variance-covariance factor

    ## Note, I put in the bit for single terms
    if (length(dim(samp)) == 0) {
        std <- backsolve(chol(var(samp)), cbind(0, t(samp)) - mean(samp),
            transpose = TRUE)
        sqdist <- colSums(std * std)
        sum(sqdist[-1] > sqdist[1])/length(samp)
    } else {
        std <- backsolve(chol(var(samp)), cbind(0, t(samp)) - colMeans(samp),
            transpose = TRUE)
        sqdist <- colSums(std * std)
        sum(sqdist[-1] > sqdist[1])/nrow(samp)
    }

}
## since values are less than zero
mcmcpvalue(data.r2jags$BUGSoutput$sims.matrix[, c("beta1")])
[1] 0

With a p-value of essentially 0, we would conclude that there is almost no evidence that the slope was likely to be equal to zero, suggesting there is a relationship.

summary(data.rstan)
$summary
              mean     se_mean        sd       2.5%        25%        50%        75%       97.5%
beta[1]  -1.540077 0.005547721 0.2992531  -2.140083  -1.733530  -1.536049  -1.347254  -0.9578622
cbeta0   27.699678 0.026072380 1.4002154  24.952730  26.779818  27.686496  28.616701  30.4432020
sigma     5.378446 0.020515831 1.0852954   3.734084   4.614093   5.199031   5.958270   7.9476304
beta0    40.790336 0.053432423 2.9034858  35.075289  38.948498  40.737680  42.663585  46.4509997
lp__    -33.769878 0.026822294 1.3557193 -37.440064 -34.368897 -33.422015 -32.778343 -32.1970451
           n_eff      Rhat
beta[1] 2909.699 0.9994293
cbeta0  2884.220 1.0003349
sigma   2798.451 0.9995632
beta0   2952.770 0.9993640
lp__    2554.746 0.9995627

$c_summary
, , chains = chain:1

         stats
parameter       mean        sd       2.5%        25%        50%        75%       97.5%
  beta[1]  -1.531479 0.3068162  -2.109599  -1.735114  -1.539470  -1.334883  -0.9173666
  cbeta0   27.746909 1.4159460  24.954516  26.855717  27.747541  28.659675  30.4723348
  sigma     5.396365 1.0961031   3.734274   4.594885   5.232184   6.006155   7.8181447
  beta0    40.764477 3.0140699  34.540731  38.900198  40.880995  42.739393  46.5386786
  lp__    -33.809348 1.4068914 -37.550169 -34.393107 -33.462536 -32.782456 -32.1869446

, , chains = chain:2

         stats
parameter       mean        sd       2.5%        25%        50%        75%      97.5%
  beta[1]  -1.550123 0.2974626  -2.155754  -1.746184  -1.538468  -1.353810  -1.010301
  cbeta0   27.687988 1.3881674  25.134487  26.703722  27.683492  28.600342  30.383584
  sigma     5.402310 1.0729273   3.838954   4.640805   5.209596   5.950922   7.982861
  beta0    40.864033 2.8689516  35.483307  38.998427  40.801638  42.774958  46.193502
  lp__    -33.734080 1.3104041 -37.188086 -34.291847 -33.386710 -32.790364 -32.213962

, , chains = chain:3

         stats
parameter       mean        sd       2.5%        25%        50%        75%       97.5%
  beta[1]  -1.538631 0.2933243  -2.141996  -1.716454  -1.531518  -1.354423  -0.9678914
  cbeta0   27.664137 1.3964915  24.918672  26.754701  27.613705  28.591730  30.4340678
  sigma     5.336664 1.0866013   3.619856   4.595549   5.154616   5.908103   8.0011510
  beta0    40.742497 2.8255388  35.183039  38.892966  40.634539  42.437613  46.3971867
  lp__    -33.766205 1.3484235 -37.384673 -34.447354 -33.396535 -32.763341 -32.2065629
# OR
library(broom)
tidyMCMC(data.rstan, conf.int = TRUE, conf.method = "HPDinterval", rhat = TRUE, ess = TRUE)
     term  estimate std.error  conf.low  conf.high      rhat  ess
1 beta[1] -1.540077 0.2992531 -2.136075 -0.9571987 0.9994293 2910
2  cbeta0 27.699678 1.4002154 25.186804 30.6173088 1.0003349 2884
3   sigma  5.378446 1.0852954  3.487439  7.4980289 0.9995632 2798
4   beta0 40.790336 2.9034858 34.878535 46.2187799 0.9993640 2953
Conclusions: a one unit increase in x is associated with a -1.5400774 change in y. That is, y declines at a rate of -1.5400774 per unit increase in x. The 95% confidence interval for the slope does not overlap with 0 implying a significant effect of x on y.

While workers attempt to become comfortable with a new statistical framework, it is only natural that they like to evaluate and comprehend new structures and output alongside more familiar concepts. One way to facilitate this is via Bayesian p-values that are somewhat analogous to the frequentist p-values for investigating the hypothesis that a parameter is equal to zero.

Also note that since our STAN model incorporated predictor centering, we have estimates of the intercept based on both centered (cbeta0) and uncentered data (beta0). Since the intercept from uncentered data is beyond the domain of our sampling data it has very little interpretability. However, the intercept based on centered data can be interpreted as the estimate of the response at the mean predictor (in this case 27.699678).

library(coda)
mcmcpvalue <- function(samp) {
    ## elementary version that creates an empirical p-value for the
    ## hypothesis that the columns of samp have mean zero versus a general
    ## multivariate distribution with elliptical contours.

    ## differences from the mean standardized by the observed
    ## variance-covariance factor

    ## Note, I put in the bit for single terms
    if (length(dim(samp)) == 0) {
        std <- backsolve(chol(var(samp)), cbind(0, t(samp)) - mean(samp),
            transpose = TRUE)
        sqdist <- colSums(std * std)
        sum(sqdist[-1] > sqdist[1])/length(samp)
    } else {
        std <- backsolve(chol(var(samp)), cbind(0, t(samp)) - colMeans(samp),
            transpose = TRUE)
        sqdist <- colSums(std * std)
        sum(sqdist[-1] > sqdist[1])/nrow(samp)
    }

}
## since values are less than zero
mcmcpvalue(as.matrix(data.rstan)[, c("beta[1]")])
[1] 0

With a p-value of essentially 0, we would conclude that there is almost no evidence that the slope was likely to be equal to zero, suggesting there is a relationship.

summary(data.rstanarm)
Model Info:

 function:  stan_glm
 family:    gaussian [identity]
 formula:   y ~ x
 algorithm: sampling
 priors:    see help('prior_summary')
 sample:    2700 (posterior sample size)
 num obs:   16

Estimates:
                mean   sd    2.5%   25%   50%   75%   97.5%
(Intercept)    40.7    3.1  34.7   38.8  40.8  42.7  46.9  
x              -1.5    0.3  -2.2   -1.7  -1.5  -1.3  -0.9  
sigma           5.6    1.2   3.8    4.8   5.4   6.2   8.5  
mean_PPD       27.7    2.0  23.6   26.4  27.7  29.0  31.7  
log-posterior -65.2    1.3 -68.6  -65.8 -64.9 -64.2 -63.7  

Diagnostics:
              mcse Rhat n_eff
(Intercept)   0.1  1.0  2271 
x             0.0  1.0  2700 
sigma         0.0  1.0  1264 
mean_PPD      0.0  1.0  1808 
log-posterior 0.0  1.0  1078 

For each parameter, mcse is Monte Carlo standard error, n_eff is a crude measure of effective sample size, and Rhat is the potential scale reduction factor on split chains (at convergence Rhat=1).
# OR
library(broom)
tidyMCMC(data.rstanarm$stanfit, conf.int = TRUE, conf.method = "HPDinterval",
    rhat = TRUE, ess = TRUE)
           term   estimate std.error   conf.low   conf.high      rhat  ess
1   (Intercept)  40.734015 3.0668570  34.412462  46.3425366 1.0000549 2271
2             x  -1.531248 0.3148917  -2.123538  -0.8981083 1.0001968 2700
3         sigma   5.619764 1.1740461   3.604894   7.9675118 0.9996872 1264
4      mean_PPD  27.698236 2.0410524  23.858059  31.9079814 1.0002406 1808
5 log-posterior -65.225515 1.3374104 -67.797185 -63.5678144 1.0007470 1078
Conclusions: a one unit increase in x is associated with a -1.5312483 change in y. That is, y declines at a rate of -1.5312483 per unit increase in x. The 95% confidence interval for the slope does not overlap with 0 implying a significant effect of x on y.

While workers attempt to become comfortable with a new statistical framework, it is only natural that they like to evaluate and comprehend new structures and output alongside more familiar concepts. One way to facilitate this is via Bayesian p-values that are somewhat analogous to the frequentist p-values for investigating the hypothesis that a parameter is equal to zero.

library(coda)
mcmcpvalue <- function(samp) {
    ## elementary version that creates an empirical p-value for the
    ## hypothesis that the columns of samp have mean zero versus a general
    ## multivariate distribution with elliptical contours.

    ## differences from the mean standardized by the observed
    ## variance-covariance factor

    ## Note, I put in the bit for single terms
    if (length(dim(samp)) == 0) {
        std <- backsolve(chol(var(samp)), cbind(0, t(samp)) - mean(samp),
            transpose = TRUE)
        sqdist <- colSums(std * std)
        sum(sqdist[-1] > sqdist[1])/length(samp)
    } else {
        std <- backsolve(chol(var(samp)), cbind(0, t(samp)) - colMeans(samp),
            transpose = TRUE)
        sqdist <- colSums(std * std)
        sum(sqdist[-1] > sqdist[1])/nrow(samp)
    }

}
## since values are less than zero
mcmcpvalue(as.matrix(data.rstanarm)[, c("x")])
[1] 0

With a p-value of essentially 0, we would conclude that there is almost no evidence that the slope was likely to be equal to zero, suggesting there is a relationship.

Alternatively we can generate posterior intervals for each parameter.

posterior_interval(data.rstanarm, prob = 0.95)
                 2.5%      97.5%
(Intercept) 34.668050 46.8721257
x           -2.151347 -0.9122868
sigma        3.846747  8.4674463
Conclusions: the 95% confidence interval for the effect of x does not overlap with 0 implying a significant relationship.

An alternative way of quantifying the impact of a predictor is to compare models with and without the predictor. In a Bayesian context, this can be achieved by comparing the leave-one-out cross-validation statistics. Leave-one-out (LOO) cross-validation explores how well a series of models can predict withheld values (Vehtari, Gelman, and Gabry, 2016b). The LOO Information Criterion (LOOIC) is analogous to the AIC except that the LOOIC takes priors into consideration, does not assume that the posterior distribution is drawn from a multivariate normal and integrates over parameter uncertainty so as to yield a distribution of looic rather than just a point estimate. The LOOIC does however assume that all observations are equally influential (it does not matter which observations are left out). This assumption can be examined via the Pareta k estimate (values greater than 0.5 or more conservatively 0.75 are considered overly influential).

(full = loo(data.rstanarm))
Computed from 2700 by 16 log-likelihood matrix

         Estimate  SE
elpd_loo    -51.2 3.2
p_loo         2.9 1.3
looic       102.4 6.3

Pareto k diagnostic values:
                         Count  Pct 
(-Inf, 0.5]   (good)     15    93.8%
 (0.5, 0.7]   (ok)        1     6.2%
   (0.7, 1]   (bad)       0     0.0%
   (1, Inf)   (very bad)  0     0.0%

All Pareto k estimates are ok (k < 0.7)
See help('pareto-k-diagnostic') for details.
(reduced = loo(update(data.rstanarm, formula = . ~ 1)))
Gradient evaluation took 1.9e-05 seconds
1000 transitions using 10 leapfrog steps per transition would take 0.19 seconds.
Adjust your expectations accordingly!



 Elapsed Time: 0.00911 seconds (Warm-up)
               0.035428 seconds (Sampling)
               0.044538 seconds (Total)


Gradient evaluation took 2e-05 seconds
1000 transitions using 10 leapfrog steps per transition would take 0.2 seconds.
Adjust your expectations accordingly!



 Elapsed Time: 0.008509 seconds (Warm-up)
               0.034266 seconds (Sampling)
               0.042775 seconds (Total)


Gradient evaluation took 1.5e-05 seconds
1000 transitions using 10 leapfrog steps per transition would take 0.15 seconds.
Adjust your expectations accordingly!



 Elapsed Time: 0.011456 seconds (Warm-up)
               0.035874 seconds (Sampling)
               0.04733 seconds (Total)
Computed from 2700 by 16 log-likelihood matrix

         Estimate  SE
elpd_loo    -59.4 3.1
p_loo         2.1 1.0
looic       118.8 6.2

Pareto k diagnostic values:
                         Count  Pct 
(-Inf, 0.5]   (good)     15    93.8%
 (0.5, 0.7]   (ok)        0     0.0%
   (0.7, 1]   (bad)       1     6.2%
   (1, Inf)   (very bad)  0     0.0%
See help('pareto-k-diagnostic') for details.
par(mfrow = 1:2, mar = c(5, 3.8, 1, 0) + 0.1, las = 3)
plot(full, label_points = TRUE)
plot(reduced, label_points = TRUE)
plot of chunk tut7.2bRSTANARMloo
compare_models(full, reduced)
elpd_diff        se 
     -8.2       1.8 
Conclusions: the difference in expected out-of-sample predictive accuracy is lower than 0 suggesting that the full model (model containing the predictor) is better at predicting $y$ than the null model. Furthermore, the LOO AIC value is lower in the full model than the reduced model.
summary(data.brms)
 Family: gaussian(identity) 
Formula: y ~ x 
   Data: data (Number of observations: 16) 
Samples: 3 chains, each with iter = 2000; warmup = 200; thin = 2; 
         total post-warmup samples = 2700
    ICs: LOO = Not computed; WAIC = Not computed
 
Population-Level Effects: 
          Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
Intercept    40.85      3.07    34.90    47.24       2310    1
x            -1.55      0.32    -2.18    -0.90       2408    1

Family Specific Parameters: 
      Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
sigma     5.63      1.19      3.9     8.48       2091    1

Samples were drawn using sampling(NUTS). For each parameter, Eff.Sample 
is a crude measure of effective sample size, and Rhat is the potential 
scale reduction factor on split chains (at convergence, Rhat = 1).
# OR
library(broom)
tidyMCMC(data.brms$fit, conf.int = TRUE, conf.method = "HPDinterval", rhat = TRUE,
    ess = TRUE)
         term  estimate std.error  conf.low  conf.high     rhat  ess
1 b_Intercept 40.853729 3.0714471 34.407211 46.6638946 1.001079 2310
2         b_x -1.545095 0.3205355 -2.141672 -0.8693169 1.001133 2408
3       sigma  5.631356 1.1888245  3.779939  8.2153548 1.001264 2091
Conclusions: a one unit increase in x is associated with a -1.5450948 change in y. That is, y declines at a rate of -1.5450948 per unit increase in x. The 95% confidence interval for the slope does not overlap with 0 implying a significant effect of x on y.

Whilst workers attempt to become comfortable with a new statistical framework, it is only natural that they like to evaluate and comprehend new structures and output alongside more familiar concepts. One way to facilitate this is via Bayesian p-values that are somewhat analogous to the frequentist p-values for investigating the hypothesis that the two populations are identical (t=0).

library(coda)
mcmcpvalue <- function(samp) {
    ## elementary version that creates an empirical p-value for the
    ## hypothesis that the columns of samp have mean zero versus a general
    ## multivariate distribution with elliptical contours.

    ## differences from the mean standardized by the observed
    ## variance-covariance factor

    ## Note, I put in the bit for single terms
    if (length(dim(samp)) == 0) {
        std <- backsolve(chol(var(samp)), cbind(0, t(samp)) - mean(samp),
            transpose = TRUE)
        sqdist <- colSums(std * std)
        sum(sqdist[-1] > sqdist[1])/length(samp)
    } else {
        std <- backsolve(chol(var(samp)), cbind(0, t(samp)) - colMeans(samp),
            transpose = TRUE)
        sqdist <- colSums(std * std)
        sum(sqdist[-1] > sqdist[1])/nrow(samp)
    }

}
## since values are less than zero
mcmcpvalue(as.matrix(data.brms)[, c("b_x")])
[1] 0.0007407407

With a p-value of essentially 0, we would conclude that there is almost no evidence that the slope was likely to be equal to zero, suggesting there is a relationship.

Alternatively we can generate posterior intervals for each parameter.

posterior_interval(as.matrix(data.brms), prob = 0.95)
                  2.5%       97.5%
b_Intercept  34.899273  47.2408583
b_x          -2.179970  -0.8959258
sigma         3.895194   8.4787733
lp__        -36.892779 -31.5536581
Conclusions: the 95% confidence interval for the effect of x does not overlap with 0 implying a significant relationship.

An alternative way of quantifying the impact of a predictor is to compare models with and without the predictor. In a Bayesian context, this can be achieved by comparing the leave-one-out cross-validation statistics. Leave-one-out (LOO) cross-validation explores how well a series of models can predict withheld values (Vehtari, Gelman, and Gabry, 2016b). The LOO Information Criterion (LOOIC) is analogous to the AIC except that the LOOIC takes priors into consideration, does not assume that the posterior distribution is drawn from a multivariate normal and integrates over parameter uncertainty so as to yield a distribution of looic rather than just a point estimate. The LOOIC does however assume that all observations are equally influential (it does not matter which observations are left out). This assumption can be examined via the Pareta k estimate (values greater than 0.5 or more conservatively 0.75 are considered overly influential).

(full = loo(data.brms))
  LOOIC   SE
 102.43 6.22
(reduced = loo(update(data.brms, formula = . ~ 1)))
SAMPLING FOR MODEL 'gaussian(identity) brms-model' NOW (CHAIN 1).

Gradient evaluation took 1.7e-05 seconds
1000 transitions using 10 leapfrog steps per transition would take 0.17 seconds.
Adjust your expectations accordingly!


Iteration:    1 / 2000 [  0%]  (Warmup)
Iteration:  200 / 2000 [ 10%]  (Warmup)
Iteration:  400 / 2000 [ 20%]  (Warmup)
Iteration:  600 / 2000 [ 30%]  (Warmup)
Iteration:  800 / 2000 [ 40%]  (Warmup)
Iteration: 1000 / 2000 [ 50%]  (Warmup)
Iteration: 1001 / 2000 [ 50%]  (Sampling)
Iteration: 1200 / 2000 [ 60%]  (Sampling)
Iteration: 1400 / 2000 [ 70%]  (Sampling)
Iteration: 1600 / 2000 [ 80%]  (Sampling)
Iteration: 1800 / 2000 [ 90%]  (Sampling)
Iteration: 2000 / 2000 [100%]  (Sampling)

 Elapsed Time: 0.022215 seconds (Warm-up)
               0.029115 seconds (Sampling)
               0.05133 seconds (Total)


SAMPLING FOR MODEL 'gaussian(identity) brms-model' NOW (CHAIN 2).

Gradient evaluation took 1.9e-05 seconds
1000 transitions using 10 leapfrog steps per transition would take 0.19 seconds.
Adjust your expectations accordingly!


Iteration:    1 / 2000 [  0%]  (Warmup)
Iteration:  200 / 2000 [ 10%]  (Warmup)
Iteration:  400 / 2000 [ 20%]  (Warmup)
Iteration:  600 / 2000 [ 30%]  (Warmup)
Iteration:  800 / 2000 [ 40%]  (Warmup)
Iteration: 1000 / 2000 [ 50%]  (Warmup)
Iteration: 1001 / 2000 [ 50%]  (Sampling)
Iteration: 1200 / 2000 [ 60%]  (Sampling)
Iteration: 1400 / 2000 [ 70%]  (Sampling)
Iteration: 1600 / 2000 [ 80%]  (Sampling)
Iteration: 1800 / 2000 [ 90%]  (Sampling)
Iteration: 2000 / 2000 [100%]  (Sampling)

 Elapsed Time: 0.025044 seconds (Warm-up)
               0.021075 seconds (Sampling)
               0.046119 seconds (Total)


SAMPLING FOR MODEL 'gaussian(identity) brms-model' NOW (CHAIN 3).

Gradient evaluation took 6e-06 seconds
1000 transitions using 10 leapfrog steps per transition would take 0.06 seconds.
Adjust your expectations accordingly!


Iteration:    1 / 2000 [  0%]  (Warmup)
Iteration:  200 / 2000 [ 10%]  (Warmup)
Iteration:  400 / 2000 [ 20%]  (Warmup)
Iteration:  600 / 2000 [ 30%]  (Warmup)
Iteration:  800 / 2000 [ 40%]  (Warmup)
Iteration: 1000 / 2000 [ 50%]  (Warmup)
Iteration: 1001 / 2000 [ 50%]  (Sampling)
Iteration: 1200 / 2000 [ 60%]  (Sampling)
Iteration: 1400 / 2000 [ 70%]  (Sampling)
Iteration: 1600 / 2000 [ 80%]  (Sampling)
Iteration: 1800 / 2000 [ 90%]  (Sampling)
Iteration: 2000 / 2000 [100%]  (Sampling)

 Elapsed Time: 0.019155 seconds (Warm-up)
               0.022313 seconds (Sampling)
               0.041468 seconds (Total)


SAMPLING FOR MODEL 'gaussian(identity) brms-model' NOW (CHAIN 1).

Gradient evaluation took 1.1e-05 seconds
1000 transitions using 10 leapfrog steps per transition would take 0.11 seconds.
Adjust your expectations accordingly!


Iteration:    1 / 2000 [  0%]  (Warmup)
Iteration:  200 / 2000 [ 10%]  (Warmup)
Iteration:  400 / 2000 [ 20%]  (Warmup)
Iteration:  600 / 2000 [ 30%]  (Warmup)
Iteration:  800 / 2000 [ 40%]  (Warmup)
Iteration: 1000 / 2000 [ 50%]  (Warmup)
Iteration: 1001 / 2000 [ 50%]  (Sampling)
Iteration: 1200 / 2000 [ 60%]  (Sampling)
Iteration: 1400 / 2000 [ 70%]  (Sampling)
Iteration: 1600 / 2000 [ 80%]  (Sampling)
Iteration: 1800 / 2000 [ 90%]  (Sampling)
Iteration: 2000 / 2000 [100%]  (Sampling)

 Elapsed Time: 0.012441 seconds (Warm-up)
               0.018111 seconds (Sampling)
               0.030552 seconds (Total)


SAMPLING FOR MODEL 'gaussian(identity) brms-model' NOW (CHAIN 2).

Gradient evaluation took 3e-06 seconds
1000 transitions using 10 leapfrog steps per transition would take 0.03 seconds.
Adjust your expectations accordingly!


Iteration:    1 / 2000 [  0%]  (Warmup)
Iteration:  200 / 2000 [ 10%]  (Warmup)
Iteration:  400 / 2000 [ 20%]  (Warmup)
Iteration:  600 / 2000 [ 30%]  (Warmup)
Iteration:  800 / 2000 [ 40%]  (Warmup)
Iteration: 1000 / 2000 [ 50%]  (Warmup)
Iteration: 1001 / 2000 [ 50%]  (Sampling)
Iteration: 1200 / 2000 [ 60%]  (Sampling)
Iteration: 1400 / 2000 [ 70%]  (Sampling)
Iteration: 1600 / 2000 [ 80%]  (Sampling)
Iteration: 1800 / 2000 [ 90%]  (Sampling)
Iteration: 2000 / 2000 [100%]  (Sampling)

 Elapsed Time: 0.012443 seconds (Warm-up)
               0.016248 seconds (Sampling)
               0.028691 seconds (Total)


SAMPLING FOR MODEL 'gaussian(identity) brms-model' NOW (CHAIN 3).

Gradient evaluation took 1.6e-05 seconds
1000 transitions using 10 leapfrog steps per transition would take 0.16 seconds.
Adjust your expectations accordingly!


Iteration:    1 / 2000 [  0%]  (Warmup)
Iteration:  200 / 2000 [ 10%]  (Warmup)
Iteration:  400 / 2000 [ 20%]  (Warmup)
Iteration:  600 / 2000 [ 30%]  (Warmup)
Iteration:  800 / 2000 [ 40%]  (Warmup)
Iteration: 1000 / 2000 [ 50%]  (Warmup)
Iteration: 1001 / 2000 [ 50%]  (Sampling)
Iteration: 1200 / 2000 [ 60%]  (Sampling)
Iteration: 1400 / 2000 [ 70%]  (Sampling)
Iteration: 1600 / 2000 [ 80%]  (Sampling)
Iteration: 1800 / 2000 [ 90%]  (Sampling)
Iteration: 2000 / 2000 [100%]  (Sampling)

 Elapsed Time: 0.012169 seconds (Warm-up)
               0.015697 seconds (Sampling)
               0.027866 seconds (Total)
  LOOIC   SE
 118.26 6.03
par(mfrow = 1:2, mar = c(5, 3.8, 1, 0) + 0.1, las = 3)
plot(full, label_points = TRUE)
plot(reduced, label_points = TRUE)
plot of chunk tut7.2bBRMSloo

Graphical summaries

A nice graphic is often a great accompaniment to a statistical analysis. Although there are no fixed assumptions associated with graphing (in contrast to statistical analyses), we often want the graphical summaries to reflect the associated statistical analyses. After all, the sample is just one perspective on the population(s). What we are more interested in is being able to estimate and depict likely population parameters/trends.

Thus, whilst we could easily provide a plot displaying the raw data along with simple measures of location and spread, arguably, we should use estimates that reflect the fitted model. In this case, it would be appropriate to plot the credibility interval associated with each group.

mcmc = data.mcmcpack
## Calculate the fitted values
newdata = data.frame(x = seq(min(data$x, na.rm = TRUE), max(data$x, na.rm = TRUE),
    len = 1000))
Xmat = model.matrix(~x, newdata)
coefs = mcmc[, 1:2]
fit = coefs %*% t(Xmat)
newdata = newdata %>% cbind(tidyMCMC(fit, conf.int = TRUE, conf.method = "HPDinterval"))

ggplot(newdata, aes(y = estimate, x = x)) + geom_line() + geom_ribbon(aes(ymin = conf.low,
    ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_continuous("Y") +
    scale_x_continuous("X") + theme_classic()
plot of chunk tut7.2bMCMCpackGraphicalSummaries

If you wanted to represent sample data on the figure in such a simple example (single predictor) we could simply over- (or under-) lay the raw data.

ggplot(newdata, aes(y = estimate, x = x)) + geom_point(data = data, aes(y = y,
    x = x), color = "gray") + geom_line() + geom_ribbon(aes(ymin = conf.low,
    ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_continuous("Y") +
    scale_x_continuous("X") + theme_classic()
plot of chunk tut7.2bMCMCpackGraphicalSummaries1

A more general solution would be to add the partial residuals to the figure. Partial residuals are the fitted values plus the residuals. In this simple case, that equates to exactly the same as the raw observations since $resid = obs - fitted$ and the fitted values depend only on the single predictor we are interested in.

## Calculate partial residuals fitted values
fdata = rdata = data
fMat = rMat = model.matrix(~x, fdata)
fit = as.vector(apply(coefs, 2, median) %*% t(fMat))
resid = as.vector(data$y - apply(coefs, 2, median) %*% t(rMat))
rdata = rdata %>% mutate(partial.resid = resid + fit)
ggplot(newdata, aes(y = estimate, x = x)) + geom_point(data = rdata, aes(y = partial.resid),
    color = "gray") + geom_line() + geom_ribbon(aes(ymin = conf.low, ymax = conf.high),
    fill = "blue", alpha = 0.3) + scale_y_continuous("Y") + scale_x_continuous("X") +
    theme_classic()
plot of chunk tut7.2bMCMCpackGraphicalSummaries2
mcmc = data.r2jags$BUGSoutput$sims.matrix
## Calculate the fitted values
newdata = data.frame(x = seq(min(data$x, na.rm = TRUE), max(data$x, na.rm = TRUE),
    len = 1000))
Xmat = model.matrix(~x, newdata)
coefs = mcmc[, c("beta0", "beta1")]
fit = coefs %*% t(Xmat)
newdata = newdata %>% cbind(tidyMCMC(fit, conf.int = TRUE, conf.method = "HPDinterval"))
ggplot(newdata, aes(y = estimate, x = x)) + geom_line() + geom_ribbon(aes(ymin = conf.low,
    ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_continuous("Y") +
    scale_x_continuous("X") + theme_classic()
plot of chunk tut7.2bR2JAGSGraphicalSummaries

If you wanted to represent sample data on the figure in such a simple example (single predictor) we could simply over- (or under-) lay the raw data.

ggplot(newdata, aes(y = estimate, x = x)) + geom_point(data = data, aes(y = y,
    x = x), color = "gray") + geom_line() + geom_ribbon(aes(ymin = conf.low,
    ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_continuous("Y") +
    scale_x_continuous("X") + theme_classic()
plot of chunk tut7.2bR2JAGSGraphicalSummaries1

A more general solution would be to add the partial residuals to the figure. Partial residuals are the fitted values plus the residuals. In this simple case, that equates to exactly the same as the raw observations since $resid = obs - fitted $ and the fitted values depend only on the single predictor we are interested in.

## Calculate partial residuals fitted values
fdata = rdata = data
fMat = rMat = model.matrix(~x, fdata)
fit = as.vector(apply(coefs, 2, median) %*% t(fMat))
resid = as.vector(data$y - apply(coefs, 2, median) %*% t(rMat))
rdata = rdata %>% mutate(partial.resid = resid + fit)
ggplot(newdata, aes(y = estimate, x = x)) + geom_point(data = rdata, aes(y = partial.resid),
    color = "gray") + geom_line() + geom_ribbon(aes(ymin = conf.low, ymax = conf.high),
    fill = "blue", alpha = 0.3) + scale_y_continuous("Y") + scale_x_continuous("X") +
    theme_classic()
plot of chunk tut7.2bR2JAGSGraphicalSummaries2
mcmc = as.matrix(data.rstan)
## Calculate the fitted values
newdata = data.frame(x = seq(min(data$x, na.rm = TRUE), max(data$x, na.rm = TRUE),
    len = 1000))
Xmat = model.matrix(~x, newdata)
coefs = mcmc[, c("beta0", "beta[1]")]
fit = coefs %*% t(Xmat)
newdata = newdata %>% cbind(tidyMCMC(fit, conf.int = TRUE, conf.method = "HPDinterval"))
ggplot(newdata, aes(y = estimate, x = x)) + geom_line() + geom_ribbon(aes(ymin = conf.low,
    ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_continuous("Y") +
    scale_x_continuous("X") + theme_classic()
plot of chunk tut7.2bRSTANGraphicalSummaries

If you wanted to represent sample data on the figure in such a simple example (single predictor) we could simply over- (or under-) lay the raw data.

ggplot(newdata, aes(y = estimate, x = x)) + geom_point(data = data, aes(y = y,
    x = x), color = "gray") + geom_line() + geom_ribbon(aes(ymin = conf.low,
    ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_continuous("Y") +
    scale_x_continuous("X") + theme_classic()
plot of chunk tut7.2bRSTANGraphicalSummaries1

A more general solution would be to add the partial residuals to the figure. Partial residuals are the fitted values plus the residuals. In this simple case, that equates to exactly the same as the raw observations since $resid = obs - fitted $ and the fitted values depend only on the single predictor we are interested in.

## Calculate partial residuals fitted values
fdata = rdata = data
fMat = rMat = model.matrix(~x, fdata)
fit = as.vector(apply(coefs, 2, median) %*% t(fMat))
resid = as.vector(data$y - apply(coefs, 2, median) %*% t(rMat))
rdata = rdata %>% mutate(partial.resid = resid + fit)
ggplot(newdata, aes(y = estimate, x = x)) + geom_point(data = rdata, aes(y = partial.resid),
    color = "gray") + geom_line() + geom_ribbon(aes(ymin = conf.low, ymax = conf.high),
    fill = "blue", alpha = 0.3) + scale_y_continuous("Y") + scale_x_continuous("X") +
    theme_classic()
plot of chunk tut7.2bRSTANGraphicalSummaries2

Although we could calculated the fitted values via matrix multiplication of the coefficients and the model matrix (as for MCMCpack, RJAGS and RSTAN), for more complex models, it is more convenient to use the posterior_linpred function that comes with rstantools.

## Calculate the fitted values
newdata = data.frame(x = seq(min(data$x, na.rm = TRUE), max(data$x,
    na.rm = TRUE), len = 1000))
# fit = posterior_predict(data.rstanarm, newdata=newdata)
fit = posterior_linpred(data.rstanarm, newdata = newdata)
newdata = newdata %>% cbind(tidyMCMC(as.mcmc(fit), conf.int = TRUE,
    conf.method = "HPDinterval"))

ggplot(newdata, aes(y = estimate, x = x)) + geom_line() + geom_ribbon(aes(ymin = conf.low,
    ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_continuous("Y") +
    scale_x_continuous("X") + theme_classic()
plot of chunk tut7.2bRSTANARMGraphicalSummaries

If you wanted to represent sample data on the figure in such a simple example (single predictor) we could simply over- (or under-) lay the raw data.

ggplot(newdata, aes(y = estimate, x = x)) + geom_point(data = data, aes(y = y,
    x = x), color = "gray") + geom_line() + geom_ribbon(aes(ymin = conf.low,
    ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_continuous("Y") +
    scale_x_continuous("X") + theme_classic()
plot of chunk tut7.2bRSTANARMGraphicalSummaries1

A more general solution would be to add the partial residuals to the figure. Partial residuals are the fitted values plus the residuals. In this simple case, that equates to exactly the same as the raw observations since $resid = obs - fitted $ and the fitted values depend only on the single predictor we are interested in.

## Calculate partial residuals fitted values
fdata = rdata = data
pp = posterior_predict(data.rstanarm, newdata = fdata)
fit = as.vector(apply(pp, 2, median))
pp = posterior_predict(data.rstanarm, newdata = rdata)
resid = as.vector(data$y - apply(pp, 2, median))
rdata = rdata %>% mutate(partial.resid = resid + fit)
ggplot(newdata, aes(y = estimate, x = x)) + geom_point(data = rdata, aes(y = partial.resid),
    color = "gray") + geom_line() + geom_ribbon(aes(ymin = conf.low, ymax = conf.high),
    fill = "blue", alpha = 0.3) + scale_y_continuous("Y") + scale_x_continuous("X") +
    theme_classic()
plot of chunk tut7.2bRSTANARMGraphicalSummaries2

Although we could calculated the fitted values via matrix multiplication of the coefficients and the model matrix (as for MCMCpack, RJAGS and RSTAN), for more complex models, it is more convenient to use the marginal_effects function that comes with brms.

plot(marginal_effects(data.brms), points = TRUE)
plot of chunk tut7.2bBRMSGraphicalSummaries

It is also possible to just use the marginal_effects function to generate the partial effects data which can then be plotted manually. Just note the names of the columns produced...

newdata = marginal_effects(data.brms)$x
newdata %>% head
         x  y cond__ estimate__     se__  lower__  upper__
1 1.000000 NA      1   39.33572 2.555412 33.98311 45.12585
2 1.151515 NA      1   39.10511 2.518356 33.85225 44.80221
3 1.303030 NA      1   38.86400 2.479195 33.69083 44.46928
4 1.454545 NA      1   38.62627 2.446745 33.54161 44.15459
5 1.606061 NA      1   38.39589 2.400776 33.37734 43.84009
6 1.757576 NA      1   38.17167 2.362441 33.21209 43.50193
ggplot(newdata, aes(y = estimate__, x = x)) + geom_line() + geom_ribbon(aes(ymin = lower__,
    ymax = upper__), fill = "blue", alpha = 0.3) + scale_y_continuous("Y") +
    scale_x_continuous("X") + theme_classic()
plot of chunk tut7.2bBRMSGraphicalSummaries1

If you wanted to represent sample data on the figure in such a simple example (single predictor) we could simply over- (or under-) lay the raw data.

ggplot(newdata, aes(y = estimate__, x = x)) + geom_point(data = data, aes(y = y,
    x = x), color = "gray") + geom_line() + geom_ribbon(aes(ymin = lower__,
    ymax = upper__), fill = "blue", alpha = 0.3) + scale_y_continuous("Y") +
    scale_x_continuous("X") + theme_classic()
plot of chunk tut7.2bBRMSGraphicalSummaries2

A more general solution would be to add the partial residuals to the figure. Partial residuals are the fitted values plus the residuals. In this simple case, that equates to exactly the same as the raw observations since $resid = obs - fitted $ and the fitted values depend only on the single predictor we are interested in.

mcmc = as.matrix(data.brms)
## Calculate the fitted values
newdata = data.frame(x = seq(min(data$x, na.rm = TRUE), max(data$x, na.rm = TRUE),
    len = 1000))
Xmat = model.matrix(~x, newdata)
coefs = mcmc[, c("b_Intercept", "b_x")]
fit = coefs %*% t(Xmat)
newdata = newdata %>% cbind(tidyMCMC(fit, conf.int = TRUE, conf.method = "HPDinterval"))

## Calculate partial residuals fitted values
fdata = rdata = data
fMat = rMat = model.matrix(~x, fdata)
fit = as.vector(apply(coefs, 2, median) %*% t(fMat))
resid = as.vector(data$y - apply(coefs, 2, median) %*% t(rMat))
rdata = rdata %>% mutate(partial.resid = resid + fit)

ggplot(newdata, aes(y = estimate, x = x)) + geom_point(data = rdata, aes(y = partial.resid),
    color = "gray") + geom_line() + geom_ribbon(aes(ymin = conf.low, ymax = conf.high),
    fill = "blue", alpha = 0.3) + scale_y_continuous("Y") + scale_x_continuous("X") +
    theme_classic()
plot of chunk tut7.2bBRMSGraphicalSummaries3

Effect sizes

In addition to deriving the distribution means for the slope parameter, we could make use of the Bayesian framework to derive the distribution of the effect size. In so doing, effect size could be considered as either the rate of change or alternatively, the difference between pairs of values along the predictor gradient. For the latter case, there are multiple ways of calculating an effect size, but the two most common are:

Raw effect size
the difference between two groups (as already calculated)
Cohen's D
the effect size standardized by division with the pooled standard deviation $$ D = (\mu_A - \mu_B)/\sigma $$
Percent effect size
expressing the effect size as a percent of one of the pairs. That is, whether you expressing a percentage increase or a percentage decline depends on which of the pairs of values are considered a reference value. Care must be exercised to ensure no division by zeros occur.

For simple linear models, effect size based on a rate is essentially the same as above except that it is expressed per unit of the predictor. Of course in many instances, one unit change in the predictor represents too subtle a shift in the underlying gradient to likely yield any ecologically meaningful or appreciable change in response.

Lets explore a range of effect sizes:

  • Raw effect size between the largest and smallest x
  • Cohen's D
  • Percentage change between the largest and smallest x
  • Fractional change between the largest and smallest x

Probability that a change in x is associated with greater than a 25% decline in y. Clearly, in order to explore this inference, we must first express the change in y as a percentage. This in turn requires us to calculate start and end points from which to calculate the magnitude of the effect (amount of decline in y) as well as the percentage decline. Hence, we start by predicting the distribution of y at the lowest and highest values of x.

mcmc = data.mcmcpack
newdata = data.frame(x = c(min(data$x, na.rm = TRUE), max(data$x, na.rm = TRUE)))
Xmat = model.matrix(~x, newdata)
coefs = mcmc[, c("(Intercept)", "x")]
fit = coefs %*% t(Xmat)
## Raw effect size
(RES = tidyMCMC(as.mcmc(fit[, 2] - fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
  term  estimate std.error  conf.low conf.high
1 var1 -23.07482   4.53964 -32.00484  -13.9857
## Cohen's D
cohenD = (fit[, 2] - fit[, 1])/sqrt(mcmc[, "sigma2"])
(cohenDES = tidyMCMC(as.mcmc(cohenD), conf.int = TRUE, conf.method = "HPDinterval"))
  term estimate std.error  conf.low conf.high
1 var1 -4.43846  1.168116 -6.752846  -2.21918
# Percentage change (relative to Group A)
ESp = 100 * (fit[, 2] - fit[, 1])/fit[, 1]
(PES = tidyMCMC(as.mcmc(ESp), conf.int = TRUE, conf.method = "HPDinterval"))
  term  estimate std.error conf.low conf.high
1 var1 -58.38874  8.549874 -75.0835  -41.3122
# Probability that the effect is greater than 25% (a decline of >25%)
sum(-1 * ESp > 25)/length(ESp)
[1] 0.9986
## fractional change
fit = fit[fit[, 2] > 0, ]
(FES = tidyMCMC(as.mcmc(fit[, 2]/fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
  term  estimate  std.error conf.low conf.high
1 var1 0.4161556 0.08539488  0.24904 0.5865297

Conclusions:

  • On average, Y declines by -23.074816 over the observed range of x. We are 95% confident that the decline is between -32.0048416 and -13.9857023.
  • The Cohen's D associated with a change over the observed range of x is -4.4384597.
  • On average, Y declines by -58.389% over the observed range of x. We are 95% confident that the decline is between -75.084% and -41.312%.
  • The probability that Y declines by more than 25% over the observed range of x is 0.999.
  • On average, Y declines by a factor of 0.416% over the observed range of x. We are 95% confident that the decline is between a factor of 0.249% and 0.587%.

Lets explore a range of effect sizes:

  • Raw effect size between the largest and smallest x
  • Cohen's D
  • Percentage change between the largest and smallest x
  • Fractional change between the largest and smallest x

Probability that a change in x is associated with greater than a 25% decline in y. Clearly, in order to explore this inference, we must first express the change in y as a percentage. This in turn requires us to calculate start and end points from which to calculate the magnitude of the effect (amount of decline in y) as well as the percentage decline. Hence, we start by predicting the distribution of y at the lowest and highest values of x.

mcmc = data.r2jags$BUGSoutput$sims.matrix
newdata = data.frame(x = c(min(data$x, na.rm = TRUE), max(data$x, na.rm = TRUE)))
Xmat = model.matrix(~x, newdata)
coefs = mcmc[, c("beta0", "beta1")]
fit = coefs %*% t(Xmat)
## Raw effect size
(RES = tidyMCMC(as.mcmc(fit[, 2] - fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
  term  estimate std.error  conf.low conf.high
1 var1 -23.03824   4.64233 -31.75579 -13.27159
## Cohen's D
cohenD = (fit[, 2] - fit[, 1])/mcmc[, "sigma"]
(cohenDES = tidyMCMC(as.mcmc(cohenD), conf.int = TRUE, conf.method = "HPDinterval"))
  term  estimate std.error  conf.low conf.high
1 var1 -4.276647  1.166878 -6.610581 -2.039906
# Percentage change (relative to Group A)
ESp = 100 * (fit[, 2] - fit[, 1])/fit[, 1]
(PES = tidyMCMC(as.mcmc(ESp), conf.int = TRUE, conf.method = "HPDinterval"))
  term  estimate std.error  conf.low conf.high
1 var1 -58.28882  8.755287 -75.37096 -40.51335
# Probability that the effect is greater than 25% (a decline of >25%)
sum(-1 * ESp > 25)/length(ESp)
[1] 0.9982
## fractional change
fit = fit[fit[, 2] > 0, ]
(FES = tidyMCMC(as.mcmc(fit[, 2]/fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
  term  estimate  std.error  conf.low conf.high
1 var1 0.4171118 0.08755287 0.2462904 0.5948665

Conclusions:

  • On average, Y declines by -23.0382448 over the observed range of x. We are 95% confident that the decline is between -31.7557852 and -13.2715912.
  • The Cohen's D associated with a change over the observed range of x is -4.2766474.
  • On average, Y declines by -58.289% over the observed range of x. We are 95% confident that the decline is between -75.371% and -40.513%.
  • The probability that Y declines by more than 25% over the observed range of x is 0.998.
  • On average, Y declines by a factor of 0.417% over the observed range of x. We are 95% confident that the decline is between a factor of 0.246% and 0.595%.

Lets explore a range of effect sizes:

  • Raw effect size between the largest and smallest x
  • Cohen's D
  • Percentage change between the largest and smallest x
  • Fractional change between the largest and smallest x

Probability that a change in x is associated with greater than a 25% decline in y. Clearly, in order to explore this inference, we must first express the change in y as a percentage. This in turn requires us to calculate start and end points from which to calculate the magnitude of the effect (amount of decline in y) as well as the percentage decline. Hence, we start by predicting the distribution of y at the lowest and highest values of x.

mcmc = as.matrix(data.rstan)
newdata = data.frame(x = c(min(data$x, na.rm = TRUE), max(data$x, na.rm = TRUE)))
Xmat = model.matrix(~x, newdata)
coefs = mcmc[, c("beta0", "beta[1]")]
fit = coefs %*% t(Xmat)
## Raw effect size
(RES = tidyMCMC(as.mcmc(fit[, 2] - fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
  term  estimate std.error  conf.low conf.high
1 var1 -23.10116  4.488796 -32.04112 -14.35798
## Cohen's D
cohenD = (fit[, 2] - fit[, 1])/mcmc[, "sigma"]
(cohenDES = tidyMCMC(as.mcmc(cohenD), conf.int = TRUE, conf.method = "HPDinterval"))
  term  estimate std.error  conf.low conf.high
1 var1 -4.453289  1.150329 -6.766335 -2.289957
# Percentage change (relative to Group A)
ESp = 100 * (fit[, 2] - fit[, 1])/fit[, 1]
(PES = tidyMCMC(as.mcmc(ESp), conf.int = TRUE, conf.method = "HPDinterval"))
  term  estimate std.error  conf.low conf.high
1 var1 -58.46377  8.445858 -75.83271 -42.96449
# Probability that the effect is greater than 25% (a decline of >25%)
sum(-1 * ESp > 25)/length(ESp)
[1] 0.9993333
## fractional change
fit = fit[fit[, 2] > 0, ]
(FES = tidyMCMC(as.mcmc(fit[, 2]/fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
  term  estimate  std.error  conf.low conf.high
1 var1 0.4153623 0.08445858 0.2416729 0.5703551

Conclusions:

  • On average, Y declines by -23.101161 over the observed range of x. We are 95% confident that the decline is between -32.0411213 and -14.3579804.
  • The Cohen's D associated with a change over the observed range of x is -4.4532885.
  • On average, Y declines by -58.464% over the observed range of x. We are 95% confident that the decline is between -75.833% and -42.964%.
  • The probability that Y declines by more than 25% over the observed range of x is 0.999.
  • On average, Y declines by a factor of 0.415% over the observed range of x. We are 95% confident that the decline is between a factor of 0.242% and 0.570%.

Lets explore a range of effect sizes:

  • Raw effect size between the largest and smallest x
  • Cohen's D
  • Percentage change between the largest and smallest x
  • Fractional change between the largest and smallest x

Probability that a change in x is associated with greater than a 25% decline in y. Clearly, in order to explore this inference, we must first express the change in y as a percentage. This in turn requires us to calculate start and end points from which to calculate the magnitude of the effect (amount of decline in y) as well as the percentage decline. Hence, we start by predicting the distribution of y at the lowest and highest values of x.

mcmc = as.matrix(data.rstanarm)
newdata = data.frame(x = c(min(data$x, na.rm = TRUE), max(data$x, na.rm = TRUE)))
Xmat = model.matrix(~x, newdata)
coefs = mcmc[, c("(Intercept)", "x")]
fit = coefs %*% t(Xmat)
## Raw effect size
(RES = tidyMCMC(as.mcmc(fit[, 2] - fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
  term  estimate std.error  conf.low conf.high
1 var1 -22.96872  4.723375 -31.85307 -13.47162
## Cohen's D
cohenD = (fit[, 2] - fit[, 1])/mcmc[, "sigma"]
(cohenDES = tidyMCMC(as.mcmc(cohenD), conf.int = TRUE, conf.method = "HPDinterval"))
  term  estimate std.error  conf.low conf.high
1 var1 -4.252559   1.16655 -6.533503 -2.049772
# Percentage change (relative to Group A)
ESp = 100 * (fit[, 2] - fit[, 1])/fit[, 1]
(PES = tidyMCMC(as.mcmc(ESp), conf.int = TRUE, conf.method = "HPDinterval"))
  term  estimate std.error  conf.low conf.high
1 var1 -58.14203  8.945745 -74.70909 -39.84752
# Probability that the effect is greater than 25% (a decline of >25%)
sum(-1 * ESp > 25)/length(ESp)
[1] 0.9985185
## fractional change
fit = fit[fit[, 2] > 0, ]
(FES = tidyMCMC(as.mcmc(fit[, 2]/fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
  term  estimate  std.error  conf.low conf.high
1 var1 0.4185797 0.08945745 0.2529091 0.6015248

Conclusions:

  • On average, Y declines by -22.9687244 over the observed range of x. We are 95% confident that the decline is between -31.8530656 and -13.4716247.
  • The Cohen's D associated with a change over the observed range of x is -4.2525591.
  • On average, Y declines by -58.142% over the observed range of x. We are 95% confident that the decline is between -74.709% and -39.848%.
  • The probability that Y declines by more than 25% over the observed range of x is 0.999.
  • On average, Y declines by a factor of 0.419% over the observed range of x. We are 95% confident that the decline is between a factor of 0.253% and 0.602%.

Lets explore a range of effect sizes:

  • Raw effect size between the largest and smallest x
  • Cohen's D
  • Percentage change between the largest and smallest x
  • Fractional change between the largest and smallest x

Probability that a change in x is associated with greater than a 25% decline in y. Clearly, in order to explore this inference, we must first express the change in y as a percentage. This in turn requires us to calculate start and end points from which to calculate the magnitude of the effect (amount of decline in y) as well as the percentage decline. Hence, we start by predicting the distribution of y at the lowest and highest values of x.

mcmc = as.matrix(data.brms)
newdata = data.frame(x = c(min(data$x, na.rm = TRUE), max(data$x, na.rm = TRUE)))
Xmat = model.matrix(~x, newdata)
coefs = mcmc[, c("b_Intercept", "b_x")]
fit = coefs %*% t(Xmat)
## Raw effect size
(RES = tidyMCMC(as.mcmc(fit[, 2] - fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
  term  estimate std.error  conf.low conf.high
1 var1 -23.17642  4.808033 -32.12509 -13.03975
## Cohen's D
cohenD = (fit[, 2] - fit[, 1])/mcmc[, "sigma"]
(cohenDES = tidyMCMC(as.mcmc(cohenD), conf.int = TRUE, conf.method = "HPDinterval"))
  term estimate std.error  conf.low conf.high
1 var1 -4.28766  1.176568 -6.596148 -1.951322
# Percentage change (relative to Group A)
ESp = 100 * (fit[, 2] - fit[, 1])/fit[, 1]
(PES = tidyMCMC(as.mcmc(ESp), conf.int = TRUE, conf.method = "HPDinterval"))
  term  estimate std.error  conf.low conf.high
1 var1 -58.50167  9.213223 -75.36007 -39.18994
# Probability that the effect is greater than 25% (a decline of >25%)
sum(-1 * ESp > 25)/length(ESp)
[1] 0.9966667
## fractional change
fit = fit[fit[, 2] > 0, ]
(FES = tidyMCMC(as.mcmc(fit[, 2]/fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
  term  estimate  std.error  conf.low conf.high
1 var1 0.4149833 0.09213223 0.2463993 0.6081006

Conclusions:

  • On average, Y declines by -23.1764222 over the observed range of x. We are 95% confident that the decline is between -32.125086 and -13.0397529.
  • The Cohen's D associated with a change over the observed range of x is -4.2876597.
  • On average, Y declines by -58.502% over the observed range of x. We are 95% confident that the decline is between -75.360% and -39.190%.
  • The probability that Y declines by more than 25% over the observed range of x is 0.997.
  • On average, Y declines by a factor of 0.415% over the observed range of x. We are 95% confident that the decline is between a factor of 0.246% and 0.608%.

Posteriors

Finite Population Standard Deviations

Variance components, the amount of added variance attributed to each influence, are traditionally estimated for so called random effects. These are the effects for which the levels employed in the design are randomly selected to represent a broader range of possible levels. For such effects, effect sizes (differences between each level and a reference level) are of little value. Instead, the 'importance' of the variables are measured in units of variance components.

On the other hand, regular variance components for fixed factors (those whose measured levels represent the only levels of interest) are not logical - since variance components estimate variance as if the levels are randomly selected from a larger population. Nevertheless, in order to compare and contrast the scale of variability of both fixed and random factors, it is necessary to measure both on the same scale (sample or population based variance).

Finite-population variance components (Gelman, 2005) assume that the levels of all factors (fixed and random) in the design are all the possible levels available. In other words, they are assumed to represent finite populations of levels. Sample (rather than population) statistics are then used to calculate these finite-population variances (or standard deviations).

Since standard deviation (and variance) are bound at zero, standard deviation posteriors are typically non-normal. Consequently, medians and HPD intervals are more robust estimates.

library(broom)
mcmc = data.mcmcpack
sd.x = abs(mcmc[, "x"]) * sd(data$x)
# generate a model matrix
newdata = data.frame(x = data$x)
Xmat = model.matrix(~x, newdata)
## get median parameter estimates
coefs = mcmc[, 1:2]
fit = coefs %*% t(Xmat)
resid = sweep(fit, 2, data$y, "-")
sd.resid = apply(resid, 1, sd)
sd.all = cbind(sd.x, sd.resid)
(fpsd = tidyMCMC(sd.all, conf.int = TRUE, conf.method = "HPDinterval"))
      term estimate std.error conf.low conf.high
1     sd.x 7.324011 1.4401645 4.439017 10.158235
2 sd.resid 5.113917 0.3125066 4.916653  5.689996
# OR expressed as a percentage
(fpsd.p = tidyMCMC(100 * sd.all/rowSums(sd.all), estimate.method = "median",
    conf.int = TRUE, conf.method = "HPDinterval"))
      term estimate std.error conf.low conf.high
1     sd.x 59.81066  5.410107 48.00330  64.16565
2 sd.resid 40.18934  5.410107 35.83435  51.99670
## we can even plot this as a Bayesian ANOVA table
ggplot(fpsd, aes(y = estimate, x = term)) + geom_pointrange(aes(ymin = conf.low,
    ymax = conf.high)) + geom_text(aes(label = sprintf("%.2f%%", fpsd.p$estimate),
    vjust = -1)) + scale_y_continuous("Finite population standard deviation") +
    scale_x_discrete() + coord_flip() + theme_classic()
plot of chunk tut7.2bMCMCpackFinitePopulation

Conclusions: Approximately 59.8% of the total finite population standard deviation is due to x.

library(broom)
mcmc = data.r2jags$BUGSoutput$sims.matrix
sd.x = abs(mcmc[, "beta1"]) * sd(data$x)
# generate a model matrix
newdata = data.frame(x = data$x)
Xmat = model.matrix(~x, newdata)
## get median parameter estimates
coefs = mcmc[, 1:2]
fit = coefs %*% t(Xmat)
resid = sweep(fit, 2, data$y, "-")
sd.resid = apply(resid, 1, sd)
sd.all = cbind(sd.x, sd.resid)
(fpsd = tidyMCMC(sd.all, conf.int = TRUE, conf.method = "HPDinterval"))
      term estimate std.error conf.low conf.high
1     sd.x 7.312266 1.4734608 4.212361 10.079185
2 sd.resid 5.123532 0.3064685 4.916653  5.728441
# OR expressed as a percentage
(fpsd.p = tidyMCMC(100 * sd.all/rowSums(sd.all), estimate.method = "median",
    conf.int = TRUE, conf.method = "HPDinterval"))
      term estimate std.error conf.low conf.high
1     sd.x 59.76241  5.634456 47.19196  64.16565
2 sd.resid 40.23759  5.634456 35.83435  52.80804
## we can even plot this as a Bayesian ANOVA table
ggplot(fpsd, aes(y = estimate, x = term)) + geom_pointrange(aes(ymin = conf.low,
    ymax = conf.high)) + geom_text(aes(label = sprintf("%.2f%%", fpsd.p$estimate),
    vjust = -1)) + scale_y_continuous("Finite population standard deviation") +
    scale_x_discrete() + coord_flip() + theme_classic()
plot of chunk tut7.2bJAGSFinitePopulation

Conclusions: Approximately 59.8% of the total finite population standard deviation is due to x.

library(broom)
mcmc = as.matrix(data.rstan)
sd.x = abs(mcmc[, "beta[1]"]) * sd(data$x)
# generate a model matrix
newdata = data.frame(x = data$x)
Xmat = model.matrix(~x, newdata)
## get median parameter estimates
coefs = mcmc[, c("beta0", "beta[1]")]
fit = coefs %*% t(Xmat)
resid = sweep(fit, 2, data$y, "-")
sd.resid = apply(resid, 1, sd)
sd.all = cbind(sd.x, sd.resid)
(fpsd = tidyMCMC(sd.all, conf.int = TRUE, conf.method = "HPDinterval"))
      term estimate std.error conf.low conf.high
1     sd.x 7.332235 1.4247297 4.557177 10.169750
2 sd.resid 5.110913 0.2865312 4.916653  5.666491
# OR expressed as a percentage
(fpsd.p = tidyMCMC(100 * sd.all/rowSums(sd.all), estimate.method = "median",
    conf.int = TRUE, conf.method = "HPDinterval"))
      term estimate std.error conf.low conf.high
1     sd.x 59.79741  5.318334 48.03619  64.16563
2 sd.resid 40.20259  5.318334 35.83437  51.96381
## we can even plot this as a Bayesian ANOVA table
ggplot(fpsd, aes(y = estimate, x = term)) + geom_pointrange(aes(ymin = conf.low,
    ymax = conf.high)) + geom_text(aes(label = sprintf("%.2f%%", fpsd.p$estimate),
    vjust = -1)) + scale_y_continuous("Finite population standard deviation") +
    scale_x_discrete() + coord_flip() + theme_classic()
plot of chunk tut7.2bRSTANFinitePopulation

Conclusions: Approximately 59.8% of the total finite population standard deviation is due to x.

library(broom)
mcmc = as.matrix(data.rstanarm)
sd.x = abs(mcmc[, "x"]) * sd(data$x)
# generate a model matrix
newdata = data.frame(x = data$x)
Xmat = model.matrix(~x, newdata)
## get median parameter estimates
coefs = mcmc[, 1:2]
fit = coefs %*% t(Xmat)
resid = sweep(fit, 2, data$y, "-")
sd.resid = apply(resid, 1, sd)
sd.all = cbind(sd.x, sd.resid)
(fpsd = tidyMCMC(sd.all, conf.int = TRUE, conf.method = "HPDinterval"))
      term estimate std.error conf.low conf.high
1     sd.x 7.290200 1.4991843 4.275851 10.110062
2 sd.resid 5.130423 0.3148904 4.916653  5.738437
# OR expressed as a percentage
(fpsd.p = tidyMCMC(100 * sd.all/rowSums(sd.all), estimate.method = "median",
    conf.int = TRUE, conf.method = "HPDinterval"))
      term estimate std.error conf.low conf.high
1     sd.x 59.72643  5.864832 46.65895  64.16561
2 sd.resid 40.27357  5.864832 35.83439  53.34105
## we can even plot this as a Bayesian ANOVA table
ggplot(fpsd, aes(y = estimate, x = term)) + geom_pointrange(aes(ymin = conf.low,
    ymax = conf.high)) + geom_text(aes(label = sprintf("%.2f%%", fpsd.p$estimate),
    vjust = -1)) + scale_y_continuous("Finite population standard deviation") +
    scale_x_discrete() + coord_flip() + theme_classic()
plot of chunk tut7.2bRSTANARMFinitePopulation

Conclusions: Approximately 59.7% of the total finite population standard deviation is due to x.

library(broom)
mcmc = as.matrix(data.brms)
sd.x = abs(mcmc[, "b_x"]) * sd(data$x)
# generate a model matrix
newdata = data.frame(x = data$x)
Xmat = model.matrix(~x, newdata)
## get median parameter estimates
coefs = mcmc[, 1:2]
fit = coefs %*% t(Xmat)
resid = sweep(fit, 2, data$y, "-")
sd.resid = apply(resid, 1, sd)
sd.all = cbind(sd.x, sd.resid)
(fpsd = tidyMCMC(sd.all, conf.int = TRUE, conf.method = "HPDinterval"))
      term estimate std.error conf.low conf.high
1     sd.x 7.357990 1.5170233 4.138776 10.196400
2 sd.resid 5.135858 0.3567607 4.916653  5.786968
# OR expressed as a percentage
(fpsd.p = tidyMCMC(100 * sd.all/rowSums(sd.all), estimate.method = "median",
    conf.int = TRUE, conf.method = "HPDinterval"))
      term estimate std.error conf.low conf.high
1     sd.x 59.88833   5.89935 46.88813  64.16558
2 sd.resid 40.11167   5.89935 35.83442  53.11187
## we can even plot this as a Bayesian ANOVA table
ggplot(fpsd, aes(y = estimate, x = term)) + geom_pointrange(aes(ymin = conf.low,
    ymax = conf.high)) + geom_text(aes(label = sprintf("%.2f%%", fpsd.p$estimate),
    vjust = -1)) + scale_y_continuous("Finite population standard deviation") +
    scale_x_discrete() + coord_flip() + theme_classic()
plot of chunk tut7.2bBRMSFinitePopulation

Conclusions: Approximately 59.9% of the total finite population standard deviation is due to x.

$R^2$

In a frequentist context, the $R^2$ value is seen as a useful indicator of goodness of fit. Whilst it has long been acknowledged that this measure is not appropriate for comparing models (for such purposes information criterion such as AIC are more appropriate), it is nevertheless useful for estimating the amount (percent) of variance explained by the model.

In a frequentist context, $R^2$ is calculated as the variance in predicted values divided by the variance in the observed (response) values. Unfortunately, this classical formulation does not translate simply into a Bayesian context since the equivalently calculated numerator can be larger than the an equivalently calculated denominator - thereby resulting in an $R^2$ greater than 100%. Gelman, Goodrich, Gabry, and Ali (2017) proposed an alternative formulation in which the denominator comprises the sum of the explained variance and the variance of the residuals.

So in the standard regression model notation of: $$ \begin{align} y_i \sim{}& N(\mu_i, \sigma)\\ \mu_i =& \mathbf{X}\boldsymbol{\beta} \end{align} $$ The $R^2$ could be formulated as: $$ R^2 = \frac{\sigma^2_f}{\sigma^2_f + \sigma^2_e} $$ where $\sigma^2_f = var(\mu)$, ($\mu = \mathbf{X}\boldsymbol{\beta})$) and for Gaussian models $\sigma^2_e = var(y-\mu)$

library(broom)
mcmc <- data.mcmcpack
Xmat = model.matrix(~x, data)
coefs = mcmc[, c("(Intercept)", "x")]
fit = coefs %*% t(Xmat)
resid = sweep(fit, 2, data$y, "-")
var_f = apply(fit, 1, var)
var_e = apply(resid, 1, var)
R2 = var_f/(var_f + var_e)
tidyMCMC(as.mcmc(R2), conf.int = TRUE, conf.method = "HPDinterval")
  term  estimate  std.error  conf.low conf.high
1 var1 0.6596643 0.09983966 0.4601296 0.7622622
# for comparison with frequentist
summary(lm(y ~ x, data))
Call:
lm(formula = y ~ x, data = data)

Residuals:
     Min       1Q   Median       3Q      Max 
-11.3455  -3.5205   0.6545   2.6319   7.3650 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)   40.747      2.669  15.268 4.03e-10 ***
x             -1.534      0.276  -5.558 7.06e-05 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 5.089 on 14 degrees of freedom
Multiple R-squared:  0.6881,	Adjusted R-squared:  0.6658 
F-statistic: 30.89 on 1 and 14 DF,  p-value: 7.057e-05
library(broom)
mcmc <- data.r2jags$BUGSoutput$sims.matrix
Xmat = model.matrix(~x, data)
coefs = mcmc[, c("beta0", "beta1")]
fit = coefs %*% t(Xmat)
resid = sweep(fit, 2, data$y, "-")
var_f = apply(fit, 1, var)
var_e = apply(resid, 1, var)
R2 = var_f/(var_f + var_e)
tidyMCMC(as.mcmc(R2), conf.int = TRUE, conf.method = "HPDinterval")
  term  estimate std.error  conf.low conf.high
1 var1 0.6573356 0.1040998 0.4440158 0.7622622
# for comparison with frequentist
summary(lm(y ~ x, data))
Call:
lm(formula = y ~ x, data = data)

Residuals:
     Min       1Q   Median       3Q      Max 
-11.3455  -3.5205   0.6545   2.6319   7.3650 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)   40.747      2.669  15.268 4.03e-10 ***
x             -1.534      0.276  -5.558 7.06e-05 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 5.089 on 14 degrees of freedom
Multiple R-squared:  0.6881,	Adjusted R-squared:  0.6658 
F-statistic: 30.89 on 1 and 14 DF,  p-value: 7.057e-05
library(broom)
mcmc <- as.matrix(data.rstan)
Xmat = model.matrix(~x, data)
coefs = mcmc[, c("beta0", "beta[1]")]
fit = coefs %*% t(Xmat)
resid = sweep(fit, 2, data$y, "-")
var_f = apply(fit, 1, var)
var_e = apply(resid, 1, var)
R2 = var_f/(var_f + var_e)
tidyMCMC(as.mcmc(R2), conf.int = TRUE, conf.method = "HPDinterval")
  term  estimate std.error  conf.low conf.high
1 var1 0.6604948  0.098497 0.4607843 0.7622619
# for comparison with frequentist
summary(lm(y ~ x, data))
Call:
lm(formula = y ~ x, data = data)

Residuals:
     Min       1Q   Median       3Q      Max 
-11.3455  -3.5205   0.6545   2.6319   7.3650 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)   40.747      2.669  15.268 4.03e-10 ***
x             -1.534      0.276  -5.558 7.06e-05 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 5.089 on 14 degrees of freedom
Multiple R-squared:  0.6881,	Adjusted R-squared:  0.6658 
F-statistic: 30.89 on 1 and 14 DF,  p-value: 7.057e-05
library(broom)
mcmc <- as.matrix(data.rstanarm)
Xmat = model.matrix(~x, data)
coefs = mcmc[, c("(Intercept)", "x")]
fit = coefs %*% t(Xmat)
resid = sweep(fit, 2, data$y, "-")
var_f = apply(fit, 1, var)
var_e = apply(resid, 1, var)
R2 = var_f/(var_f + var_e)
tidyMCMC(as.mcmc(R2), conf.int = TRUE, conf.method = "HPDinterval")
  term  estimate std.error conf.low conf.high
1 var1 0.6548455  0.107712 0.433476 0.7622615
# for comparison with frequentist
summary(lm(y ~ x, data))
Call:
lm(formula = y ~ x, data = data)

Residuals:
     Min       1Q   Median       3Q      Max 
-11.3455  -3.5205   0.6545   2.6319   7.3650 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)   40.747      2.669  15.268 4.03e-10 ***
x             -1.534      0.276  -5.558 7.06e-05 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 5.089 on 14 degrees of freedom
Multiple R-squared:  0.6881,	Adjusted R-squared:  0.6658 
F-statistic: 30.89 on 1 and 14 DF,  p-value: 7.057e-05
library(broom)
mcmc <- as.matrix(data.brms)
Xmat = model.matrix(~x, data)
coefs = mcmc[, c("b_Intercept", "b_x")]
fit = coefs %*% t(Xmat)
resid = sweep(fit, 2, data$y, "-")
var_f = apply(fit, 1, var)
var_e = apply(resid, 1, var)
R2 = var_f/(var_f + var_e)
tidyMCMC(as.mcmc(R2), conf.int = TRUE, conf.method = "HPDinterval")
  term  estimate std.error  conf.low conf.high
1 var1 0.6588937  0.107873 0.4380028 0.7622611
# for comparison with frequentist
summary(lm(y ~ x, data))
Call:
lm(formula = y ~ x, data = data)

Residuals:
     Min       1Q   Median       3Q      Max 
-11.3455  -3.5205   0.6545   2.6319   7.3650 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)   40.747      2.669  15.268 4.03e-10 ***
x             -1.534      0.276  -5.558 7.06e-05 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 5.089 on 14 degrees of freedom
Multiple R-squared:  0.6881,	Adjusted R-squared:  0.6658 
F-statistic: 30.89 on 1 and 14 DF,  p-value: 7.057e-05

References

Gelman, A. (2005). “Analysis of Variance - Why it is More Important Than Ever”. In: The Annals of Statistics 33.1, pp. 1–53.

Gelman, A., B. Goodrich, J. Gabry, et al. (2017). “R-squared for Bayesian regression models”.

Gelman, A. and J. Hill (2007). Data Analysis Using Regression and Multilevel/hierarchical Models. Cambridge, UK: Cambridge University Press.

Kery, M. (2010). Introduction to WinBUGS for Ecologists: Bayesian approach to regression, ANOVA, mixed models and related analyses. 1st ed. Academic Press. ISBN: 0123786053. URL: http://www.amazon.com/exec/obidos/redirect?tag=citeulike07-20\&path=ASIN/0123786053.

Logan, M. (2010). Biostatistical Design and Analysis Using R, a practical guide. Wiley-Blackwell.

McCarthy, M. A. (2007). Bayesian methods for ecology. Cambridge, Massachusetts: Cambridge University Press. ISBN: 0521615593. URL: http://www.amazon.com/exec/obidos/redirect?tag=citeulike07-20\&path=ASIN/0521615593.

Quinn, G. P. and K. J. Keough (2002). Experimental design and data analysis for biologists. London: Cambridge University Press.

Vehtari, A, A. Gelman and J. Gabry (2016b). “Practical Bayesian model evaluation using leave-one-out cross-validation and WAIC”. In: Statistics and Computing.




Worked Examples

Simple linear regression

Here is an example from Fowler, Cohen and Parvis (1998). An agriculturalist was interested in the effects of fertilizer load on the yield of grass. Grass seed was sown uniformly over an area and different quantities of commercial fertilizer were applied to each of ten 1 m2 randomly located plots. Two months later the grass from each plot was harvested, dried and weighed. The data are in the file fertilizer.csv.

Download Fertilizer data set
Format of fertilizer.csv data files
FERTILIZERYIELD
2584
5080
7590
100154
125148
......

FERTILIZERMass of fertilizer (g.m-2) - Predictor variable
YIELDYield of grass (g.m-2) - Response variable
turf

Open the fertilizer dataset

Show code
fert <- read.table("../downloads/data/fertilizer.csv", header = T, sep = ",", strip.white = T)
fert
   FERTILIZER YIELD
1          25    84
2          50    80
3          75    90
4         100   154
5         125   148
6         150   169
7         175   206
8         200   244
9         225   212
10        250   248

  1. The artificial researchers were most likely interested in investigating whether there was a relationship between grass yield and fertilizer concentration. Write out an appropriate linear model.
  2. Perform exploratory data analysis to help guide what sort of analysis will be suitable and whether the various assumptions are likely to be met.
    Show code
    ggplot(fert, aes(y = YIELD, x = FERTILIZER)) + geom_point()
    
    plot of chunk tut7.2bQ1.1
    ggplot(fert, aes(y = YIELD, x = 1)) + geom_boxplot()
    
    plot of chunk tut7.2bQ1.1
  3. Fit the appropriate Bayesian model.
    Show MCMCpack code
    library(MCMCpack)
    fert.mcmcpack = MCMCregress(YIELD ~ FERTILIZER, data = fert)
    
    Show JAGS code
            modelString=" 
    	model {
    	#Likelihood
    	for (i in 1:n) {
    	yield[i]~dnorm(mu[i],tau)
    	mu[i] <- alpha+beta*fertilizer[i]
    	}
    	
    	#Priors
    	alpha ~ dnorm (0.01,1.0E-6)
    	beta ~ dnorm(0,1.0E-6)
    	tau <- 1 / (sigma * sigma)
    	sigma~dgamma(0.001,0.001)
    	}
    	"
            ## write the model to a text file (I suggest you alter the path to somewhere more relevant 
            ## to your system!)  
            writeLines(modelString,con="../downloads/BUGSscripts/tut7.2bQ1_JAGS.txt")
    
            fert.list <- with(fert,
            list(fertilizer=FERTILIZER,
            yield=YIELD,n=nrow(fert))
            )
    
            #inits <- rep(list(list(alpha=mean(fert$YIELD), beta=0,
            #		 sigma=sd(fert$YIELD))),3) 
    
            params <- c("alpha","beta","sigma")
            burnInSteps = 2000
            nChains = 3
            numSavedSteps = 50000
            thinSteps = 10
            nIter = ceiling((numSavedSteps * thinSteps)/nChains)
    
            fert.r2jags <- jags(data=fert.list,
            inits=NULL, #or inits=list(inits,inits,inits) # since there are three chains
            parameters.to.save=params,
            model.file="../downloads/BUGSscripts/tut7.2bQ1_JAGS.txt",
            n.chains=nChains,
            n.iter=nIter,
            n.burnin=burnInSteps,
            n.thin=thinSteps
            )
    
    Compiling model graph
       Resolving undeclared variables
       Allocating nodes
    Graph information:
       Observed stochastic nodes: 10
       Unobserved stochastic nodes: 3
       Total graph size: 53
    
    Initializing model
    
    Show RSTAN code
    modelString = " 
    data { 
    int<lower=1> n;   // total number of observations 
    vector[n] Y;      // response variable 
    int<lower=1> nX;  // number of effects 
    matrix[n, nX] X;   // model matrix 
    } 
    ransformed data { 
    matrix[n, nX - 1] Xc;  // centered version of X 
    vector[nX - 1] means_X;  // column means of X before centering 
    
    for (i in 2:nX) { 
    means_X[i - 1] = mean(X[, i]); 
    Xc[, i - 1] = X[, i] - means_X[i - 1]; 
    }  
    } 
    parameters { 
    vector[nX-1] beta;  // population-level effects 
    real cbeta0;  // center-scale intercept 
    real<lower=0> sigma;  // residual SD 
    } 
    ransformed parameters { 
    } 
    model { 
    vector[n] mu; 
    mu = Xc * beta + cbeta0; 
    // prior specifications 
    beta ~ normal(0, 100); 
    cbeta0 ~ normal(0, 100); 
    sigma ~ cauchy(0, 5); 
    // likelihood contribution 
    Y ~ normal(mu, sigma); 
    } 
    generated quantities { 
    real beta0;  // population-level intercept 
    beta0 = cbeta0 - dot_product(means_X, beta); 
    }
    "
    
    Xmat <- model.matrix(~FERTILIZER, data = fert)
    fert.list <- with(fert, list(Y = YIELD, X = Xmat, nX = ncol(Xmat), n = nrow(fert)))
    
    library(rstan)
    fert.rstan <- stan(data = fert.list, model_code = modelString, chains = 3, iter = 5000, warmup = 500,
        thin = 2)
    
    In file included from /usr/local/lib/R/site-library/BH/include/boost/config.hpp:39:0,
                     from /usr/local/lib/R/site-library/BH/include/boost/math/tools/config.hpp:13,
                     from /usr/local/lib/R/site-library/StanHeaders/include/stan/math/rev/core/var.hpp:7,
                     from /usr/local/lib/R/site-library/StanHeaders/include/stan/math/rev/core/gevv_vvv_vari.hpp:5,
                     from /usr/local/lib/R/site-library/StanHeaders/include/stan/math/rev/core.hpp:12,
                     from /usr/local/lib/R/site-library/StanHeaders/include/stan/math/rev/mat.hpp:4,
                     from /usr/local/lib/R/site-library/StanHeaders/include/stan/math.hpp:4,
                     from /usr/local/lib/R/site-library/StanHeaders/include/src/stan/model/model_header.hpp:4,
                     from file39d3243970d.cpp:8:
    /usr/local/lib/R/site-library/BH/include/boost/config/compiler/gcc.hpp:186:0: warning: "BOOST_NO_CXX11_RVALUE_REFERENCES" redefined
     #  define BOOST_NO_CXX11_RVALUE_REFERENCES
     ^
    <command-line>:0:0: note: this is the location of the previous definition
    
    SAMPLING FOR MODEL 'c89e04c2495a0b6eb4be2b406df0876b' NOW (CHAIN 1).
    
    Gradient evaluation took 1e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.1 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration:  501 / 5000 [ 10%]  (Sampling)
    Iteration: 1000 / 5000 [ 20%]  (Sampling)
    Iteration: 1500 / 5000 [ 30%]  (Sampling)
    Iteration: 2000 / 5000 [ 40%]  (Sampling)
    Iteration: 2500 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.019704 seconds (Warm-up)
                   0.059723 seconds (Sampling)
                   0.079427 seconds (Total)
    
    
    SAMPLING FOR MODEL 'c89e04c2495a0b6eb4be2b406df0876b' NOW (CHAIN 2).
    
    Gradient evaluation took 5e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.05 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration:  501 / 5000 [ 10%]  (Sampling)
    Iteration: 1000 / 5000 [ 20%]  (Sampling)
    Iteration: 1500 / 5000 [ 30%]  (Sampling)
    Iteration: 2000 / 5000 [ 40%]  (Sampling)
    Iteration: 2500 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.012823 seconds (Warm-up)
                   0.062457 seconds (Sampling)
                   0.07528 seconds (Total)
    
    
    SAMPLING FOR MODEL 'c89e04c2495a0b6eb4be2b406df0876b' NOW (CHAIN 3).
    
    Gradient evaluation took 1.5e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.15 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration:  501 / 5000 [ 10%]  (Sampling)
    Iteration: 1000 / 5000 [ 20%]  (Sampling)
    Iteration: 1500 / 5000 [ 30%]  (Sampling)
    Iteration: 2000 / 5000 [ 40%]  (Sampling)
    Iteration: 2500 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.018759 seconds (Warm-up)
                   0.07513 seconds (Sampling)
                   0.093889 seconds (Total)
    
    Show RSTANARM code
    fert.rstanarm = stan_glm(YIELD ~ FERTILIZER, data = fert, iter = 5000, warmup = 500, chains = 3, thin = 2,
        refresh = 0, prior_intercept = normal(0, 1000), prior = normal(0, 1000), prior_aux = cauchy(0, 25))
    
    Gradient evaluation took 1.7e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.17 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 2.87974 seconds (Warm-up)
                   1.8448 seconds (Sampling)
                   4.72454 seconds (Total)
    
    
    Gradient evaluation took 1e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.1 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 1.88517 seconds (Warm-up)
                   1.45586 seconds (Sampling)
                   3.34103 seconds (Total)
    
    
    Gradient evaluation took 1e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.1 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 2.30701 seconds (Warm-up)
                   1.26275 seconds (Sampling)
                   3.56975 seconds (Total)
    
    Show BRMS code
    fert.brm = brm(YIELD ~ FERTILIZER, data = fert, iter = 5000, warmup = 500, chains = 3, thin = 2, refresh = 0,
        prior = c(prior(normal(0, 1000), class = "Intercept"), prior(normal(0, 1000), class = "b"), prior(cauchy(0,
            25), class = "sigma")))
    
    Gradient evaluation took 1e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.1 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.019368 seconds (Warm-up)
                   0.085001 seconds (Sampling)
                   0.104369 seconds (Total)
    
    
    Gradient evaluation took 5e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.05 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.018599 seconds (Warm-up)
                   0.062118 seconds (Sampling)
                   0.080717 seconds (Total)
    
    
    Gradient evaluation took 6e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.06 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.018222 seconds (Warm-up)
                   0.063125 seconds (Sampling)
                   0.081347 seconds (Total)
    
  4. Explore MCMC diagnostics
    Show MCMCpack code
    library(MCMCpack)
    plot(fert.mcmcpack)
    
    plot of chunk tut7.2bQ1.3a
    raftery.diag(fert.mcmcpack)
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
                                                       
                 Burn-in  Total Lower bound  Dependence
                 (M)      (N)   (Nmin)       factor (I)
     (Intercept) 3        4267  3746         1.140     
     FERTILIZER  3        4129  3746         1.100     
     sigma2      2        3680  3746         0.982     
    
    autocorr.diag(fert.mcmcpack)
    
            (Intercept)    FERTILIZER       sigma2
    Lag 0   1.000000000  1.0000000000 1.0000000000
    Lag 1  -0.004037621 -0.0114692120 0.2554797754
    Lag 5  -0.004986237  0.0054805924 0.0092656838
    Lag 10 -0.012538601 -0.0161207640 0.0009712328
    Lag 50 -0.001201054 -0.0005511779 0.0037849556
    
    Show JAGS code
    library(R2jags)
    library(coda)
    fert.mcmc = as.mcmc(fert.r2jags)
    plot(fert.mcmc)
    
    plot of chunk tut7.2bQ1.3b
    raftery.diag(fert.mcmc)
    
    [[1]]
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
                                                    
              Burn-in  Total Lower bound  Dependence
              (M)      (N)   (Nmin)       factor (I)
     alpha    20       36350 3746          9.70     
     beta     20       38210 3746         10.20     
     deviance 20       38020 3746         10.10     
     sigma    20       37270 3746          9.95     
    
    
    [[2]]
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
                                                    
              Burn-in  Total Lower bound  Dependence
              (M)      (N)   (Nmin)       factor (I)
     alpha    20       38020 3746         10.10     
     beta     10       37440 3746          9.99     
     deviance 20       37640 3746         10.00     
     sigma    20       37830 3746         10.10     
    
    
    [[3]]
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
                                                    
              Burn-in  Total Lower bound  Dependence
              (M)      (N)   (Nmin)       factor (I)
     alpha    20       37080 3746          9.90     
     beta     10       37440 3746          9.99     
     deviance 20       37830 3746         10.10     
     sigma    20       37000 3746          9.88     
    
    autocorr.diag(fert.mcmc)
    
                    alpha          beta     deviance        sigma
    Lag 0    1.0000000000  1.0000000000  1.000000000  1.000000000
    Lag 10  -0.0044127316 -0.0023406056  0.004963650  0.015916804
    Lag 50  -0.0060828419 -0.0028847071  0.004949708 -0.001727307
    Lag 100  0.0057039932  0.0030810054 -0.005268254  0.002371374
    Lag 500 -0.0005423204 -0.0008620483  0.010255930  0.008363875
    
    Show RSTAN code
    library(rstan)
    library(coda)
    s = as.array(fert.rstan)
    fert.mcmc <- do.call(mcmc.list, plyr:::alply(s[, , -(length(s[1, 1, ]))], 2, as.mcmc))
    plot(fert.mcmc)
    
    plot of chunk tut7.2bQ1.3c
    raftery.diag(fert.mcmc)
    
    $`1`
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
    
    You need a sample size of at least 3746 with these values of q, r and s
    
    $`2`
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
    
    You need a sample size of at least 3746 with these values of q, r and s
    
    $`3`
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
    
    You need a sample size of at least 3746 with these values of q, r and s
    
    autocorr.diag(fert.mcmc)
    
                beta[1]     cbeta0         sigma        beta0
    Lag 0   1.000000000 1.00000000  1.0000000000  1.000000000
    Lag 1   0.059317207 0.07926084  0.1737320913  0.068192640
    Lag 5  -0.001646535 0.01350466  0.0209769999 -0.011735998
    Lag 10 -0.011774603 0.01984983  0.0006350554 -0.001634785
    Lag 50 -0.008110674 0.02465931 -0.0189181231  0.009131390
    
    library(rstan)
    library(coda)
    stan_ac(fert.rstan)
    
    plot of chunk tut7.2bQ1.3c1
    stan_rhat(fert.rstan)
    
    plot of chunk tut7.2bQ1.3c1
    stan_ess(fert.rstan)
    
    plot of chunk tut7.2bQ1.3c1
    # using Bayeseplot
    library(bayesplot)
    detach("package:reshape")
    mcmc_trace(as.array(fert.rstan))
    
    plot of chunk tut7.2bQ1.3c2
    mcmc_trace(as.array(fert.rstan), regex_pars = "beta|sigma")
    
    plot of chunk tut7.2bQ1.3c2
    mcmc_dens(as.array(fert.rstan))
    
    plot of chunk tut7.2bQ1.3c2
    detach("package:reshape")
    library(bayesplot)
    mcmc_combo(as.array(fert.rstan))
    
    plot of chunk tut7.2bQ1.3c3
    Show RSTANARM code
    library(rstan)
    library(coda)
    s = as.array(fert.rstanarm)
    fert.mcmc <- do.call(mcmc.list, plyr:::alply(s[, , -(length(s[1, 1, ]))], 2, as.mcmc))
    plot(fert.mcmc)
    
    plot of chunk tut7.2bQ1.3d
    raftery.diag(fert.mcmc)
    
    $`1`
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
    
    You need a sample size of at least 3746 with these values of q, r and s
    
    $`2`
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
    
    You need a sample size of at least 3746 with these values of q, r and s
    
    $`3`
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
    
    You need a sample size of at least 3746 with these values of q, r and s
    
    autocorr.diag(fert.mcmc)
    
             (Intercept)    FERTILIZER
    Lag 0   1.000000e+00  1.000000e+00
    Lag 1   9.245402e-02  2.710592e-02
    Lag 5   2.809036e-03  8.528322e-03
    Lag 10 -2.278203e-03 -6.860284e-05
    Lag 50 -5.866553e-05 -6.178508e-03
    
    library(rstan)
    library(coda)
    stan_ac(fert.rstanarm)
    
    plot of chunk tut7.2bQ1.3d1
    stan_rhat(fert.rstanarm)
    
    plot of chunk tut7.2bQ1.3d1
    stan_ess(fert.rstanarm)
    
    plot of chunk tut7.2bQ1.3d1
    # using Bayeseplot
    library(bayesplot)
    detach("package:reshape")
    mcmc_trace(as.array(fert.rstanarm))
    
    plot of chunk tut7.2bQ1.3d2
    mcmc_trace(as.array(fert.rstanarm), regex_pars = "Intercept|FERT|sigma")
    
    plot of chunk tut7.2bQ1.3d2
    mcmc_dens(as.array(fert.rstanarm))
    
    plot of chunk tut7.2bQ1.3d2
    detach("package:reshape")
    library(bayesplot)
    mcmc_combo(as.array(fert.rstanarm))
    
    plot of chunk tut7.2bQ1.3d3
    library(rstanarm)
    posterior_vs_prior(fert.rstanarm, color_by = "vs", group_by = TRUE, facet_args = list(scales = "free_y"))
    
    Gradient evaluation took 2.5e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.25 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 2.7357 seconds (Warm-up)
                   0.034422 seconds (Sampling)
                   2.77012 seconds (Total)
    
    
    Gradient evaluation took 1.2e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.12 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 3.71385 seconds (Warm-up)
                   0.031524 seconds (Sampling)
                   3.74537 seconds (Total)
    
    plot of chunk tut7.2bQ1.3d4
    Show BRMS code
    library(coda)
    library(brms)
    fert.mcmc = as.mcmc(fert.brm)
    plot(fert.mcmc)
    
    plot of chunk tut7.2bQ1.3e
    raftery.diag(fert.mcmc)
    
    [[1]]
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
    
    You need a sample size of at least 3746 with these values of q, r and s
    
    [[2]]
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
    
    You need a sample size of at least 3746 with these values of q, r and s
    
    [[3]]
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
    
    You need a sample size of at least 3746 with these values of q, r and s
    
    autocorr.diag(fert.mcmc)
    
    Error in ts(x, start = start(x), end = end(x), deltat = thin(x)): invalid time series parameters specified
    
    library(coda)
    stan_ac(fert.brm$fit)
    
    plot of chunk tut7.2bQ1.3e1
    stan_rhat(fert.brm$fit)
    
    plot of chunk tut7.2bQ1.3e1
    stan_ess(fert.brm$fit)
    
    plot of chunk tut7.2bQ1.3e1
  5. Perform model validation
    Show MCMCpack code
    library(MCMCpack)
    fert.mcmc = as.data.frame(fert.mcmcpack)
    # generate a model matrix
    newdata = data.frame(FERTILIZER = fert$FERTILIZER)
    Xmat = model.matrix(~FERTILIZER, newdata)
    ## get median parameter estimates
    coefs = apply(fert.mcmc[, 1:2], 2, median)
    fit = as.vector(coefs %*% t(Xmat))
    resid = fert$YIELD - fit
    ggplot() + geom_point(data = NULL, aes(y = resid, x = fit))
    
    plot of chunk tut7.2bQ1.4a1
    library(MCMCpack)
    fert.mcmc = as.data.frame(fert.mcmcpack)
    # generate a model matrix
    newdata = data.frame(FERTILIZER = fert$FERTILIZER)
    Xmat = model.matrix(~FERTILIZER, newdata)
    ## get median parameter estimates
    coefs = apply(fert.mcmc[, 1:2], 2, median)
    fit = as.vector(coefs %*% t(Xmat))
    resid = fert$YIELD - fit
    ggplot() + geom_point(data = NULL, aes(y = resid, x = fert$FERTILIZER))
    
    plot of chunk tut7.2bQ1.4a2
    library(MCMCpack)
    fert.mcmc = as.data.frame(fert.mcmcpack)
    # generate a model matrix
    newdata = data.frame(FERTILIZER = fert$FERTILIZER)
    Xmat = model.matrix(~FERTILIZER, newdata)
    ## get median parameter estimates
    coefs = apply(fert.mcmc[, 1:2], 2, median)
    fit = as.vector(coefs %*% t(Xmat))
    resid = fert$YIELD - fit
    sresid = resid/sd(resid)
    ggplot() + geom_point(data = NULL, aes(y = sresid, x = fit))
    
    plot of chunk tut7.2bQ1.4a3
    library(MCMCpack)
    fert.mcmc = as.matrix(fert.mcmcpack)
    # generate a model matrix
    Xmat = model.matrix(~FERTILIZER, fert)
    ## get median parameter estimates
    coefs = fert.mcmc[, 1:2]
    fit = coefs %*% t(Xmat)
    ## draw samples from this model
    yRep = sapply(1:nrow(fert.mcmc), function(i) rnorm(nrow(fert), fit[i, ], sqrt(fert.mcmc[i, "sigma2"])))
    ggplot() + geom_density(data = NULL, aes(x = as.vector(yRep), fill = "Model"), alpha = 0.5) + geom_density(data = fert,
        aes(x = YIELD, fill = "Obs"), alpha = 0.5)
    
    plot of chunk tut7.2bQ1.4a4
    Show JAGS code
    library(R2jags)
    fert.mcmc = fert.r2jags$BUGSoutput$sims.matrix[, c("alpha", "beta")]
    # generate a model matrix
    newdata = data.frame(FERTILIZER = fert$FERTILIZER)
    Xmat = model.matrix(~FERTILIZER, newdata)
    ## get median parameter estimates
    coefs = apply(fert.mcmc, 2, median)
    fit = as.vector(coefs %*% t(Xmat))
    resid = fert$YIELD - fit
    ggplot() + geom_point(data = NULL, aes(y = resid, x = fit))
    
    plot of chunk tut7.2bQ1.4b1
    ggplot() + geom_point(data = NULL, aes(y = resid, x = fert$FERTILIZER))
    
    plot of chunk tut7.2bQ1.4b2
    sresid = resid/sd(resid)
    ggplot() + geom_point(data = NULL, aes(y = sresid, x = fit))
    
    plot of chunk tut7.2bQ1.4b3
    fert.mcmc = fert.r2jags$BUGSoutput$sims.matrix[, c("alpha", "beta", "sigma")]
    # generate a model matrix
    Xmat = model.matrix(~FERTILIZER, fert)
    ## get median parameter estimates
    coefs = fert.mcmc[, c("alpha", "beta")]
    fit = coefs %*% t(Xmat)
    ## draw samples from this model
    yRep = sapply(1:nrow(fert.mcmc), function(i) rnorm(nrow(fert), fit[i, ], fert.mcmc[i, "sigma"]))
    ggplot() + geom_density(data = NULL, aes(x = as.vector(yRep), fill = "Model"), alpha = 0.5) + geom_density(data = fert,
        aes(x = YIELD, fill = "Obs"), alpha = 0.5)
    
    plot of chunk tut7.2bQ1.4b4
    Show RSTAN code
    library(rstan)
    fert.mcmc = as.matrix(fert.rstan)[, c("beta0", "beta[1]")]
    # generate a model matrix
    newdata = data.frame(FERTILIZER = fert$FERTILIZER)
    Xmat = model.matrix(~FERTILIZER, newdata)
    ## get median parameter estimates
    coefs = apply(fert.mcmc, 2, median)
    fit = as.vector(coefs %*% t(Xmat))
    resid = fert$YIELD - fit
    ggplot() + geom_point(data = NULL, aes(y = resid, x = fit))
    
    plot of chunk tut7.2bQ1.4c1
    ggplot() + geom_point(data = NULL, aes(y = resid, x = fert$FERTILIZER))
    
    plot of chunk tut7.2bQ1.4c2
    sresid = resid/sd(resid)
    ggplot() + geom_point(data = NULL, aes(y = sresid, x = fit))
    
    plot of chunk tut7.2bQ1.4c3
    fert.mcmc = as.matrix(fert.rstan)[, c("beta0", "beta[1]", "sigma")]
    # generate a model matrix
    Xmat = model.matrix(~FERTILIZER, fert)
    ## get median parameter estimates
    coefs = fert.mcmc[, c("beta0", "beta[1]")]
    fit = coefs %*% t(Xmat)
    ## draw samples from this model
    yRep = sapply(1:nrow(fert.mcmc), function(i) rnorm(nrow(fert), fit[i, ], fert.mcmc[i, "sigma"]))
    ggplot() + geom_density(data = NULL, aes(x = as.vector(yRep), fill = "Model"), alpha = 0.5) + geom_density(data = fert,
        aes(x = YIELD, fill = "Obs"), alpha = 0.5)
    
    plot of chunk tut7.2bQ1.4c4
    Show RSTANARM code
    library(rstanarm)
    resid = resid(fert.rstanarm)
    fit = fitted(fert.rstanarm)
    ggplot() + geom_point(data = NULL, aes(y = resid, x = fit))
    
    plot of chunk tut7.2bQ1.4d1
    ggplot() + geom_point(data = NULL, aes(y = resid, x = fert$FERTILIZER))
    
    plot of chunk tut7.2bQ1.4d2
    sresid = resid/sd(resid)
    ggplot() + geom_point(data = NULL, aes(y = sresid, x = fit))
    
    plot of chunk tut7.2bQ1.4d3
    y_pred = posterior_predict(fert.rstanarm)
    newdata = fert %>% cbind(t(y_pred)) %>% gather(key = "Rep", value = "Value", -YIELD, -FERTILIZER)
    ggplot(newdata, aes(Value, x = FERTILIZER)) + geom_violin(color = "blue", fill = "blue", alpha = 0.5) +
        geom_violin(data = fert, aes(y = YIELD, x = FERTILIZER), fill = "red", color = "red", alpha = 0.5)
    
    plot of chunk tut7.2bQ1.4d4
    ## Calculate the fitted values
    newdata = data.frame(FERTILIZER = seq(min(fert$FERTILIZER, na.rm = TRUE), max(fert$FERTILIZER, na.rm = TRUE),
        len = 1000))
    fit = posterior_predict(fert.rstanarm, newdata = newdata)
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(fit), conf.int = TRUE, conf.method = "HPDinterval"))
    
    ggplot(newdata, aes(y = estimate, x = FERTILIZER)) + geom_point(data = fert, aes(y = YIELD)) + geom_line() +
        geom_ribbon(aes(ymin = conf.low, ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_continuous("YIELD") +
        scale_x_continuous("FERTILIZER") + theme_classic()
    
    plot of chunk tut7.2bQ1.4d4
    Show BRMS code
    library(brms)
    resid = resid(fert.brm)[, "Estimate"]
    fit = fitted(fert.brm)[, "Estimate"]
    ggplot() + geom_point(data = NULL, aes(y = resid, x = fit))
    
    plot of chunk tut7.2bQ1.4e1
    ggplot() + geom_point(data = NULL, aes(y = resid, x = fert$FERTILIZER))
    
    plot of chunk tut7.2bQ1.4e2
    sresid = resid/sd(resid)
    ggplot() + geom_point(data = NULL, aes(y = sresid, x = fit))
    
    plot of chunk tut7.2bQ1.4e3
    y_pred = posterior_predict(fert.brms)
    
    Error in posterior_predict(fert.brms): object 'fert.brms' not found
    
    newdata = fert %>% cbind(t(y_pred)) %>% gather(key = "Rep", value = "Value", -YIELD, -FERTILIZER)
    ggplot(newdata, aes(Value, x = FERTILIZER)) + geom_violin(color = "blue", fill = "blue", alpha = 0.5) +
        geom_violin(data = fert, aes(y = YIELD, x = FERTILIZER), fill = "red", color = "red", alpha = 0.5)
    
    plot of chunk tut7.2bQ1.4e4
    ## Calculate the fitted values
    newdata = data.frame(FERTILIZER = seq(min(fert$FERTILIZER, na.rm = TRUE), max(fert$FERTILIZER, na.rm = TRUE),
        len = 1000))
    fit = posterior_predict(fert.brm, newdata = newdata)
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(fit), conf.int = TRUE, conf.method = "HPDinterval"))
    
    ggplot(newdata, aes(y = estimate, x = FERTILIZER)) + geom_point(data = fert, aes(y = YIELD)) + geom_line() +
        geom_ribbon(aes(ymin = conf.low, ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_continuous("YIELD") +
        scale_x_continuous("FERTILIZER") + theme_classic()
    
    plot of chunk tut7.2bQ1.4e4
  6. Explore parameter estimates
    Show MCMCpack code
    library(MCMCpack)
    summary(fert.mcmcpack)
    
    Iterations = 1001:11000
    Thinning interval = 1 
    Number of chains = 1 
    Sample size per chain = 10000 
    
    1. Empirical mean and standard deviation for each variable,
       plus standard error of the mean:
    
                    Mean        SD  Naive SE Time-series SE
    (Intercept)  52.1741  14.97636 0.1497636      0.1451274
    FERTILIZER    0.8097   0.09708 0.0009708      0.0009146
    sigma2      481.1315 323.12851 3.2312851      4.1585666
    
    2. Quantiles for each variable:
    
                    2.5%      25%      50%    75%    97.5%
    (Intercept)  22.6977  42.9486  52.1874  61.15   82.881
    FERTILIZER    0.6143   0.7512   0.8102   0.87    1.002
    sigma2      167.1821 281.7044 392.9891 568.26 1322.691
    
    library(broom)
    tidyMCMC(fert.mcmcpack, conf.int = TRUE, conf.method = "HPDinterval")
    
             term    estimate    std.error    conf.low   conf.high
    1 (Intercept)  52.1740843  14.97635880  21.3646092   81.114767
    2  FERTILIZER   0.8097191   0.09707823   0.6181384    1.005315
    3      sigma2 481.1315426 323.12850667 123.8952634 1089.733228
    
    mcmcpvalue(fert.mcmcpack[, 2])
    
    [1] 0
    
    Show JAGS code
    library(R2jags)
    print(fert.r2jags)
    
    Inference for Bugs model at "../downloads/BUGSscripts/tut7.2bQ1_JAGS.txt", fit using jags,
     3 chains, each with 166667 iterations (first 2000 discarded), n.thin = 10
     n.sims = 49401 iterations saved
             mu.vect sd.vect   2.5%    25%    50%    75%  97.5%  Rhat n.eff
    alpha     51.849  14.984 21.858 42.754 51.832 61.002 81.635 1.001 49000
    beta       0.812   0.097  0.617  0.753  0.812  0.871  1.005 1.001 49000
    sigma     21.026   6.133 12.857 16.795 19.811 23.835 36.260 1.001 49000
    deviance  88.562   2.884 85.290 86.461 87.818 89.867 96.062 1.001 37000
    
    For each parameter, n.eff is a crude measure of effective sample size,
    and Rhat is the potential scale reduction factor (at convergence, Rhat=1).
    
    DIC info (using the rule, pD = var(deviance)/2)
    pD = 4.2 and DIC = 92.7
    DIC is an estimate of expected predictive error (lower deviance is better).
    
    # OR
    library(broom)
    tidyMCMC(as.mcmc(fert.r2jags), conf.int = TRUE, conf.method = "HPDinterval")
    
          term   estimate   std.error   conf.low conf.high
    1    alpha 51.8492738 14.98388244 21.8583517 81.642155
    2     beta  0.8120709  0.09654881  0.6192913  1.006265
    3 deviance 88.5621720  2.88386090 85.0412289 94.270274
    4    sigma 21.0258884  6.13340577 11.4968165 32.881356
    
    mcmcpvalue(fert.r2jags$BUGSoutput$sims.matrix[, c("beta")])
    
    [1] 0
    
    Show RSTAN code
    library(rstan)
    summary(fert.rstan)
    
    $summary
                  mean     se_mean          sd        2.5%         25%        50%         75%
    beta[1]   0.809339 0.001224893  0.09133433   0.6302421   0.7536958   0.808977   0.8644469
    cbeta0  162.911120 0.088746904  6.59606165 149.6686239 158.7781670 162.995295 167.1182082
    sigma    19.755274 0.088886313  5.52011025  12.3522892  16.0198526  18.727561  22.2138427
    beta0    51.627013 0.194446016 14.22664023  23.1531087  42.8389913  51.835282  60.1747185
    lp__    -36.107824 0.024765438  1.46640854 -39.9064736 -36.7508815 -35.721599 -35.0529187
                  97.5%    n_eff     Rhat
    beta[1]   0.9943676 5559.958 1.000022
    cbeta0  175.9175873 5524.119 1.000387
    sigma    33.3456585 3856.788 1.000305
    beta0    79.8334231 5353.115 1.000033
    lp__    -34.4662193 3506.049 1.000220
    
    $c_summary
    , , chains = chain:1
    
             stats
    parameter        mean          sd        2.5%         25%         50%         75%       97.5%
      beta[1]   0.8062179  0.09006342   0.6278512   0.7517994   0.8064476   0.8607343   0.9912481
      cbeta0  162.8156913  6.55558914 149.5264160 158.6916828 162.8788927 167.1278693 175.8170642
      sigma    19.7434368  5.54546922  12.3279034  15.9510823  18.8511934  22.2436079  33.3647357
      beta0    51.9607351 14.14110561  23.4203535  43.1606609  52.0365182  60.6746148  80.9455324
      lp__    -36.1251415  1.44746841 -39.8586983 -36.7754005 -35.7606787 -35.0631530 -34.4765177
    
    , , chains = chain:2
    
             stats
    parameter        mean         sd        2.5%         25%         50%         75%      97.5%
      beta[1]   0.8101857  0.0908987   0.6351154   0.7529598   0.8102831   0.8655236   1.001964
      cbeta0  162.8427059  6.6615603 149.5567338 158.6341487 163.0016877 167.0187024 175.783045
      sigma    19.7644672  5.4723037  12.2371274  15.9932157  18.6477422  22.3340807  33.270306
      beta0    51.4421703 14.2602676  23.1959990  42.5775876  51.5415815  60.1122890  79.674492
      lp__    -36.1068651  1.4730745 -39.8942511 -36.7389338 -35.7200206 -35.0385177 -34.467814
    
    , , chains = chain:3
    
             stats
    parameter        mean          sd        2.5%         25%         50%         75%       97.5%
      beta[1]   0.8116133  0.09297132   0.6290305   0.7566819   0.8104881   0.8672376   0.9899435
      cbeta0  163.0749636  6.57038774 150.0552004 158.9972371 163.1267028 167.1366895 176.1365046
      sigma    19.7579187  5.54467140  12.4973713  16.0894053  18.7061891  22.0596009  33.3351892
      beta0    51.4781334 14.27858494  23.1574980  42.8290483  51.7703420  59.9094807  79.1162177
      lp__    -36.0914654  1.47894973 -39.9818101 -36.7232619 -35.6896052 -35.0490553 -34.4629588
    
    # OR
    library(broom)
    tidyMCMC(fert.rstan, conf.int = TRUE, conf.method = "HPDinterval")
    
         term   estimate   std.error    conf.low   conf.high
    1 beta[1]   0.809339  0.09133433   0.6286141   0.9906276
    2  cbeta0 162.911120  6.59606165 150.0733053 176.1017746
    3   sigma  19.755274  5.52011025  10.8809881  30.0637007
    4   beta0  51.627013 14.22664023  23.8893344  80.2856801
    
    mcmcpvalue(as.matrix(fert.rstan)[, c("beta[2]")])
    
    Error in as.matrix(fert.rstan)[, c("beta[2]")]: subscript out of bounds
    
    Show RSTANARM code
    library(rstanarm)
    summary(fert.rstanarm)
    
    Model Info:
    
     function:  stan_glm
     family:    gaussian [identity]
     formula:   YIELD ~ FERTILIZER
     algorithm: sampling
     priors:    see help('prior_summary')
     sample:    6750 (posterior sample size)
     num obs:   10
    
    Estimates:
                    mean   sd    2.5%   25%   50%   75%   97.5%
    (Intercept)    52.3   16.4  20.0   42.4  52.2  61.9  85.5  
    FERTILIZER      0.8    0.1   0.6    0.7   0.8   0.9   1.0  
    sigma          22.7    7.5  13.4   17.8  21.1  25.8  41.6  
    mean_PPD      163.7   10.8 142.9  157.0 163.6 170.0 185.6  
    log-posterior -62.9    1.5 -66.8  -63.5 -62.5 -61.8 -61.2  
    
    Diagnostics:
                  mcse Rhat n_eff
    (Intercept)   0.2  1.0  5424 
    FERTILIZER    0.0  1.0  6419 
    sigma         0.1  1.0  2775 
    mean_PPD      0.2  1.0  3774 
    log-posterior 0.0  1.0  2387 
    
    For each parameter, mcse is Monte Carlo standard error, n_eff is a crude measure of effective sample size, and Rhat is the potential scale reduction factor on split chains (at convergence Rhat=1).
    
    # OR
    library(broom)
    tidyMCMC(fert.rstanarm$stanfit, conf.int = TRUE, conf.method = "HPDinterval", rhat = TRUE, ess = TRUE)
    
               term    estimate  std.error    conf.low  conf.high      rhat  ess
    1   (Intercept)  52.3380468 16.3541986  19.1844357  84.055416 0.9998678 5424
    2    FERTILIZER   0.8097014  0.1045031   0.5997843   1.012831 0.9997428 6419
    3         sigma  22.7356331  7.4747818  12.1911517  36.856341 0.9999145 2775
    4      mean_PPD 163.6570502 10.8247627 141.7715662 184.049507 1.0001552 3774
    5 log-posterior -62.8815619  1.5021455 -65.8124268 -61.090052 0.9999853 2387
    
    mcmcpvalue(as.matrix(fert.rstanarm)[, c("FERTILIZER")])
    
    [1] 0
    
    posterior_interval(fert.rstanarm, prob = 0.95)
    
                      2.5%     97.5%
    (Intercept) 19.9536145 85.512691
    FERTILIZER   0.6049777  1.018857
    sigma       13.4087337 41.584921
    
    (full = loo(fert.rstanarm))
    
    Computed from 6750 by 10 log-likelihood matrix
    
             Estimate  SE
    elpd_loo    -45.9 1.4
    p_loo         2.2 0.5
    looic        91.8 2.8
    
    Pareto k diagnostic values:
                             Count  Pct 
    (-Inf, 0.5]   (good)     9     90.0%
     (0.5, 0.7]   (ok)       1     10.0%
       (0.7, 1]   (bad)      0      0.0%
       (1, Inf)   (very bad) 0      0.0%
    
    All Pareto k estimates are ok (k < 0.7)
    See help('pareto-k-diagnostic') for details.
    
    (reduced = loo(update(fert.rstanarm, formula = . ~ 1)))
    
    Gradient evaluation took 2.3e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.23 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.039963 seconds (Warm-up)
                   0.077622 seconds (Sampling)
                   0.117585 seconds (Total)
    
    
    Gradient evaluation took 9e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.09 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.03145 seconds (Warm-up)
                   0.088448 seconds (Sampling)
                   0.119898 seconds (Total)
    
    
    Gradient evaluation took 9e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.09 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.030714 seconds (Warm-up)
                   0.088801 seconds (Sampling)
                   0.119515 seconds (Total)
    
    Computed from 6750 by 10 log-likelihood matrix
    
             Estimate  SE
    elpd_loo    -57.2 1.1
    p_loo         1.2 0.2
    looic       114.4 2.3
    
    All Pareto k estimates are good (k < 0.5)
    See help('pareto-k-diagnostic') for details.
    
    par(mfrow = 1:2, mar = c(5, 3.8, 1, 0) + 0.1, las = 3)
    plot(full, label_points = TRUE)
    plot(reduced, label_points = TRUE)
    
    plot of chunk tut7.2bQ1.5d1
    compare_models(full, reduced)
    
    elpd_diff        se 
        -11.3       1.5 
    
    Show BRMS code
    library(brms)
    summary(fert.brm)
    
     Family: gaussian(identity) 
    Formula: YIELD ~ FERTILIZER 
       Data: fert (Number of observations: 10) 
    Samples: 3 chains, each with iter = 5000; warmup = 500; thin = 2; 
             total post-warmup samples = 6750
        ICs: LOO = Not computed; WAIC = Not computed
     
    Population-Level Effects: 
               Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
    Intercept     51.92     14.72    22.46    81.83       6260    1
    FERTILIZER     0.81      0.10     0.61     1.00       6326    1
    
    Family Specific Parameters: 
          Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
    sigma    21.03      5.77       13    35.05       5190    1
    
    Samples were drawn using sampling(NUTS). For each parameter, Eff.Sample 
    is a crude measure of effective sample size, and Rhat is the potential 
    scale reduction factor on split chains (at convergence, Rhat = 1).
    
    # OR
    library(broom)
    tidyMCMC(fert.brm$fit, conf.int = TRUE, conf.method = "HPDinterval", rhat = TRUE, ess = TRUE)
    
              term   estimate   std.error   conf.low  conf.high      rhat  ess
    1  b_Intercept 51.9228855 14.71902757 22.1522286 81.4263823 0.9998708 6260
    2 b_FERTILIZER  0.8107323  0.09515934  0.6106665  0.9943814 0.9998047 6326
    3        sigma 21.0256275  5.77415796 11.9385908 32.5465719 1.0000062 5190
    
    mcmcpvalue(as.matrix(fert.brm)[, c("b_FERTILIZER")])
    
    [1] 0
    
    posterior_interval(as.matrix(fert.brm), prob = 0.95)
    
                       2.5%       97.5%
    b_Intercept   22.462644  81.8312739
    b_FERTILIZER   0.613901   0.9995781
    sigma         12.995195  35.0498366
    lp__         -36.063369 -31.0011369
    
    (full = loo(fert.brm))
    
     LOOIC   SE
     91.21 3.18
    
    (reduced = loo(update(fert.brm, formula = . ~ 1)))
    
    SAMPLING FOR MODEL 'gaussian(identity) brms-model' NOW (CHAIN 1).
    
    Gradient evaluation took 7e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.07 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration: 1000 / 5000 [ 20%]  (Warmup)
    Iteration: 1500 / 5000 [ 30%]  (Warmup)
    Iteration: 2000 / 5000 [ 40%]  (Warmup)
    Iteration: 2500 / 5000 [ 50%]  (Warmup)
    Iteration: 2501 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.031218 seconds (Warm-up)
                   0.022592 seconds (Sampling)
                   0.05381 seconds (Total)
    
    
    SAMPLING FOR MODEL 'gaussian(identity) brms-model' NOW (CHAIN 2).
    
    Gradient evaluation took 4e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.04 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration: 1000 / 5000 [ 20%]  (Warmup)
    Iteration: 1500 / 5000 [ 30%]  (Warmup)
    Iteration: 2000 / 5000 [ 40%]  (Warmup)
    Iteration: 2500 / 5000 [ 50%]  (Warmup)
    Iteration: 2501 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.031854 seconds (Warm-up)
                   0.022912 seconds (Sampling)
                   0.054766 seconds (Total)
    
    
    SAMPLING FOR MODEL 'gaussian(identity) brms-model' NOW (CHAIN 3).
    
    Gradient evaluation took 3e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.03 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration: 1000 / 5000 [ 20%]  (Warmup)
    Iteration: 1500 / 5000 [ 30%]  (Warmup)
    Iteration: 2000 / 5000 [ 40%]  (Warmup)
    Iteration: 2500 / 5000 [ 50%]  (Warmup)
    Iteration: 2501 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.030551 seconds (Warm-up)
                   0.023864 seconds (Sampling)
                   0.054415 seconds (Total)
    
    
    SAMPLING FOR MODEL 'gaussian(identity) brms-model' NOW (CHAIN 1).
    
    Gradient evaluation took 5e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.05 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration: 1000 / 5000 [ 20%]  (Warmup)
    Iteration: 1500 / 5000 [ 30%]  (Warmup)
    Iteration: 2000 / 5000 [ 40%]  (Warmup)
    Iteration: 2500 / 5000 [ 50%]  (Warmup)
    Iteration: 2501 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.031004 seconds (Warm-up)
                   0.022572 seconds (Sampling)
                   0.053576 seconds (Total)
    
    
    SAMPLING FOR MODEL 'gaussian(identity) brms-model' NOW (CHAIN 2).
    
    Gradient evaluation took 3e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.03 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration: 1000 / 5000 [ 20%]  (Warmup)
    Iteration: 1500 / 5000 [ 30%]  (Warmup)
    Iteration: 2000 / 5000 [ 40%]  (Warmup)
    Iteration: 2500 / 5000 [ 50%]  (Warmup)
    Iteration: 2501 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.031758 seconds (Warm-up)
                   0.022977 seconds (Sampling)
                   0.054735 seconds (Total)
    
    
    SAMPLING FOR MODEL 'gaussian(identity) brms-model' NOW (CHAIN 3).
    
    Gradient evaluation took 4e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.04 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration: 1000 / 5000 [ 20%]  (Warmup)
    Iteration: 1500 / 5000 [ 30%]  (Warmup)
    Iteration: 2000 / 5000 [ 40%]  (Warmup)
    Iteration: 2500 / 5000 [ 50%]  (Warmup)
    Iteration: 2501 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.030404 seconds (Warm-up)
                   0.024019 seconds (Sampling)
                   0.054423 seconds (Total)
    
      LOOIC   SE
     114.12 2.85
    
    par(mfrow = 1:2, mar = c(5, 3.8, 1, 0) + 0.1, las = 3)
    plot(full, label_points = TRUE)
    plot(reduced, label_points = TRUE)
    
    plot of chunk tut7.2bQ1.5e1
  7. Generate graphical summaries
    Show MCMCpack code
    library(MCMCpack)
    fert.mcmc = fert.mcmcpack
    ## Calculate the fitted values
    library(newdata)
    newdata = new_data(fert, seq = "FERTILIZER", length = 1000)
    Xmat = model.matrix(~FERTILIZER, newdata)
    coefs = fert.mcmc[, 1:2]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(tidyMCMC(fit, conf.int = TRUE, conf.method = "HPDinterval"))
    
    ggplot(newdata, aes(y = estimate, x = FERTILIZER)) + geom_point(data = fert,
        aes(y = YIELD, x = FERTILIZER)) + geom_line() + geom_ribbon(aes(ymin = conf.low,
        ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_continuous(expression(Grass ~
        yield ~ (g * m^-3))) + scale_x_continuous(expression(Grass ~ yield ~
        (g * L^{
            -1
        }))) + theme_classic()
    
    plot of chunk tut7.2bQ1.6a1
    library(MCMCpack)
    fert.mcmc = fert.mcmcpack
    ## Calculate the fitted values
    library(newdata)
    newdata = new_data(fert, seq = "FERTILIZER", length = 1000)
    Xmat = model.matrix(~FERTILIZER, newdata)
    coefs = fert.mcmc[, 1:2]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(t(fit))
    newdata = newdata %>% gather(key = Sample, value = fit, -FERTILIZER, -YIELD)
    newdata.sum = newdata %>% group_by(FERTILIZER) %>% dplyr:::summarize(fit = median(fit))
    ggplot(newdata, aes(y = estimate, x = FERTILIZER)) + geom_line(aes(y = fit,
        x = FERTILIZER, group = Sample), alpha = 0.01) + geom_line(data = newdata.sum,
        aes(y = fit, x = FERTILIZER), color = "blue") + geom_point(data = fert,
        aes(y = YIELD, x = FERTILIZER), color = "red") + scale_y_continuous(expression(Grass ~
        yield ~ (g * m^-3))) + scale_x_continuous(expression(Grass ~ yield ~
        (g * L^-1))) + theme_classic()
    
    plot of chunk tut7.2bQ1.6a2
    Show JAGS code
    library(MCMCpack)
    fert.mcmc = fert.r2jags$BUGSoutput$sims.matrix
    ## Calculate the fitted values
    library(newdata)
    newdata = new_data(fert, seq = "FERTILIZER", length = 1000)
    Xmat = model.matrix(~FERTILIZER, newdata)
    coefs = fert.mcmc[, c("alpha", "beta")]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(tidyMCMC(fit, conf.int = TRUE, conf.method = "HPDinterval"))
    
    ggplot(newdata, aes(y = estimate, x = FERTILIZER)) + geom_point(data = fert,
        aes(y = YIELD, x = FERTILIZER)) + geom_line() + geom_ribbon(aes(ymin = conf.low,
        ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_continuous(expression(Grass ~
        yield ~ (g * m^-3))) + scale_x_continuous(expression(Grass ~ yield ~
        (g * L^{
            -1
        }))) + theme_classic()
    
    plot of chunk tut7.2bQ1.6b1
    library(MCMCpack)
    fert.mcmc = fert.mcmcpack
    ## Calculate the fitted values
    library(newdata)
    newdata = new_data(fert, seq = "FERTILIZER", length = 1000)
    Xmat = model.matrix(~FERTILIZER, newdata)
    coefs = fert.mcmc[, c("beta0", "beta1")]
    
    Error in `[.default`(fert.mcmc, , c("beta0", "beta1")): subscript out of bounds
    
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(t(fit))
    newdata = newdata %>% gather(key = Sample, value = fit, -FERTILIZER, -YIELD)
    newdata.sum = newdata %>% group_by(FERTILIZER) %>% dplyr:::summarize(fit = median(fit))
    ggplot(newdata, aes(y = estimate, x = FERTILIZER)) + geom_line(aes(y = fit,
        x = FERTILIZER, group = Sample), alpha = 0.01) + geom_line(data = newdata.sum,
        aes(y = fit, x = FERTILIZER), color = "blue") + geom_point(data = fert,
        aes(y = YIELD, x = FERTILIZER), color = "red") + scale_y_continuous(expression(Grass ~
        yield ~ (g * m^-3))) + scale_x_continuous(expression(Grass ~ yield ~
        (g * L^-1))) + theme_classic()
    
    plot of chunk tut7.2bQ1.6b2
    Show RSTAN code
    library(MCMCpack)
    fert.mcmc = as.matrix(fert.rstan)
    ## Calculate the fitted values
    library(newdata)
    newdata = new_data(fert, seq = "FERTILIZER", length = 1000)
    Xmat = model.matrix(~FERTILIZER, newdata)
    coefs = fert.mcmc[, c("beta0", "beta[1]")]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(tidyMCMC(fit, conf.int = TRUE, conf.method = "HPDinterval"))
    
    ggplot(newdata, aes(y = estimate, x = FERTILIZER)) + geom_point(data = fert,
        aes(y = YIELD, x = FERTILIZER)) + geom_line() + geom_ribbon(aes(ymin = conf.low,
        ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_continuous(expression(Grass ~
        yield ~ (g * m^-3))) + scale_x_continuous(expression(Grass ~ yield ~
        (g * L^{
            -1
        }))) + theme_classic()
    
    plot of chunk tut7.2bQ1.6c1
    library(MCMCpack)
    fert.mcmc = as.matrix(fert.rstan)
    ## Calculate the fitted values
    library(newdata)
    newdata = new_data(fert, seq = "FERTILIZER", length = 1000)
    Xmat = model.matrix(~FERTILIZER, newdata)
    coefs = fert.mcmc[, c("beta0", "beta[1]")]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(t(fit))
    newdata = newdata %>% gather(key = Sample, value = fit, -FERTILIZER, -YIELD)
    newdata.sum = newdata %>% group_by(FERTILIZER) %>% dplyr:::summarize(fit = median(fit))
    ggplot(newdata, aes(y = estimate, x = FERTILIZER)) + geom_line(aes(y = fit,
        x = FERTILIZER, group = Sample), alpha = 0.01) + geom_line(data = newdata.sum,
        aes(y = fit, x = FERTILIZER), color = "blue") + geom_point(data = fert,
        aes(y = YIELD, x = FERTILIZER), color = "red") + scale_y_continuous(expression(Grass ~
        yield ~ (g * m^-3))) + scale_x_continuous(expression(Grass ~ yield ~
        (g * L^-1))) + theme_classic()
    
    plot of chunk tut7.2bQ1.6c2
    Show RSTANARM code
    newdata = newdata = new_data(fert, seq = "FERTILIZER", length = 1000)
    fit = posterior_linpred(fert.rstanarm, newdata = newdata)
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(fit), conf.int = TRUE, conf.method = "HPDinterval"))
    
    ggplot(newdata, aes(y = estimate, x = FERTILIZER)) + geom_point(data = fert,
        aes(y = YIELD, x = FERTILIZER)) + geom_line() + geom_ribbon(aes(ymin = conf.low,
        ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_continuous(expression(Grass ~
        yield ~ (g * m^-3))) + scale_x_continuous(expression(Grass ~ yield ~
        (g * L^{
            -1
        }))) + theme_classic()
    
    plot of chunk tut7.2bQ1.6d1
    library(rstanarm)
    fert.mcmc = as.matrix(fert.rstanarm)
    ## Calculate the fitted values
    library(newdata)
    newdata = new_data(fert, seq = "FERTILIZER", length = 1000)
    Xmat = model.matrix(~FERTILIZER, newdata)
    coefs = fert.mcmc[, c("(Intercept)", "FERTILIZER")]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(t(fit))
    newdata = newdata %>% gather(key = Sample, value = fit, -FERTILIZER, -YIELD)
    newdata.sum = newdata %>% group_by(FERTILIZER) %>% dplyr:::summarize(fit = median(fit))
    ggplot(newdata, aes(y = estimate, x = FERTILIZER)) + geom_line(aes(y = fit,
        x = FERTILIZER, group = Sample), alpha = 0.01) + geom_line(data = newdata.sum,
        aes(y = fit, x = FERTILIZER), color = "blue") + geom_point(data = fert,
        aes(y = YIELD, x = FERTILIZER), color = "red") + scale_y_continuous(expression(Grass ~
        yield ~ (g * m^-3))) + scale_x_continuous(expression(Grass ~ yield ~
        (g * L^-1))) + theme_classic()
    
    plot of chunk tut7.2bQ1.6d2
    Show BRMS code
    newdata = marginal_effects(fert.brm)$FERTILIZER
    
    ggplot(newdata, aes(y = estimate__, x = FERTILIZER)) + geom_point(data = fert,
        aes(y = YIELD, x = FERTILIZER)) + geom_line() + geom_ribbon(aes(ymin = lower__,
        ymax = upper__), fill = "blue", alpha = 0.3) + scale_y_continuous(expression(Grass ~
        yield ~ (g * m^-3))) + scale_x_continuous(expression(Grass ~ yield ~
        (g * L^{
            -1
        }))) + theme_classic()
    
    plot of chunk tut7.2bQ1.6e1
    library(brms)
    fert.mcmc = as.matrix(fert.brm)
    ## Calculate the fitted values
    library(newdata)
    newdata = new_data(fert, seq = "FERTILIZER", length = 1000)
    Xmat = model.matrix(~FERTILIZER, newdata)
    coefs = fert.mcmc[, c("b_Intercept", "b_FERTILIZER")]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(t(fit))
    newdata = newdata %>% gather(key = Sample, value = fit, -FERTILIZER, -YIELD)
    newdata.sum = newdata %>% group_by(FERTILIZER) %>% dplyr:::summarize(fit = median(fit))
    ggplot(newdata, aes(y = estimate, x = FERTILIZER)) + geom_line(aes(y = fit,
        x = FERTILIZER, group = Sample), alpha = 0.01) + geom_line(data = newdata.sum,
        aes(y = fit, x = FERTILIZER), color = "blue") + geom_point(data = fert,
        aes(y = YIELD, x = FERTILIZER), color = "red") + scale_y_continuous(expression(Grass ~
        yield ~ (g * m^-3))) + scale_x_continuous(expression(Grass ~ yield ~
        (g * L^-1))) + theme_classic()
    
    plot of chunk tut7.2bQ1.6e2
  8. Explore effect sizes
    Show MCMCpack code
    library(MCMCpack)
    fert.mcmc = fert.mcmcpack
    newdata = with(fert, data.frame(FERTILIZER = c(min(FERTILIZER, na.rm = TRUE),
        max(FERTILIZER, na.rm = TRUE))))
    Xmat = model.matrix(~FERTILIZER, newdata)
    coefs = fert.mcmc[, c("(Intercept)", "FERTILIZER")]
    fit = coefs %*% t(Xmat)
    ## Raw effect size
    (RES = tidyMCMC(as.mcmc(fit[, 2] - fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 182.1868   21.8426 139.0811  226.1958
    
    ## Cohen's D
    cohenD = (fit[, 2] - fit[, 1])/sqrt(fert.mcmc[, "sigma2"])
    (cohenDES = tidyMCMC(as.mcmc(cohenD), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 9.288865  2.569286  4.40718  14.36279
    
    # Percentage change
    ESp = 100 * (fit[, 2] - fit[, 1])/fit[, 1]
    (PES = tidyMCMC(as.mcmc(ESp), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 262.2656  298.5128 122.3063  426.8095
    
    # Probability that the effect is greater than 25% (a decline of >25%)
    sum(-1 * ESp > 25)/length(ESp)
    
    [1] 2e-04
    
    ## fractional change
    fit = fit[fit[, 2] > 0, ]
    (FES = tidyMCMC(as.mcmc(fit[, 2]/fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 3.622656  2.985128 2.223063  5.268095
    
    Show JAGS code
    library(R2jags)
    fert.mcmc = fert.r2jags$BUGSoutput$sims.matrix
    newdata = with(fert, data.frame(FERTILIZER = c(min(FERTILIZER, na.rm = TRUE),
        max(FERTILIZER, na.rm = TRUE))))
    Xmat = model.matrix(~FERTILIZER, newdata)
    coefs = fert.mcmc[, c("alpha", "beta")]
    fit = coefs %*% t(Xmat)
    ## Raw effect size
    (RES = tidyMCMC(as.mcmc(fit[, 2] - fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1  182.716  21.72348 139.3406  226.4097
    
    ## Cohen's D
    cohenD = (fit[, 2] - fit[, 1])/fert.mcmc[, "sigma"]
    (cohenDES = tidyMCMC(as.mcmc(cohenD), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 9.326646  2.559971 4.446114  14.37503
    
    # Percentage change
    ESp = 100 * (fit[, 2] - fit[, 1])/fit[, 1]
    (PES = tidyMCMC(as.mcmc(ESp), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 267.7493  140.0571 126.1084  433.3658
    
    # Probability that the effect is greater than 25% (a decline of >25%)
    sum(-1 * ESp > 25)/length(ESp)
    
    [1] 0.0001416975
    
    ## fractional change
    fit = fit[fit[, 2] > 0, ]
    (FES = tidyMCMC(as.mcmc(fit[, 2]/fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 3.677493  1.400571 2.261084  5.333658
    
    Show RSTAN code
    library(rstan)
    fert.mcmc = as.matrix(fert.rstan)
    newdata = with(fert, data.frame(FERTILIZER = c(min(FERTILIZER, na.rm = TRUE),
        max(FERTILIZER, na.rm = TRUE))))
    Xmat = model.matrix(~FERTILIZER, newdata)
    coefs = fert.mcmc[, c("beta0", "beta[1]")]
    fit = coefs %*% t(Xmat)
    ## Raw effect size
    (RES = tidyMCMC(as.mcmc(fit[, 2] - fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 182.1013  20.55022 141.4382  222.8912
    
    ## Cohen's D
    cohenD = (fit[, 2] - fit[, 1])/fert.mcmc[, "sigma"]
    (cohenDES = tidyMCMC(as.mcmc(cohenD), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 9.829208  2.571008 4.981677  15.01005
    
    # Percentage change
    ESp = 100 * (fit[, 2] - fit[, 1])/fit[, 1]
    (PES = tidyMCMC(as.mcmc(ESp), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 267.2579  99.26202 139.4832  431.2538
    
    # Probability that the effect is greater than 25% (a decline of >25%)
    sum(-1 * ESp > 25)/length(ESp)
    
    [1] 0
    
    ## fractional change
    fit = fit[fit[, 2] > 0, ]
    (FES = tidyMCMC(as.mcmc(fit[, 2]/fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 3.672579 0.9926202 2.394832  5.312538
    
    Show RSTANARM code
    library(rstanarm)
    fert.mcmc = as.matrix(fert.rstanarm)
    newdata = with(fert, data.frame(FERTILIZER = c(min(FERTILIZER, na.rm = TRUE),
        max(FERTILIZER, na.rm = TRUE))))
    Xmat = model.matrix(~FERTILIZER, newdata)
    coefs = fert.mcmc[, c("(Intercept)", "FERTILIZER")]
    fit = coefs %*% t(Xmat)
    ## Raw effect size
    (RES = tidyMCMC(as.mcmc(fit[, 2] - fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 182.1828  23.51321 134.9515  227.8871
    
    ## Cohen's D
    cohenD = (fit[, 2] - fit[, 1])/fert.mcmc[, "sigma"]
    (cohenDES = tidyMCMC(as.mcmc(cohenD), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1  8.71441  2.569302 3.801572  13.73853
    
    # Percentage change
    ESp = 100 * (fit[, 2] - fit[, 1])/fit[, 1]
    (PES = tidyMCMC(as.mcmc(ESp), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 252.7138   923.965 104.8493  434.5145
    
    # Probability that the effect is greater than 25% (a decline of >25%)
    sum(-1 * ESp > 25)/length(ESp)
    
    [1] 0.0005925926
    
    ## fractional change
    fit = fit[fit[, 2] > 0, ]
    (FES = tidyMCMC(as.mcmc(fit[, 2]/fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 3.527138   9.23965 2.048493  5.345145
    
    Show BRMS code
    library(brms)
    fert.mcmc = as.matrix(fert.brm)
    newdata = with(fert, data.frame(FERTILIZER = c(min(FERTILIZER, na.rm = TRUE),
        max(FERTILIZER, na.rm = TRUE))))
    Xmat = model.matrix(~FERTILIZER, newdata)
    coefs = fert.mcmc[, c("b_Intercept", "b_FERTILIZER")]
    fit = coefs %*% t(Xmat)
    ## Raw effect size
    (RES = tidyMCMC(as.mcmc(fit[, 2] - fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 182.4148  21.41085    137.4  223.7358
    
    ## Cohen's D
    cohenD = (fit[, 2] - fit[, 1])/fert.mcmc[, "sigma"]
    (cohenDES = tidyMCMC(as.mcmc(cohenD), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 9.266529  2.498071 4.514346  14.21276
    
    # Percentage change
    ESp = 100 * (fit[, 2] - fit[, 1])/fit[, 1]
    (PES = tidyMCMC(as.mcmc(ESp), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1  266.801  91.17899 128.9894  434.6131
    
    # Probability that the effect is greater than 25% (a decline of >25%)
    sum(-1 * ESp > 25)/length(ESp)
    
    [1] 0
    
    ## fractional change
    fit = fit[fit[, 2] > 0, ]
    (FES = tidyMCMC(as.mcmc(fit[, 2]/fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1  3.66801 0.9117899 2.289894  5.346131
    
  9. Explore finite-population standard deviations
    Show MCMCpack code
    library(MCMCpack)
    library(broom)
    fert.mcmc = fert.mcmcpack
    sd.FERTILIZER = abs(fert.mcmc[, "FERTILIZER"]) * sd(fert$FERTILIZER)
    # generate a model matrix
    newdata = data.frame(FERTILIZER = fert$FERTILIZER)
    Xmat = model.matrix(~FERTILIZER, newdata)
    ## get median parameter estimates
    coefs = fert.mcmc[, 1:2]
    fit = coefs %*% t(Xmat)
    resid = sweep(fit, 2, fert$YIELD, "-")
    sd.resid = apply(resid, 1, sd)
    sd.all = cbind(sd.FERTILIZER, sd.resid)
    (fpsd = tidyMCMC(sd.all, conf.int = TRUE, conf.method = "HPDinterval"))
    
               term estimate std.error conf.low conf.high
    1 sd.FERTILIZER 61.28866  7.347973 46.78768  76.09352
    2      sd.resid 19.24431  2.127803 17.91277  23.15467
    
    # OR expressed as a percentage
    (fpsd.p = tidyMCMC(100 * sd.all/rowSums(sd.all), estimate.method = "median",
        conf.int = TRUE, conf.method = "HPDinterval"))
    
               term estimate std.error conf.low conf.high
    1 sd.FERTILIZER 77.19688  3.476627 69.65459  78.12506
    2      sd.resid 22.80312  3.476627 21.87494  30.34541
    
    ## we can even plot this as a Bayesian ANOVA table
    ggplot(fpsd, aes(y = estimate, x = term)) + geom_pointrange(aes(ymin = conf.low,
        ymax = conf.high)) + geom_text(aes(label = sprintf("%.2f%%", fpsd.p$estimate),
        vjust = -1)) + scale_y_continuous("Finite population standard deviation") +
        scale_x_discrete() + coord_flip() + theme_classic()
    
    plot of chunk tut7.2bQ1.8a1
    Show JAGS code
    library(R2jags)
    library(broom)
    fert.mcmc = fert.r2jags$BUGSoutput$sims.matrix
    sd.FERTILIZER = abs(fert.mcmc[, "beta"]) * sd(fert$FERTILIZER)
    # generate a model matrix
    newdata = data.frame(FERTILIZER = fert$FERTILIZER)
    Xmat = model.matrix(~FERTILIZER, newdata)
    ## get median parameter estimates
    coefs = fert.mcmc[, c("alpha", "beta")]
    fit = coefs %*% t(Xmat)
    resid = sweep(fit, 2, fert$YIELD, "-")
    sd.resid = apply(resid, 1, sd)
    sd.all = cbind(sd.FERTILIZER, sd.resid)
    (fpsd = tidyMCMC(sd.all, conf.int = TRUE, conf.method = "HPDinterval"))
    
               term estimate std.error conf.low conf.high
    1 sd.FERTILIZER 61.46667  7.307901 46.87494  76.16548
    2      sd.resid 19.23513  2.069818 17.91277  23.14717
    
    # OR expressed as a percentage
    (fpsd.p = tidyMCMC(100 * sd.all/rowSums(sd.all), estimate.method = "median",
        conf.int = TRUE, conf.method = "HPDinterval"))
    
               term estimate std.error conf.low conf.high
    1 sd.FERTILIZER 77.21399  3.237124 69.88457  78.12506
    2      sd.resid 22.78601  3.237124 21.87494  30.11543
    
    ## we can even plot this as a Bayesian ANOVA table
    ggplot(fpsd, aes(y = estimate, x = term)) + geom_pointrange(aes(ymin = conf.low,
        ymax = conf.high)) + geom_text(aes(label = sprintf("%.2f%%", fpsd.p$estimate),
        vjust = -1)) + scale_y_continuous("Finite population standard deviation") +
        scale_x_discrete() + coord_flip() + theme_classic()
    
    plot of chunk tut7.2bQ1.8b1
    Show RSTAN code
    library(rstan)
    library(broom)
    fert.mcmc = as.matrix(fert.rstan)
    sd.FERTILIZER = abs(fert.mcmc[, "beta[1]"]) * sd(fert$FERTILIZER)
    # generate a model matrix
    newdata = data.frame(FERTILIZER = fert$FERTILIZER)
    Xmat = model.matrix(~FERTILIZER, newdata)
    ## get median parameter estimates
    coefs = fert.mcmc[, c("beta0", "beta[1]")]
    fit = coefs %*% t(Xmat)
    resid = sweep(fit, 2, fert$YIELD, "-")
    sd.resid = apply(resid, 1, sd)
    sd.all = cbind(sd.FERTILIZER, sd.resid)
    (fpsd = tidyMCMC(sd.all, conf.int = TRUE, conf.method = "HPDinterval"))
    
               term estimate std.error conf.low conf.high
    1 sd.FERTILIZER 61.25988  6.913210 47.58059  74.98185
    2      sd.resid 19.10316  1.935704 17.91277  22.61032
    
    # OR expressed as a percentage
    (fpsd.p = tidyMCMC(100 * sd.all/rowSums(sd.all), estimate.method = "median",
        conf.int = TRUE, conf.method = "HPDinterval"))
    
               term estimate std.error conf.low conf.high
    1 sd.FERTILIZER 77.20433  3.192041 70.37898  78.12506
    2      sd.resid 22.79567  3.192041 21.87494  29.62102
    
    ## we can even plot this as a Bayesian ANOVA table
    ggplot(fpsd, aes(y = estimate, x = term)) + geom_pointrange(aes(ymin = conf.low,
        ymax = conf.high)) + geom_text(aes(label = sprintf("%.2f%%", fpsd.p$estimate),
        vjust = -1)) + scale_y_continuous("Finite population standard deviation") +
        scale_x_discrete() + coord_flip() + theme_classic()
    
    plot of chunk tut7.2bQ1.8c1
    Show RSTANARM code
    library(rstanarm)
    library(broom)
    fert.mcmc = as.matrix(fert.rstanarm)
    sd.FERTILIZER = abs(fert.mcmc[, "FERTILIZER"]) * sd(fert$FERTILIZER)
    # generate a model matrix
    newdata = data.frame(FERTILIZER = fert$FERTILIZER)
    Xmat = model.matrix(~FERTILIZER, newdata)
    ## get median parameter estimates
    coefs = fert.mcmc[, c("(Intercept)", "FERTILIZER")]
    fit = coefs %*% t(Xmat)
    resid = sweep(fit, 2, fert$YIELD, "-")
    sd.resid = apply(resid, 1, sd)
    sd.all = cbind(sd.FERTILIZER, sd.resid)
    (fpsd = tidyMCMC(sd.all, conf.int = TRUE, conf.method = "HPDinterval"))
    
               term estimate std.error conf.low conf.high
    1 sd.FERTILIZER 61.28732  7.909974 45.39843  76.66249
    2      sd.resid 19.42438  2.477229 17.91277  23.81033
    
    # OR expressed as a percentage
    (fpsd.p = tidyMCMC(100 * sd.all/rowSums(sd.all), estimate.method = "median",
        conf.int = TRUE, conf.method = "HPDinterval"))
    
               term estimate std.error conf.low conf.high
    1 sd.FERTILIZER 77.11062  3.719985 68.86628  78.12506
    2      sd.resid 22.88938  3.719985 21.87494  31.13372
    
    ## we can even plot this as a Bayesian ANOVA table
    ggplot(fpsd, aes(y = estimate, x = term)) + geom_pointrange(aes(ymin = conf.low,
        ymax = conf.high)) + geom_text(aes(label = sprintf("%.2f%%", fpsd.p$estimate),
        vjust = -1)) + scale_y_continuous("Finite population standard deviation") +
        scale_x_discrete() + coord_flip() + theme_classic()
    
    plot of chunk tut7.2bQ1.8d1
    Show BRMS code
    library(brms)
    library(broom)
    fert.mcmc = as.matrix(fert.brm)
    sd.FERTILIZER = abs(fert.mcmc[, "b_FERTILIZER"]) * sd(fert$FERTILIZER)
    # generate a model matrix
    newdata = data.frame(FERTILIZER = fert$FERTILIZER)
    Xmat = model.matrix(~FERTILIZER, newdata)
    ## get median parameter estimates
    coefs = fert.mcmc[, c("b_Intercept", "b_FERTILIZER")]
    fit = coefs %*% t(Xmat)
    resid = sweep(fit, 2, fert$YIELD, "-")
    sd.resid = apply(resid, 1, sd)
    sd.all = cbind(sd.FERTILIZER, sd.resid)
    (fpsd = tidyMCMC(sd.all, conf.int = TRUE, conf.method = "HPDinterval"))
    
               term estimate std.error conf.low conf.high
    1 sd.FERTILIZER 61.36535  7.202730 46.22211  75.26598
    2      sd.resid 19.20309  1.995814 17.91277  23.12029
    
    # OR expressed as a percentage
    (fpsd.p = tidyMCMC(100 * sd.all/rowSums(sd.all), estimate.method = "median",
        conf.int = TRUE, conf.method = "HPDinterval"))
    
               term estimate std.error conf.low conf.high
    1 sd.FERTILIZER 77.22118  3.232889 69.63626  78.12506
    2      sd.resid 22.77882  3.232889 21.87494  30.36374
    
    ## we can even plot this as a Bayesian ANOVA table
    ggplot(fpsd, aes(y = estimate, x = term)) + geom_pointrange(aes(ymin = conf.low,
        ymax = conf.high)) + geom_text(aes(label = sprintf("%.2f%%", fpsd.p$estimate),
        vjust = -1)) + scale_y_continuous("Finite population standard deviation") +
        scale_x_discrete() + coord_flip() + theme_classic()
    
    plot of chunk tut7.2bQ1.8e1
  10. Explore $R^2$
    Show MCMCpack code
    library(MCMCpack)
    library(broom)
    fert.mcmc <- fert.mcmcpack
    Xmat = model.matrix(~FERTILIZER, data = fert)
    coefs = fert.mcmc[, c("(Intercept)", "FERTILIZER")]
    fit = coefs %*% t(Xmat)
    resid = sweep(fit, 2, fert$FERTILIZER, "-")
    var_f = apply(fit, 1, var)
    var_e = apply(resid, 1, var)
    R2 = var_f/(var_f + var_e)
    tidyMCMC(as.mcmc(R2), conf.int = TRUE, conf.method = "HPDinterval")
    
      term  estimate  std.error  conf.low conf.high
    1 var1 0.9257774 0.08018707 0.7802406         1
    
    # for comparison with frequentist
    summary(lm(YIELD ~ FERTILIZER, data = fert))
    
    Call:
    lm(formula = YIELD ~ FERTILIZER, data = fert)
    
    Residuals:
       Min     1Q Median     3Q    Max 
    -22.79 -11.07  -5.00  12.00  29.79 
    
    Coefficients:
                Estimate Std. Error t value Pr(>|t|)    
    (Intercept) 51.93333   12.97904   4.001  0.00394 ** 
    FERTILIZER   0.81139    0.08367   9.697 1.07e-05 ***
    ---
    Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    
    Residual standard error: 19 on 8 degrees of freedom
    Multiple R-squared:  0.9216,	Adjusted R-squared:  0.9118 
    F-statistic: 94.04 on 1 and 8 DF,  p-value: 1.067e-05
    
    Show JAGS code
    library(R2jags)
    library(broom)
    fert.mcmc <- fert.r2jags$BUGSoutput$sims.matrix
    Xmat = model.matrix(~FERTILIZER, data = fert)
    coefs = fert.mcmc[, c("alpha", "beta")]
    fit = coefs %*% t(Xmat)
    resid = sweep(fit, 2, fert$FERTILIZER, "-")
    var_f = apply(fit, 1, var)
    var_e = apply(resid, 1, var)
    R2 = var_f/(var_f + var_e)
    tidyMCMC(as.mcmc(R2), conf.int = TRUE, conf.method = "HPDinterval")
    
      term  estimate  std.error  conf.low conf.high
    1 var1 0.9276763 0.07600148 0.7851166         1
    
    # for comparison with frequentist
    summary(lm(YIELD ~ FERTILIZER, data = fert))
    
    Call:
    lm(formula = YIELD ~ FERTILIZER, data = fert)
    
    Residuals:
       Min     1Q Median     3Q    Max 
    -22.79 -11.07  -5.00  12.00  29.79 
    
    Coefficients:
                Estimate Std. Error t value Pr(>|t|)    
    (Intercept) 51.93333   12.97904   4.001  0.00394 ** 
    FERTILIZER   0.81139    0.08367   9.697 1.07e-05 ***
    ---
    Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    
    Residual standard error: 19 on 8 degrees of freedom
    Multiple R-squared:  0.9216,	Adjusted R-squared:  0.9118 
    F-statistic: 94.04 on 1 and 8 DF,  p-value: 1.067e-05
    
    Show RSTAN code
    library(rstan)
    library(broom)
    fert.mcmc <- as.matrix(fert.rstan)
    Xmat = model.matrix(~FERTILIZER, data = fert)
    coefs = fert.mcmc[, c("beta0", "beta[1]")]
    fit = coefs %*% t(Xmat)
    resid = sweep(fit, 2, fert$FERTILIZER, "-")
    var_f = apply(fit, 1, var)
    var_e = apply(resid, 1, var)
    R2 = var_f/(var_f + var_e)
    tidyMCMC(as.mcmc(R2), conf.int = TRUE, conf.method = "HPDinterval")
    
      term  estimate  std.error conf.low conf.high
    1 var1 0.9280336 0.07363253 0.795127         1
    
    # for comparison with frequentist
    summary(lm(YIELD ~ FERTILIZER, data = fert))
    
    Call:
    lm(formula = YIELD ~ FERTILIZER, data = fert)
    
    Residuals:
       Min     1Q Median     3Q    Max 
    -22.79 -11.07  -5.00  12.00  29.79 
    
    Coefficients:
                Estimate Std. Error t value Pr(>|t|)    
    (Intercept) 51.93333   12.97904   4.001  0.00394 ** 
    FERTILIZER   0.81139    0.08367   9.697 1.07e-05 ***
    ---
    Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    
    Residual standard error: 19 on 8 degrees of freedom
    Multiple R-squared:  0.9216,	Adjusted R-squared:  0.9118 
    F-statistic: 94.04 on 1 and 8 DF,  p-value: 1.067e-05
    
    Show RSTANARM code
    library(rstanarm)
    library(broom)
    fert.mcmc <- as.matrix(fert.rstanarm)
    Xmat = model.matrix(~FERTILIZER, data = fert)
    coefs = fert.mcmc[, c("(Intercept)", "FERTILIZER")]
    fit = coefs %*% t(Xmat)
    resid = sweep(fit, 2, fert$FERTILIZER, "-")
    var_f = apply(fit, 1, var)
    var_e = apply(resid, 1, var)
    R2 = var_f/(var_f + var_e)
    tidyMCMC(as.mcmc(R2), conf.int = TRUE, conf.method = "HPDinterval")
    
      term  estimate  std.error  conf.low conf.high
    1 var1 0.9229182 0.08473831 0.7641056         1
    
    # for comparison with frequentist
    summary(lm(YIELD ~ FERTILIZER, data = fert))
    
    Call:
    lm(formula = YIELD ~ FERTILIZER, data = fert)
    
    Residuals:
       Min     1Q Median     3Q    Max 
    -22.79 -11.07  -5.00  12.00  29.79 
    
    Coefficients:
                Estimate Std. Error t value Pr(>|t|)    
    (Intercept) 51.93333   12.97904   4.001  0.00394 ** 
    FERTILIZER   0.81139    0.08367   9.697 1.07e-05 ***
    ---
    Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    
    Residual standard error: 19 on 8 degrees of freedom
    Multiple R-squared:  0.9216,	Adjusted R-squared:  0.9118 
    F-statistic: 94.04 on 1 and 8 DF,  p-value: 1.067e-05
    
    Show BRMS code
    library(brms)
    library(broom)
    fert.mcmc <- as.matrix(fert.brm)
    Xmat = model.matrix(~FERTILIZER, data = fert)
    coefs = fert.mcmc[, c("b_Intercept", "b_FERTILIZER")]
    fit = coefs %*% t(Xmat)
    resid = sweep(fit, 2, fert$FERTILIZER, "-")
    var_f = apply(fit, 1, var)
    var_e = apply(resid, 1, var)
    R2 = var_f/(var_f + var_e)
    tidyMCMC(as.mcmc(R2), conf.int = TRUE, conf.method = "HPDinterval")
    
      term  estimate  std.error  conf.low conf.high
    1 var1 0.9271947 0.07609225 0.7798637         1
    
    # for comparison with frequentist
    summary(lm(YIELD ~ FERTILIZER, data = fert))
    
    Call:
    lm(formula = YIELD ~ FERTILIZER, data = fert)
    
    Residuals:
       Min     1Q Median     3Q    Max 
    -22.79 -11.07  -5.00  12.00  29.79 
    
    Coefficients:
                Estimate Std. Error t value Pr(>|t|)    
    (Intercept) 51.93333   12.97904   4.001  0.00394 ** 
    FERTILIZER   0.81139    0.08367   9.697 1.07e-05 ***
    ---
    Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    
    Residual standard error: 19 on 8 degrees of freedom
    Multiple R-squared:  0.9216,	Adjusted R-squared:  0.9118 
    F-statistic: 94.04 on 1 and 8 DF,  p-value: 1.067e-05
    

Simple linear regression

Christensen et al. (1996) studied the relationships between coarse woody debris (CWD) and, shoreline vegetation and lake development in a sample of 16 lakes. They defined CWD as debris greater than 5cm in diameter and recorded, for a number of plots on each lake, the basal area (m2.km-1) of CWD in the nearshore water, and the density (no.km-1) of riparian trees along the shore. The data are in the file christ.csv and the relevant variables are the response variable, CWDBASAL (coarse woody debris basal area, m2.km-1), and the predictor variable, RIPDENS (riparian tree density, trees.km-1).

Download Christensen data set
Format of christ.csv data files
LAKERIPDENSCWDBASAL
Bay1270121
Bergner121041
Crampton1800183
Long1875130
Roach1300127
.........

LAKEName of the North American freshwater lake from which the observations were collected
RIPDENSDensity of riparian trees (trees.km-1) Predictor variable
CWDBASALCourse woody debris basal area (m2.km-1) Response variable
Lake

Open the christ data file.
Show code
christ <- read.table("../downloads/data/christ.csv", header = T, sep = ",", strip.white = T)
head(christ)
        LAKE RIPDENS CWDBASAL
1        Bay    1270      121
2    Bergner    1210       41
3   Crampton    1800      183
4       Long    1875      130
5      Roach    1300      127
6 Tenderfoot    2150      134
  1. The researchers were most likely interested in investigating whether there was a relationship between course woody debris basal area and the density of riparian vegetation. Write out an appropriate linear model.
  2. Perform exploratory data analysis to help guide what sort of analysis will be suitable and whether the various assumptions are likely to be met.
    Show code
    ggplot(christ, aes(y = CWDBASAL, x = RIPDENS)) + geom_point() + geom_smooth()
    
    plot of chunk tut7.2bQ2.1
    ggplot(christ, aes(y = CWDBASAL, x = 1)) + geom_boxplot()
    
    plot of chunk tut7.2bQ2.1
    ggplot(christ, aes(y = RIPDENS, x = 1)) + geom_boxplot()
    
    plot of chunk tut7.2bQ2.1
  3. Fit the appropriate Bayesian model.
    Show MCMCpack code
    library(MCMCpack)
    christ.mcmcpack = MCMCregress(CWDBASAL ~ RIPDENS, data = christ)
    
    Show JAGS code
            modelString=" 
    	model {
    	#Likelihood
    	for (i in 1:n) {
    	y[i]~dnorm(mu[i],tau)
    	mu[i] <- alpha+beta*x[i]
    	}
    	
    	#Priors
    	alpha ~ dnorm (0.01,1.0E-6)
    	beta ~ dnorm(0,1.0E-6)
    	tau <- 1 / (sigma * sigma)
    	sigma~dgamma(0.001,0.001)
    	}
    	"
    
            christ.list <- with(christ,
            list(x=RIPDENS,
            y=CWDBASAL,n=nrow(christ))
            )
    
            params <- c("alpha","beta","sigma")
            burnInSteps = 2000
            nChains = 3
            numSavedSteps = 50000
            thinSteps = 10
            nIter = ceiling((numSavedSteps * thinSteps)/nChains)
    
            christ.r2jags <- jags(data=christ.list,
            inits=NULL, #or inits=list(inits,inits,inits) # since there are three chains
            parameters.to.save=params,
            model.file=textConnection(modelString), #"../downloads/BUGSscripts/tut7.2bQ1_JAGS.txt",
            n.chains=nChains,
            n.iter=nIter,
            n.burnin=burnInSteps,
            n.thin=thinSteps
            )
    
    Compiling model graph
       Resolving undeclared variables
       Allocating nodes
    Graph information:
       Observed stochastic nodes: 16
       Unobserved stochastic nodes: 3
       Total graph size: 77
    
    Initializing model
    
    Show RSTAN code
    modelString = " 
    data { 
    int<lower=1> n;   // total number of observations 
    vector[n] Y;      // response variable 
    int<lower=1> nX;  // number of effects 
    matrix[n, nX] X;   // model matrix 
    } 
    ransformed data { 
    matrix[n, nX - 1] Xc;  // centered version of X 
    vector[nX - 1] means_X;  // column means of X before centering 
    
    for (i in 2:nX) { 
    means_X[i - 1] = mean(X[, i]); 
    Xc[, i - 1] = X[, i] - means_X[i - 1]; 
    }  
    } 
    parameters { 
    vector[nX-1] beta;  // population-level effects 
    real cbeta0;  // center-scale intercept 
    real<lower=0> sigma;  // residual SD 
    } 
    ransformed parameters { 
    } 
    model { 
    vector[n] mu; 
    mu = Xc * beta + cbeta0; 
    // prior specifications 
    beta ~ normal(0, 100); 
    cbeta0 ~ normal(0, 100); 
    sigma ~ cauchy(0, 5); 
    // likelihood contribution 
    Y ~ normal(mu, sigma); 
    } 
    generated quantities { 
    real beta0;  // population-level intercept 
    beta0 = cbeta0 - dot_product(means_X, beta); 
    }
    "
    
    Xmat <- model.matrix(~RIPDENS, data = christ)
    christ.list <- with(christ, list(Y = CWDBASAL, X = Xmat, nX = ncol(Xmat), n = nrow(christ)))
    
    library(rstan)
    christ.rstan <- stan(data = christ.list, model_code = modelString, chains = 3, iter = 5000, warmup = 500,
        thin = 2)
    
    SAMPLING FOR MODEL 'c89e04c2495a0b6eb4be2b406df0876b' NOW (CHAIN 1).
    
    Gradient evaluation took 1e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.1 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration:  501 / 5000 [ 10%]  (Sampling)
    Iteration: 1000 / 5000 [ 20%]  (Sampling)
    Iteration: 1500 / 5000 [ 30%]  (Sampling)
    Iteration: 2000 / 5000 [ 40%]  (Sampling)
    Iteration: 2500 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.031024 seconds (Warm-up)
                   0.075979 seconds (Sampling)
                   0.107003 seconds (Total)
    
    
    SAMPLING FOR MODEL 'c89e04c2495a0b6eb4be2b406df0876b' NOW (CHAIN 2).
    
    Gradient evaluation took 5e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.05 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration:  501 / 5000 [ 10%]  (Sampling)
    Iteration: 1000 / 5000 [ 20%]  (Sampling)
    Iteration: 1500 / 5000 [ 30%]  (Sampling)
    Iteration: 2000 / 5000 [ 40%]  (Sampling)
    Iteration: 2500 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.019954 seconds (Warm-up)
                   0.06602 seconds (Sampling)
                   0.085974 seconds (Total)
    
    
    SAMPLING FOR MODEL 'c89e04c2495a0b6eb4be2b406df0876b' NOW (CHAIN 3).
    
    Gradient evaluation took 5e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.05 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration:  501 / 5000 [ 10%]  (Sampling)
    Iteration: 1000 / 5000 [ 20%]  (Sampling)
    Iteration: 1500 / 5000 [ 30%]  (Sampling)
    Iteration: 2000 / 5000 [ 40%]  (Sampling)
    Iteration: 2500 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.050727 seconds (Warm-up)
                   0.076632 seconds (Sampling)
                   0.127359 seconds (Total)
    
    Show RSTANARM code
    christ.rstanarm = stan_glm(CWDBASAL ~ RIPDENS, data = christ, iter = 5000, warmup = 500, chains = 3,
        thin = 2, refresh = 0, prior_intercept = normal(0, 1000), prior = normal(0, 1000), prior_aux = cauchy(0,
            25))
    
    Gradient evaluation took 3.7e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.37 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 2.76309 seconds (Warm-up)
                   1.68553 seconds (Sampling)
                   4.44862 seconds (Total)
    
    
    Gradient evaluation took 1.1e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.11 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 1.85513 seconds (Warm-up)
                   1.09875 seconds (Sampling)
                   2.95388 seconds (Total)
    
    
    Gradient evaluation took 9e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.09 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 3.49276 seconds (Warm-up)
                   1.17575 seconds (Sampling)
                   4.66851 seconds (Total)
    
    Show BRMS code
    christ.brm = brm(CWDBASAL ~ RIPDENS, data = christ, iter = 5000, warmup = 500, chains = 3, thin = 2,
        refresh = 0, prior = c(prior(normal(0, 1000), class = "Intercept"), prior(normal(0, 1000), class = "b"),
            prior(cauchy(0, 25), class = "sigma")))
    
    Gradient evaluation took 9e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.09 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.041827 seconds (Warm-up)
                   0.067657 seconds (Sampling)
                   0.109484 seconds (Total)
    
    
    Gradient evaluation took 1.2e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.12 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.037164 seconds (Warm-up)
                   0.0659 seconds (Sampling)
                   0.103064 seconds (Total)
    
    
    Gradient evaluation took 6e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.06 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.030273 seconds (Warm-up)
                   0.085104 seconds (Sampling)
                   0.115377 seconds (Total)
    
  4. Explore MCMC diagnostics
    Show MCMCpack code
    library(MCMCpack)
    plot(christ.mcmcpack)
    
    plot of chunk tut7.2bQ2.3a
    raftery.diag(christ.mcmcpack)
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
                                                       
                 Burn-in  Total Lower bound  Dependence
                 (M)      (N)   (Nmin)       factor (I)
     (Intercept) 3        4028  3746         1.080     
     RIPDENS     2        3914  3746         1.040     
     sigma2      2        3680  3746         0.982     
    
    autocorr.diag(christ.mcmcpack)
    
            (Intercept)      RIPDENS       sigma2
    Lag 0   1.000000000  1.000000000  1.000000000
    Lag 1   0.011287106  0.004374026  0.162987189
    Lag 5  -0.004110531  0.001777689  0.008242103
    Lag 10 -0.015174763 -0.014133085  0.002405411
    Lag 50 -0.003762082 -0.006531493 -0.009647390
    
    Show JAGS code
    library(R2jags)
    library(coda)
    christ.mcmc = as.mcmc(christ.r2jags)
    plot(christ.mcmc)
    
    plot of chunk tut7.2bQ2.3b
    raftery.diag(christ.mcmc)
    
    [[1]]
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
                                                    
              Burn-in  Total Lower bound  Dependence
              (M)      (N)   (Nmin)       factor (I)
     alpha    20       37830 3746         10.10     
     beta     20       37270 3746          9.95     
     deviance 20       37640 3746         10.00     
     sigma    10       37440 3746          9.99     
    
    
    [[2]]
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
                                                    
              Burn-in  Total Lower bound  Dependence
              (M)      (N)   (Nmin)       factor (I)
     alpha    20       37830 3746         10.10     
     beta     20       37830 3746         10.10     
     deviance 10       37440 3746          9.99     
     sigma    20       38020 3746         10.10     
    
    
    [[3]]
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
                                                    
              Burn-in  Total Lower bound  Dependence
              (M)      (N)   (Nmin)       factor (I)
     alpha    20       37640 3746         10.00     
     beta     20       37640 3746         10.00     
     deviance 20       36710 3746          9.80     
     sigma    20       37000 3746          9.88     
    
    autocorr.diag(christ.mcmc)
    
                    alpha          beta     deviance         sigma
    Lag 0    1.0000000000  1.0000000000  1.000000000  1.000000e+00
    Lag 10  -0.0009480939 -0.0001283899  0.002458865  3.570752e-03
    Lag 50   0.0091996629  0.0044812666 -0.003176260 -3.782869e-03
    Lag 100  0.0001015533 -0.0003768049  0.001761242 -7.936498e-05
    Lag 500  0.0061069559  0.0054183924  0.004162177  5.187498e-04
    
    Show RSTAN code
    library(rstan)
    library(coda)
    s = as.array(christ.rstan)
    christ.mcmc <- do.call(mcmc.list, plyr:::alply(s[, , -(length(s[1, 1, ]))], 2, as.mcmc))
    plot(christ.mcmc)
    
    plot of chunk tut7.2bQ2.3c
    raftery.diag(christ.mcmc)
    
    $`1`
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
    
    You need a sample size of at least 3746 with these values of q, r and s
    
    $`2`
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
    
    You need a sample size of at least 3746 with these values of q, r and s
    
    $`3`
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
    
    You need a sample size of at least 3746 with these values of q, r and s
    
    autocorr.diag(christ.mcmc)
    
                beta[1]       cbeta0         sigma         beta0
    Lag 0   1.000000000  1.000000000  1.0000000000  1.0000000000
    Lag 1   0.047995261  0.034159169  0.0738886641  0.0508115262
    Lag 5  -0.010886901 -0.027535766  0.0049054884 -0.0127033106
    Lag 10 -0.016754669  0.011014910  0.0004265406 -0.0101132742
    Lag 50  0.001727158 -0.006262706 -0.0052488064 -0.0008333885
    
    library(rstan)
    library(coda)
    stan_ac(christ.rstan)
    
    plot of chunk tut7.2bQ2.3c1
    stan_rhat(christ.rstan)
    
    plot of chunk tut7.2bQ2.3c1
    stan_ess(christ.rstan)
    
    plot of chunk tut7.2bQ2.3c1
    # using Bayeseplot
    library(bayesplot)
    detach("package:reshape")
    mcmc_trace(as.array(christ.rstan))
    
    plot of chunk tut7.2bQ2.3c2
    mcmc_trace(as.array(christ.rstan), regex_pars = "beta|sigma")
    
    plot of chunk tut7.2bQ2.3c2
    mcmc_dens(as.array(christ.rstan))
    
    plot of chunk tut7.2bQ2.3c2
    detach("package:reshape")
    library(bayesplot)
    mcmc_combo(as.array(christ.rstan))
    
    plot of chunk tut7.2bQ2.3c3
    Show RSTANARM code
    library(rstan)
    library(coda)
    s = as.array(christ.rstanarm)
    christ.mcmc <- do.call(mcmc.list, plyr:::alply(s[, , -(length(s[1, 1, ]))], 2, as.mcmc))
    plot(christ.mcmc)
    
    plot of chunk tut7.2bQ2.3d
    raftery.diag(christ.mcmc)
    
    $`1`
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
    
    You need a sample size of at least 3746 with these values of q, r and s
    
    $`2`
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
    
    You need a sample size of at least 3746 with these values of q, r and s
    
    $`3`
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
    
    You need a sample size of at least 3746 with these values of q, r and s
    
    autocorr.diag(christ.mcmc)
    
            (Intercept)      RIPDENS
    Lag 0   1.000000000  1.000000000
    Lag 1   0.041291203  0.010643546
    Lag 5  -0.005398754 -0.009086948
    Lag 10  0.002417242 -0.003359512
    Lag 50 -0.010695723 -0.010799876
    
    library(rstan)
    library(coda)
    stan_ac(christ.rstanarm)
    
    plot of chunk tut7.2bQ2.3d1
    stan_rhat(christ.rstanarm)
    
    plot of chunk tut7.2bQ2.3d1
    stan_ess(christ.rstanarm)
    
    plot of chunk tut7.2bQ2.3d1
    # using Bayeseplot
    library(bayesplot)
    detach("package:reshape")
    mcmc_trace(as.array(christ.rstanarm))
    
    plot of chunk tut7.2bQ2.3d2
    mcmc_trace(as.array(christ.rstanarm), regex_pars = "Intercept|x|sigma")
    
    plot of chunk tut7.2bQ2.3d2
    mcmc_dens(as.array(christ.rstan))
    
    plot of chunk tut7.2bQ2.3d2
    detach("package:reshape")
    library(bayesplot)
    mcmc_combo(as.array(christ.rstanarm))
    
    plot of chunk tut7.2bQ2.3d3
    library(rstanarm)
    posterior_vs_prior(christ.rstanarm, color_by = "vs", group_by = TRUE, facet_args = list(scales = "free_y"))
    
    Gradient evaluation took 2.1e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.21 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 3.62107 seconds (Warm-up)
                   0.036939 seconds (Sampling)
                   3.65801 seconds (Total)
    
    
    Gradient evaluation took 9e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.09 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 3.67508 seconds (Warm-up)
                   0.057926 seconds (Sampling)
                   3.73301 seconds (Total)
    
    plot of chunk tut7.2bQ2.3d4
    Show BRMS code
    library(coda)
    library(brms)
    christ.mcmc = as.mcmc(christ.brm)
    plot(christ.mcmc)
    
    plot of chunk tut7.2bQ2.3e
    raftery.diag(christ.mcmc)
    
    [[1]]
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
    
    You need a sample size of at least 3746 with these values of q, r and s
    
    [[2]]
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
    
    You need a sample size of at least 3746 with these values of q, r and s
    
    [[3]]
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
    
    You need a sample size of at least 3746 with these values of q, r and s
    
    autocorr.diag(christ.mcmc)
    
    Error in ts(x, start = start(x), end = end(x), deltat = thin(x)): invalid time series parameters specified
    
    library(coda)
    stan_ac(christ.brm$fit)
    
    plot of chunk tut7.2bQ2.3e1
    stan_rhat(christ.brm$fit)
    
    plot of chunk tut7.2bQ2.3e1
    stan_ess(christ.brm$fit)
    
    plot of chunk tut7.2bQ2.3e1
  5. Perform model validation
    Show MCMCpack code
    library(MCMCpack)
    christ.mcmc = as.data.frame(christ.mcmcpack)
    # generate a model matrix
    newdata = data.frame(RIPDENS = christ$RIPDENS)
    Xmat = model.matrix(~RIPDENS, newdata)
    ## get median parameter estimates
    coefs = apply(christ.mcmc[, 1:2], 2, median)
    fit = as.vector(coefs %*% t(Xmat))
    resid = christ$CWDBASAL - fit
    ggplot() + geom_point(data = NULL, aes(y = resid, x = fit))
    
    plot of chunk tut7.2bQ2.4a1
    library(MCMCpack)
    christ.mcmc = as.data.frame(christ.mcmcpack)
    # generate a model matrix
    newdata = data.frame(RIPDENS = christ$RIPDENS)
    Xmat = model.matrix(~RIPDENS, newdata)
    ## get median parameter estimates
    coefs = apply(christ.mcmc[, 1:2], 2, median)
    fit = as.vector(coefs %*% t(Xmat))
    resid = christ$CWDBASAL - fit
    ggplot() + geom_point(data = NULL, aes(y = resid, x = christ$RIPDENS))
    
    plot of chunk tut7.2bQ2.4a2
    library(MCMCpack)
    christ.mcmc = as.data.frame(christ.mcmcpack)
    # generate a model matrix
    newdata = data.frame(RIPDENS = christ$RIPDENS)
    Xmat = model.matrix(~RIPDENS, newdata)
    ## get median parameter estimates
    coefs = apply(christ.mcmc[, 1:2], 2, median)
    fit = as.vector(coefs %*% t(Xmat))
    resid = christ$CWDBASAL - fit
    sresid = resid/sd(resid)
    ggplot() + geom_point(data = NULL, aes(y = sresid, x = fit))
    
    plot of chunk tut7.2bQ2.4a3
    library(MCMCpack)
    christ.mcmc = as.matrix(christ.mcmcpack)
    # generate a model matrix
    Xmat = model.matrix(~RIPDENS, christ)
    ## get median parameter estimates
    coefs = christ.mcmc[, 1:2]
    fit = coefs %*% t(Xmat)
    ## draw samples from this model
    yRep = sapply(1:nrow(christ.mcmc), function(i) rnorm(nrow(christ), fit[i, ], sqrt(christ.mcmc[i, "sigma2"])))
    ggplot() + geom_density(data = NULL, aes(x = as.vector(yRep), fill = "Model"), alpha = 0.5) + geom_density(data = christ,
        aes(x = CWDBASAL, fill = "Obs"), alpha = 0.5)
    
    plot of chunk tut7.2bQ2.4a4
    ## Plot predicted effects
    library(MCMCpack)
    christ.mcmc = as.matrix(christ.mcmcpack)
    # generate a model matrix
    newdata = with(christ, data.frame(RIPDENS = seq(min(RIPDENS, na.rm = TRUE), max(RIPDENS, na.rm = TRUE),
        len = 100)))
    Xmat = model.matrix(~RIPDENS, data = newdata)
    ## get median parameter estimates
    coefs = christ.mcmc[, 1:2]
    fit = coefs %*% t(Xmat)
    fit = apply(fit, 2, function(x) rnorm(length(x), x, sqrt(christ.mcmc[, "sigma2"])))
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(fit), conf.int = TRUE, conf.method = "HPDinterval"))
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_ribbon(aes(ymin = conf.low, ymax = conf.high),
        fill = "blue", alpha = 0.3) + geom_line() + geom_point(data = christ, aes(y = CWDBASAL))
    
    plot of chunk tut7.2bQ2.4a5
    ## Plot effects
    library(MCMCpack)
    christ.mcmc = as.matrix(christ.mcmcpack)
    # generate a model matrix
    newdata = with(christ, data.frame(RIPDENS = seq(min(RIPDENS, na.rm = TRUE), max(RIPDENS, na.rm = TRUE),
        len = 100)))
    Xmat = model.matrix(~RIPDENS, data = newdata)
    ## get median parameter estimates
    coefs = christ.mcmc[, 1:2]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(fit), conf.int = TRUE, conf.method = "HPDinterval"))
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_ribbon(aes(ymin = conf.low, ymax = conf.high),
        fill = "blue", alpha = 0.3) + geom_line() + geom_point(data = christ, aes(y = CWDBASAL))
    
    plot of chunk tut7.2bQ2.4a6
    Show JAGS code
    library(R2jags)
    christ.mcmc = christ.r2jags$BUGSoutput$sims.matrix[, c("alpha", "beta")]
    # generate a model matrix
    newdata = data.frame(RIPDENS = christ$RIPDENS)
    Xmat = model.matrix(~RIPDENS, newdata)
    ## get median parameter estimates
    coefs = apply(christ.mcmc, 2, median)
    fit = as.vector(coefs %*% t(Xmat))
    resid = christ$CWDBASAL - fit
    ggplot() + geom_point(data = NULL, aes(y = resid, x = fit))
    
    plot of chunk tut7.2bQ2.4b1
    ggplot() + geom_point(data = NULL, aes(y = resid, x = christ$RIPDENS))
    
    plot of chunk tut7.2bQ2.4b2
    sresid = resid/sd(resid)
    ggplot() + geom_point(data = NULL, aes(y = sresid, x = fit))
    
    plot of chunk tut7.2bQ2.4b3
    christ.mcmc = christ.r2jags$BUGSoutput$sims.matrix[, c("alpha", "beta", "sigma")]
    # generate a model matrix
    Xmat = model.matrix(~RIPDENS, christ)
    ## get median parameter estimates
    coefs = christ.mcmc[, c("alpha", "beta")]
    fit = coefs %*% t(Xmat)
    ## draw samples from this model
    yRep = sapply(1:nrow(christ.mcmc), function(i) rnorm(nrow(christ), fit[i, ], christ.mcmc[i, "sigma"]))
    ggplot() + geom_density(data = NULL, aes(x = as.vector(yRep), fill = "Model"), alpha = 0.5) + geom_density(data = christ,
        aes(x = CWDBASAL, fill = "Obs"), alpha = 0.5)
    
    plot of chunk tut7.2bQ2.4b4
    christ.mcmc = christ.r2jags$BUGSoutput$sims.matrix[, c("alpha", "beta", "sigma")]
    # generate a model matrix
    newdata = with(christ, data.frame(RIPDENS = seq(min(RIPDENS, na.rm = TRUE), max(RIPDENS, na.rm = TRUE),
        len = 100)))
    Xmat = model.matrix(~RIPDENS, data = newdata)
    ## get median parameter estimates
    coefs = christ.mcmc[, 1:2]
    fit = coefs %*% t(Xmat)
    fit = apply(fit, 2, function(x) rnorm(length(x), x, christ.mcmc[, "sigma"]))
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(fit), conf.int = TRUE, conf.method = "HPDinterval"))
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_ribbon(aes(ymin = conf.low, ymax = conf.high),
        fill = "blue", alpha = 0.3) + geom_line() + geom_point(data = christ, aes(y = CWDBASAL))
    
    plot of chunk tut7.2bQ2.4b5
    christ.mcmc = christ.r2jags$BUGSoutput$sims.matrix[, c("alpha", "beta", "sigma")]
    # generate a model matrix
    newdata = with(christ, data.frame(RIPDENS = seq(min(RIPDENS, na.rm = TRUE), max(RIPDENS, na.rm = TRUE),
        len = 100)))
    Xmat = model.matrix(~RIPDENS, data = newdata)
    ## get median parameter estimates
    coefs = christ.mcmc[, 1:2]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(fit), conf.int = TRUE, conf.method = "HPDinterval"))
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_ribbon(aes(ymin = conf.low, ymax = conf.high),
        fill = "blue", alpha = 0.3) + geom_line() + geom_point(data = christ, aes(y = CWDBASAL))
    
    plot of chunk tut7.2bQ2.4b6
    Show RSTAN code
    library(rstan)
    christ.mcmc = as.matrix(christ.rstan)[, c("beta0", "beta[1]")]
    # generate a model matrix
    newdata = data.frame(RIPDENS = christ$RIPDENS)
    Xmat = model.matrix(~RIPDENS, newdata)
    ## get median parameter estimates
    coefs = apply(christ.mcmc, 2, median)
    fit = as.vector(coefs %*% t(Xmat))
    resid = christ$CWDBASAL - fit
    ggplot() + geom_point(data = NULL, aes(y = resid, x = fit))
    
    plot of chunk tut7.2bQ2.4c1
    ggplot() + geom_point(data = NULL, aes(y = resid, x = christ$RIPDENS))
    
    plot of chunk tut7.2bQ2.4c2
    sresid = resid/sd(resid)
    ggplot() + geom_point(data = NULL, aes(y = sresid, x = fit))
    
    plot of chunk tut7.2bQ2.4c3
    christ.mcmc = as.matrix(christ.rstan)[, c("beta0", "beta[1]", "sigma")]
    # generate a model matrix
    Xmat = model.matrix(~RIPDENS, christ)
    ## get median parameter estimates
    coefs = christ.mcmc[, c("beta0", "beta[1]")]
    fit = coefs %*% t(Xmat)
    ## draw samples from this model
    yRep = sapply(1:nrow(christ.mcmc), function(i) rnorm(nrow(christ), fit[i, ], christ.mcmc[i, "sigma"]))
    ggplot() + geom_density(data = NULL, aes(x = as.vector(yRep), fill = "Model"), alpha = 0.5) + geom_density(data = christ,
        aes(x = CWDBASAL, fill = "Obs"), alpha = 0.5)
    
    plot of chunk tut7.2bQ2.4c4
    christ.mcmc = as.matrix(christ.rstan)[, c("beta0", "beta[1]", "sigma")]
    # generate a model matrix
    newdata = with(christ, data.frame(RIPDENS = seq(min(RIPDENS, na.rm = TRUE), max(RIPDENS, na.rm = TRUE),
        len = 100)))
    Xmat = model.matrix(~RIPDENS, data = newdata)
    ## get median parameter estimates
    coefs = christ.mcmc[, 1:2]
    fit = coefs %*% t(Xmat)
    fit = apply(fit, 2, function(x) rnorm(length(x), x, christ.mcmc[, "sigma"]))
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(fit), conf.int = TRUE, conf.method = "HPDinterval"))
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_ribbon(aes(ymin = conf.low, ymax = conf.high),
        fill = "blue", alpha = 0.3) + geom_line() + geom_point(data = christ, aes(y = CWDBASAL))
    
    plot of chunk tut7.2bQ2.4c5
    christ.mcmc = as.matrix(christ.rstan)[, c("beta0", "beta[1]", "sigma")]
    # generate a model matrix
    newdata = with(christ, data.frame(RIPDENS = seq(min(RIPDENS, na.rm = TRUE), max(RIPDENS, na.rm = TRUE),
        len = 100)))
    Xmat = model.matrix(~RIPDENS, data = newdata)
    ## get median parameter estimates
    coefs = christ.mcmc[, 1:2]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(fit), conf.int = TRUE, conf.method = "HPDinterval"))
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_ribbon(aes(ymin = conf.low, ymax = conf.high),
        fill = "blue", alpha = 0.3) + geom_line() + geom_point(data = christ, aes(y = CWDBASAL))
    
    plot of chunk tut7.2bQ2.4c6
    Show RSTANARM code
    library(rstanarm)
    resid = resid(christ.rstanarm)
    fit = fitted(christ.rstanarm)
    ggplot() + geom_point(data = NULL, aes(y = resid, x = fit))
    
    plot of chunk tut7.2bQ2.4d1
    ggplot() + geom_point(data = NULL, aes(y = resid, x = christ$RIPDENS))
    
    plot of chunk tut7.2bQ2.4d2
    sresid = resid/sd(resid)
    ggplot() + geom_point(data = NULL, aes(y = sresid, x = fit))
    
    plot of chunk tut7.2bQ2.4d3
    y_pred = posterior_predict(christ.rstanarm)
    newdata = christ %>% cbind(t(y_pred)) %>% gather(key = "Rep", value = "Value", -CWDBASAL, -RIPDENS, -LAKE)
    ggplot(newdata, aes(Value, x = RIPDENS)) + geom_violin(color = "blue", fill = "blue", alpha = 0.5) +
        geom_violin(data = christ, aes(y = CWDBASAL, x = RIPDENS), fill = "red", color = "red", alpha = 0.5)
    
    plot of chunk tut7.2bQ2.4d4
    ## Calculate the fitted values
    newdata = data.frame(RIPDENS = seq(min(christ$RIPDENS, na.rm = TRUE), max(christ$RIPDENS, na.rm = TRUE),
        len = 1000))
    fit = posterior_predict(christ.rstanarm, newdata = newdata)
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(fit), conf.int = TRUE, conf.method = "HPDinterval"))
    
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_point(data = christ, aes(y = CWDBASAL)) + geom_line() +
        geom_ribbon(aes(ymin = conf.low, ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_continuous("CWDBASAL") +
        scale_x_continuous("RIPDENS") + theme_classic()
    
    plot of chunk tut7.2bQ2.4d4
    ## Marginal plots
    pp_check(christ.rstanarm, x = christ$RIPDENS, plotfun = "ribbon")
    
    plot of chunk tut7.2bQ2.4d4
    newdata = data.frame(RIPDENS = seq(min(christ$RIPDENS, na.rm = TRUE), max(christ$RIPDENS, na.rm = TRUE),
        len = 100))
    fit = posterior_linpred(christ.rstanarm, newdata = newdata)
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(fit), conf.int = TRUE, conf.method = "HPDinterval"))
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_ribbon(aes(ymin = conf.low, ymax = conf.high),
        fill = "blue", alpha = 0.3) + geom_line() + geom_point(data = christ, aes(y = CWDBASAL))
    
    plot of chunk tut7.2bQ2.4d4
    Show BRMS code
    library(brms)
    resid = resid(christ.brm)[, "Estimate"]
    fit = fitted(christ.brm)[, "Estimate"]
    ggplot() + geom_point(data = NULL, aes(y = resid, x = fit))
    
    plot of chunk tut7.2bQ2.4e1
    ggplot() + geom_point(data = NULL, aes(y = resid, x = christ$RIPDENS))
    
    plot of chunk tut7.2bQ2.4e2
    sresid = resid/sd(resid)
    ggplot() + geom_point(data = NULL, aes(y = sresid, x = fit))
    
    plot of chunk tut7.2bQ2.4e3
    y_pred = posterior_predict(christ.brm)
    newdata = christ %>% cbind(t(y_pred)) %>% gather(key = "Rep", value = "Value", -CWDBASAL, -RIPDENS, -LAKE)
    ggplot(newdata, aes(Value, x = RIPDENS)) + geom_violin(color = "blue", fill = "blue", alpha = 0.5) +
        geom_violin(data = christ, aes(y = CWDBASAL, x = RIPDENS), fill = "red", color = "red", alpha = 0.5)
    
    plot of chunk tut7.2bQ2.4e4
    ## Calculate the fitted values
    newdata = data.frame(RIPDENS = seq(min(christ$RIPDENS, na.rm = TRUE), max(christ$RIPDENS, na.rm = TRUE),
        len = 1000))
    fit = posterior_predict(christ.brm, newdata = newdata)
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(fit), conf.int = TRUE, conf.method = "HPDinterval"))
    
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_point(data = christ, aes(y = CWDBASAL)) + geom_line() +
        geom_ribbon(aes(ymin = conf.low, ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_continuous("CWDBASAL") +
        scale_x_continuous("RIPDENS") + theme_classic()
    
    plot of chunk tut7.2bQ2.4e4
    # marginal effects plots
    marginal_effects(christ.brm)
    
    plot of chunk tut7.2bQ2.4e4
    marginal_effects(christ.brm, spaghetti = TRUE, nsamples = 100)
    
    plot of chunk tut7.2bQ2.4e4
  6. The value of plotting the fitted model is evident at the point. Whilst the prediction intervals did encompass all the observed data, suggesting that the model does represent the observed data, the fact that prediction or confidence intervals descend below zero for low values of RIPDENS indicates that the model does not adequately capture the underlying data generation process. Obviously, it is not logically possible to obtain a basal area of course woody debris less than zero.

    At this point we should make adjustments to correct this. There are multiple options available:

    • fit the model against a distribution (family) that more suitably reflects the underlying data generation process. A Gamma and log-normal distributions are two possible candidates. This option will be explored in Tutorial 10.4 and Tutorial 10.7a.
    • apply a scale transform on the response (CWDBASAL) such that back-transformed derivations of parameter estimates are naturally bound at zero. Of course, with this if we transform the scale of the response variable, it might be necessary to similarly rescale the predictor variable in order to preserve linearity.

      Log transformations can be useful when applied to positive responses. In this case however, log transformations result in substantial non-linearity and are therefore not appropriate. Square-root transformations are traditionally popular for normalization, yet can have substantial back-transformation issues when the values to be back-transformed have a mixture of positive and negative values or even a mixture of values less than or greater than one. This can be partly elevated by applying transformations involving the reciprocal of an odd positive integer (powers 1/3, 1/5, 1/7, etc.). Fortunately in this case a square-root transformation appears to be free of such issues.

      Although this approach might now be considered less preferred the the previous option, it can be applied within the current (OLS) context and thus will be the approach demonstrated here.

  7. Re-fit the appropriate Bayesian model.
    Show MCMCpack code
    library(MCMCpack)
    christ.mcmcpack = MCMCregress(I(CWDBASAL^(1/3)) ~ RIPDENS, data = christ)
    
    ## Check marginal plot
    christ.mcmc = as.matrix(christ.mcmcpack)
    # generate a model matrix
    newdata = with(christ, data.frame(RIPDENS = seq(min(RIPDENS, na.rm = TRUE), max(RIPDENS, na.rm = TRUE),
        len = 100)))
    Xmat = model.matrix(~RIPDENS, data = newdata)
    ## get median parameter estimates
    coefs = christ.mcmc[, 1:2]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(fit), conf.int = TRUE, conf.method = "HPDinterval"))
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_ribbon(aes(ymin = conf.low, ymax = conf.high),
        fill = "blue", alpha = 0.3) + geom_line()
    
    plot of chunk tut7.2bQ2.2a2
    ## Check marginal plot
    newdata = data.frame(RIPDENS = seq(min(christ$RIPDENS, na.rm = TRUE), max(christ$RIPDENS, na.rm = TRUE),
        len = 100))
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(fit^3), conf.int = TRUE, conf.method = "HPDinterval"))
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_ribbon(aes(ymin = conf.low, ymax = conf.high),
        fill = "blue", alpha = 0.3) + geom_line() + geom_point(data = christ, aes(y = CWDBASAL))
    
    plot of chunk tut7.2bQ2.2a2
    Show JAGS code
            modelString=" 
    	model {
    	#Likelihood
    	for (i in 1:n) {
    	y[i]~dnorm(mu[i],tau)
    	mu[i] <- alpha+beta*x[i]
    	}
    	
    	#Priors
    	alpha ~ dnorm (0.01,1.0E-6)
    	beta ~ dnorm(0,1.0E-6)
    	tau <- 1 / (sigma * sigma)
    	sigma~dgamma(0.001,0.001)
    	}
    	"
    
            christ.list <- with(christ,
            list(x=RIPDENS,
            y=CWDBASAL^(1/3),n=nrow(christ))
            )
    
            params <- c("alpha","beta","sigma")
            burnInSteps = 2000
            nChains = 3
            numSavedSteps = 50000
            thinSteps = 10
            nIter = ceiling((numSavedSteps * thinSteps)/nChains)
    
            christ.r2jags <- jags(data=christ.list,
            inits=NULL, #or inits=list(inits,inits,inits) # since there are three chains
            parameters.to.save=params,
            model.file=textConnection(modelString),
            n.chains=nChains,
            n.iter=nIter,
            n.burnin=burnInSteps,
            n.thin=thinSteps
            )
    
    Compiling model graph
       Resolving undeclared variables
       Allocating nodes
    Graph information:
       Observed stochastic nodes: 16
       Unobserved stochastic nodes: 3
       Total graph size: 77
    
    Initializing model
    
    ## Check marginal plot
    christ.mcmc = christ.r2jags$BUGSoutput$sims.matrix[, c("alpha", "beta", "sigma")]
    # generate a model matrix
    newdata = with(christ, data.frame(RIPDENS = seq(min(RIPDENS, na.rm = TRUE), max(RIPDENS, na.rm = TRUE),
        len = 100)))
    Xmat = model.matrix(~RIPDENS, data = newdata)
    coefs = christ.mcmc[, 1:2]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(fit), conf.int = TRUE, conf.method = "HPDinterval"))
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_ribbon(aes(ymin = conf.low, ymax = conf.high),
        fill = "blue", alpha = 0.3) + geom_line()
    
    plot of chunk tut7.2bQ2.2b2
    ## Check marginal plot
    newdata = data.frame(RIPDENS = seq(min(christ$RIPDENS, na.rm = TRUE), max(christ$RIPDENS, na.rm = TRUE),
        len = 100))
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(fit^3), conf.int = TRUE, conf.method = "HPDinterval"))
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_ribbon(aes(ymin = conf.low, ymax = conf.high),
        fill = "blue", alpha = 0.3) + geom_line() + geom_point(data = christ, aes(y = CWDBASAL))
    
    plot of chunk tut7.2bQ2.2b2
    Show RSTAN code
    modelString = " 
    data { 
    int<lower=1> n;   // total number of observations 
    vector[n] Y;      // response variable 
    int<lower=1> nX;  // number of effects 
    matrix[n, nX] X;   // model matrix 
    } 
    ransformed data { 
    matrix[n, nX - 1] Xc;  // centered version of X 
    vector[nX - 1] means_X;  // column means of X before centering 
    
    for (i in 2:nX) { 
    means_X[i - 1] = mean(X[, i]); 
    Xc[, i - 1] = X[, i] - means_X[i - 1]; 
    }  
    } 
    parameters { 
    vector[nX-1] beta;  // population-level effects 
    real cbeta0;  // center-scale intercept 
    real<lower=0> sigma;  // residual SD 
    } 
    ransformed parameters { 
    } 
    model { 
    vector[n] mu; 
    mu = Xc * beta + cbeta0; 
    // prior specifications 
    beta ~ normal(0, 100); 
    cbeta0 ~ normal(0, 100); 
    sigma ~ cauchy(0, 5); 
    // likelihood contribution 
    Y ~ normal(mu, sigma); 
    } 
    generated quantities { 
    real beta0;  // population-level intercept 
    beta0 = cbeta0 - dot_product(means_X, beta); 
    }
    "
    
    Xmat <- model.matrix(~RIPDENS, data = christ)
    christ.list <- with(christ, list(Y = CWDBASAL^(1/3), X = Xmat, nX = ncol(Xmat), n = nrow(christ)))
    
    library(rstan)
    christ.rstan <- stan(data = christ.list, model_code = modelString, chains = 3, iter = 5000, warmup = 500,
        thin = 2)
    
    SAMPLING FOR MODEL 'c89e04c2495a0b6eb4be2b406df0876b' NOW (CHAIN 1).
    
    Gradient evaluation took 1.1e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.11 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration:  501 / 5000 [ 10%]  (Sampling)
    Iteration: 1000 / 5000 [ 20%]  (Sampling)
    Iteration: 1500 / 5000 [ 30%]  (Sampling)
    Iteration: 2000 / 5000 [ 40%]  (Sampling)
    Iteration: 2500 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.095137 seconds (Warm-up)
                   0.176843 seconds (Sampling)
                   0.27198 seconds (Total)
    
    
    SAMPLING FOR MODEL 'c89e04c2495a0b6eb4be2b406df0876b' NOW (CHAIN 2).
    
    Gradient evaluation took 5e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.05 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration:  501 / 5000 [ 10%]  (Sampling)
    Iteration: 1000 / 5000 [ 20%]  (Sampling)
    Iteration: 1500 / 5000 [ 30%]  (Sampling)
    Iteration: 2000 / 5000 [ 40%]  (Sampling)
    Iteration: 2500 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.103326 seconds (Warm-up)
                   0.15283 seconds (Sampling)
                   0.256156 seconds (Total)
    
    
    SAMPLING FOR MODEL 'c89e04c2495a0b6eb4be2b406df0876b' NOW (CHAIN 3).
    
    Gradient evaluation took 6e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.06 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration:  501 / 5000 [ 10%]  (Sampling)
    Iteration: 1000 / 5000 [ 20%]  (Sampling)
    Iteration: 1500 / 5000 [ 30%]  (Sampling)
    Iteration: 2000 / 5000 [ 40%]  (Sampling)
    Iteration: 2500 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.058992 seconds (Warm-up)
                   0.193731 seconds (Sampling)
                   0.252723 seconds (Total)
    
    ## Check marginal plot
    christ.mcmc = as.matrix(christ.rstan)[, c("beta0", "beta[1]", "sigma")]
    # generate a model matrix
    newdata = with(christ, data.frame(RIPDENS = seq(min(RIPDENS, na.rm = TRUE), max(RIPDENS, na.rm = TRUE),
        len = 100)))
    Xmat = model.matrix(~RIPDENS, data = newdata)
    ## get median parameter estimates
    coefs = christ.mcmc[, 1:2]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(fit), conf.int = TRUE, conf.method = "HPDinterval"))
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_ribbon(aes(ymin = conf.low, ymax = conf.high),
        fill = "blue", alpha = 0.3) + geom_line()
    
    plot of chunk tut7.2bQ2.2c2
    ## Check marginal plot
    newdata = data.frame(RIPDENS = seq(min(christ$RIPDENS, na.rm = TRUE), max(christ$RIPDENS, na.rm = TRUE),
        len = 100))
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(fit^3), conf.int = TRUE, conf.method = "HPDinterval"))
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_ribbon(aes(ymin = conf.low, ymax = conf.high),
        fill = "blue", alpha = 0.3) + geom_line() + geom_point(data = christ, aes(y = CWDBASAL))
    
    plot of chunk tut7.2bQ2.2c2
    Show RSTANARM code
    christ.rstanarm = stan_glm(I(CWDBASAL^(1/3)) ~ RIPDENS, data = christ, iter = 5000, warmup = 500, chains = 3,
        thin = 2, refresh = 0, prior_intercept = normal(0, 1000), prior = normal(0, 1000), prior_aux = cauchy(0,
            25))
    
    Gradient evaluation took 2.9e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.29 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.446307 seconds (Warm-up)
                   1.05851 seconds (Sampling)
                   1.50481 seconds (Total)
    
    
    Gradient evaluation took 9e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.09 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.918382 seconds (Warm-up)
                   1.02339 seconds (Sampling)
                   1.94177 seconds (Total)
    
    
    Gradient evaluation took 9e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.09 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.508515 seconds (Warm-up)
                   0.902821 seconds (Sampling)
                   1.41134 seconds (Total)
    
    ## Check marginal plot
    newdata = data.frame(RIPDENS = seq(min(christ$RIPDENS, na.rm = TRUE), max(christ$RIPDENS, na.rm = TRUE),
        len = 100))
    fit = posterior_linpred(christ.rstanarm, newdata = newdata)
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(fit), conf.int = TRUE, conf.method = "HPDinterval"))
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_ribbon(aes(ymin = conf.low, ymax = conf.high),
        fill = "blue", alpha = 0.3) + geom_line()
    
    plot of chunk tut7.2bQ2.2d2
    ## Check marginal plot
    newdata = data.frame(RIPDENS = seq(min(christ$RIPDENS, na.rm = TRUE), max(christ$RIPDENS, na.rm = TRUE),
        len = 100))
    fit = posterior_linpred(christ.rstanarm, newdata = newdata)
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(fit^3), conf.int = TRUE, conf.method = "HPDinterval"))
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_ribbon(aes(ymin = conf.low, ymax = conf.high),
        fill = "blue", alpha = 0.3) + geom_line() + geom_point(data = christ, aes(y = CWDBASAL))
    
    plot of chunk tut7.2bQ2.2d2
    Show BRMS code
    christ.brm = brm(I(CWDBASAL^(1/3)) ~ RIPDENS, data = christ, iter = 5000, warmup = 500, chains = 3, thin = 2,
        refresh = 0, prior = c(prior(normal(0, 1000), class = "Intercept"), prior(normal(0, 1000), class = "b"),
            prior(cauchy(0, 25), class = "sigma")))
    
    Gradient evaluation took 1e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.1 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.095796 seconds (Warm-up)
                   0.206029 seconds (Sampling)
                   0.301825 seconds (Total)
    
    
    Gradient evaluation took 4e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.04 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.109704 seconds (Warm-up)
                   0.179808 seconds (Sampling)
                   0.289512 seconds (Total)
    
    
    Gradient evaluation took 5e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.05 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.095171 seconds (Warm-up)
                   0.170215 seconds (Sampling)
                   0.265386 seconds (Total)
    
    ## Check marginal plot
    library(brms)
    christ.mcmc = as.matrix(christ.brm)
    newdata = data.frame(RIPDENS = seq(min(christ$RIPDENS, na.rm = TRUE), max(christ$RIPDENS, na.rm = TRUE),
        len = 100))
    Xmat = model.matrix(~RIPDENS, newdata)
    coefs = christ.mcmc[, c("b_Intercept", "b_RIPDENS")]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(fit), conf.int = TRUE, conf.method = "HPDinterval"))
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_ribbon(aes(ymin = conf.low, ymax = conf.high),
        fill = "blue", alpha = 0.3) + geom_line()
    
    plot of chunk tut7.2bQ2.2e2
    ## Check marginal plot
    newdata = data.frame(RIPDENS = seq(min(christ$RIPDENS, na.rm = TRUE), max(christ$RIPDENS, na.rm = TRUE),
        len = 100))
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(fit^3), conf.int = TRUE, conf.method = "HPDinterval"))
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_ribbon(aes(ymin = conf.low, ymax = conf.high),
        fill = "blue", alpha = 0.3) + geom_line() + geom_point(data = christ, aes(y = CWDBASAL))
    
    plot of chunk tut7.2bQ2.2e2
  8. Clearly, whilst not perfect, the effects plot is more logical. Fitted values (and confidence intervals) on the third root scale do not contain a mixture of values above and below zero and thus, back-transformations to a natural scale are sensible.

  9. Explore parameter estimates
    Show MCMCpack code
    library(MCMCpack)
    summary(christ.mcmcpack)
    
    Iterations = 1001:11000
    Thinning interval = 1 
    Number of chains = 1 
    Sample size per chain = 10000 
    
    1. Empirical mean and standard deviation for each variable,
       plus standard error of the mean:
    
                     Mean        SD  Naive SE Time-series SE
    (Intercept) -0.228718 0.9582329 9.582e-03      9.425e-03
    RIPDENS      0.003012 0.0007352 7.352e-06      7.163e-06
    sigma2       1.273452 0.5866810 5.867e-03      6.777e-03
    
    2. Quantiles for each variable:
    
                     2.5%       25%       50%      75%    97.5%
    (Intercept) -2.102296 -0.833106 -0.224161 0.373343 1.706202
    RIPDENS      0.001535  0.002556  0.003016 0.003477 0.004467
    sigma2       0.586059  0.885812  1.140838 1.495254 2.712343
    
    library(broom)
    tidyMCMC(christ.mcmcpack, conf.int = TRUE, conf.method = "HPDinterval")
    
             term     estimate    std.error     conf.low   conf.high
    1 (Intercept) -0.228718049 0.9582329153 -2.231431354 1.551137800
    2     RIPDENS  0.003011873 0.0007351707  0.001520431 0.004435215
    3      sigma2  1.273451645 0.5866810241  0.458135477 2.372467015
    
    mcmcpvalue(christ.mcmcpack[, 2])
    
    [1] 6e-04
    
    Show JAGS code
    library(R2jags)
    print(christ.r2jags)
    
    Inference for Bugs model at "5", fit using jags,
     3 chains, each with 166667 iterations (first 2000 discarded), n.thin = 10
     n.sims = 49401 iterations saved
             mu.vect sd.vect   2.5%    25%    50%    75%  97.5%  Rhat n.eff
    alpha     -0.254   0.949 -2.133 -0.862 -0.261  0.360  1.634 1.001 41000
    beta       0.003   0.001  0.002  0.003  0.003  0.004  0.004 1.001 40000
    sigma      1.099   0.227  0.761  0.939  1.064  1.219  1.641 1.001 41000
    deviance  47.856   2.709 44.789 45.874 47.154 49.077 54.835 1.001 44000
    
    For each parameter, n.eff is a crude measure of effective sample size,
    and Rhat is the potential scale reduction factor (at convergence, Rhat=1).
    
    DIC info (using the rule, pD = var(deviance)/2)
    pD = 3.7 and DIC = 51.5
    DIC is an estimate of expected predictive error (lower deviance is better).
    
    # OR
    library(broom)
    tidyMCMC(as.mcmc(christ.r2jags), conf.int = TRUE, conf.method = "HPDinterval")
    
          term     estimate    std.error     conf.low    conf.high
    1    alpha -0.253735823 0.9488442000 -2.068999951  1.689707623
    2     beta  0.003031594 0.0007271712  0.001568172  0.004444404
    3 deviance 47.855954540 2.7086335019 44.550776097 53.182854749
    4    sigma  1.099085426 0.2270903406  0.708150821  1.543613473
    
    mcmcpvalue(christ.r2jags$BUGSoutput$sims.matrix[, c("beta")])
    
    [1] 0.0006072752
    
    Show RSTAN code
    library(rstan)
    summary(christ.rstan)
    
    $summary
                    mean      se_mean           sd          2.5%          25%          50%         75%
    beta[1]  0.003014071 9.323866e-06 0.0007442382   0.001574644  0.002529798  0.003005116  0.00349233
    cbeta0   3.532588489 4.738430e-03 0.2951544668   2.940823361  3.346518520  3.527742075  3.72151151
    sigma    1.145761103 4.002948e-03 0.2497957989   0.778028939  0.971382847  1.107608861  1.27303908
    beta0   -0.227276640 1.247551e-02 0.9771620195  -2.205902973 -0.860914613 -0.225280924  0.40455504
    lp__    -9.294257523 2.439312e-02 1.3986959429 -12.939374565 -9.884172951 -8.919922970 -8.29386968
                   97.5%    n_eff      Rhat
    beta[1]  0.004529292 6371.357 0.9999844
    cbeta0   4.138645318 3879.983 1.0001253
    sigma    1.745191663 3894.130 0.9998791
    beta0    1.674706864 6135.032 0.9999353
    lp__    -7.738204736 3287.848 1.0001045
    
    $c_summary
    , , chains = chain:1
    
             stats
    parameter         mean           sd          2.5%          25%         50%          75%       97.5%
      beta[1]  0.003012956 0.0007367359   0.001608733  0.002523578  0.00299251  0.003485502  0.00448781
      cbeta0   3.532558136 0.2903601379   2.955578580  3.348534442  3.52285785  3.722025361  4.15117917
      sigma    1.141081087 0.2417855281   0.789443225  0.973305505  1.10659204  1.261085766  1.69409378
      beta0   -0.225916238 0.9727568400  -2.140160038 -0.859500810 -0.23688174  0.404555040  1.69298799
      lp__    -9.244647008 1.3985239659 -12.986730744 -9.821343736 -8.83667582 -8.243089368 -7.74575619
    
    , , chains = chain:2
    
             stats
    parameter         mean           sd          2.5%          25%          50%          75%
      beta[1]  0.003002075 0.0007521026   0.001516745  0.002522409  0.002991425  0.003487179
      cbeta0   3.531119503 0.2944475789   2.934661291  3.344866805  3.531856505  3.716769700
      sigma    1.152116061 0.2593116381   0.776460571  0.969750027  1.107721390  1.288436352
      beta0   -0.213782019 0.9841321601  -2.257165263 -0.840676452 -0.199133635  0.429111226
      lp__    -9.337607246 1.3990541932 -12.936652302 -9.950410337 -8.948028090 -8.327997074
             stats
    parameter        97.5%
      beta[1]  0.004515869
      cbeta0   4.102494115
      sigma    1.795514988
      beta0    1.673549856
      lp__    -7.744029663
    
    , , chains = chain:3
    
             stats
    parameter         mean           sd          2.5%          25%          50%          75%
      beta[1]  0.003027181 0.0007439147   0.001611204  0.002543634  0.003026013  0.003504629
      cbeta0   3.534087829 0.3006878009   2.934047840  3.346518520  3.528847242  3.725248748
      sigma    1.144086160 0.2479544783   0.777431920  0.971450043  1.109158218  1.267027411
      beta0   -0.242131664 0.9747867359  -2.196939511 -0.881006482 -0.254368706  0.387771868
      lp__    -9.300518316 1.3975647779 -12.908641487 -9.883698553 -8.942956401 -8.317176264
             stats
    parameter        97.5%
      beta[1]  0.004560656
      cbeta0   4.161998257
      sigma    1.750087140
      beta0    1.655714877
      lp__    -7.729775020
    
    # OR
    library(broom)
    tidyMCMC(christ.rstan, conf.int = TRUE, conf.method = "HPDinterval")
    
         term     estimate    std.error     conf.low  conf.high
    1 beta[1]  0.003014071 0.0007442382  0.001502438 0.00444291
    2  cbeta0  3.532588489 0.2951544668  2.922534076 4.11412126
    3   sigma  1.145761103 0.2497957989  0.705767889 1.61446082
    4   beta0 -0.227276640 0.9771620195 -2.063573813 1.76973681
    
    mcmcpvalue(as.matrix(christ.rstan)[, c("beta[1]")])
    
    [1] 0.0004444444
    
    Show RSTANARM code
    library(rstanarm)
    summary(christ.rstanarm)
    
    Model Info:
    
     function:  stan_glm
     family:    gaussian [identity]
     formula:   I(CWDBASAL^(1/3)) ~ RIPDENS
     algorithm: sampling
     priors:    see help('prior_summary')
     sample:    6750 (posterior sample size)
     num obs:   16
    
    Estimates:
                    mean   sd    2.5%   25%   50%   75%   97.5%
    (Intercept)    -0.2    1.0  -2.2   -0.9  -0.2   0.4   1.7  
    RIPDENS         0.0    0.0   0.0    0.0   0.0   0.0   0.0  
    sigma           1.2    0.2   0.8    1.0   1.1   1.3   1.7  
    mean_PPD        3.5    0.4   2.7    3.3   3.5   3.8   4.4  
    log-posterior -38.0    1.3 -41.4  -38.6 -37.6 -37.0 -36.4  
    
    Diagnostics:
                  mcse Rhat n_eff
    (Intercept)   0.0  1.0  6377 
    RIPDENS       0.0  1.0  6750 
    sigma         0.0  1.0  3214 
    mean_PPD      0.0  1.0  4507 
    log-posterior 0.0  1.0  2884 
    
    For each parameter, mcse is Monte Carlo standard error, n_eff is a crude measure of effective sample size, and Rhat is the potential scale reduction factor on split chains (at convergence Rhat=1).
    
    # OR
    library(broom)
    tidyMCMC(christ.rstanarm$stanfit, conf.int = TRUE, conf.method = "HPDinterval", rhat = TRUE, ess = TRUE)
    
               term     estimate   std.error      conf.low     conf.high      rhat  ess
    1   (Intercept)  -0.23221103 0.986663817  -2.152395184   1.702509933 0.9998255 6377
    2       RIPDENS   0.00301297 0.000751395   0.001602318   0.004514023 0.9998705 6750
    3         sigma   1.15162654 0.238320455   0.753087990   1.637726073 1.0000491 3214
    4      mean_PPD   3.52626377 0.422541405   2.664226108   4.341947036 1.0009874 4507
    5 log-posterior -37.96063922 1.341449138 -40.594588810 -36.301106545 1.0002068 2884
    
    mcmcpvalue(as.matrix(christ.rstanarm)[, c("RIPDENS")])
    
    [1] 0.0004444444
    
    posterior_interval(christ.rstanarm, prob = 0.95)
    
                        2.5%       97.5%
    (Intercept) -2.180082961 1.681712664
    RIPDENS      0.001534922 0.004479068
    sigma        0.791948892 1.720893581
    
    (full = loo(christ.rstanarm))
    
    Computed from 6750 by 16 log-likelihood matrix
    
             Estimate  SE
    elpd_loo    -25.5 2.0
    p_loo         2.4 0.7
    looic        51.1 4.1
    
    Pareto k diagnostic values:
                             Count  Pct 
    (-Inf, 0.5]   (good)     15    93.8%
     (0.5, 0.7]   (ok)        1     6.2%
       (0.7, 1]   (bad)       0     0.0%
       (1, Inf)   (very bad)  0     0.0%
    
    All Pareto k estimates are ok (k < 0.7)
    See help('pareto-k-diagnostic') for details.
    
    (reduced = loo(update(christ.rstanarm, formula = . ~ 1)))
    
    Gradient evaluation took 1.9e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.19 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.013155 seconds (Warm-up)
                   0.08746 seconds (Sampling)
                   0.100615 seconds (Total)
    
    
    Gradient evaluation took 8e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.08 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.01065 seconds (Warm-up)
                   0.096919 seconds (Sampling)
                   0.107569 seconds (Total)
    
    
    Gradient evaluation took 8e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.08 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.011049 seconds (Warm-up)
                   0.089792 seconds (Sampling)
                   0.100841 seconds (Total)
    
    Computed from 6750 by 16 log-likelihood matrix
    
             Estimate  SE
    elpd_loo    -31.4 1.8
    p_loo         1.4 0.3
    looic        62.7 3.5
    
    All Pareto k estimates are good (k < 0.5)
    See help('pareto-k-diagnostic') for details.
    
    par(mfrow = 1:2, mar = c(5, 3.8, 1, 0) + 0.1, las = 3)
    plot(full, label_points = TRUE)
    plot(reduced, label_points = TRUE)
    
    plot of chunk tut7.2bQ2.5d1
    compare_models(full, reduced)
    
    elpd_diff        se 
         -5.8       2.3 
    
    Show BRMS code
    library(brms)
    summary(christ.brm)
    
     Family: gaussian(identity) 
    Formula: I(CWDBASAL^(1/3)) ~ RIPDENS 
       Data: christ (Number of observations: 16) 
    Samples: 3 chains, each with iter = 5000; warmup = 500; thin = 2; 
             total post-warmup samples = 6750
        ICs: LOO = Not computed; WAIC = Not computed
     
    Population-Level Effects: 
              Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
    Intercept    -0.26      0.98    -2.19     1.71       6578    1
    RIPDENS       0.00      0.00     0.00     0.00       6750    1
    
    Family Specific Parameters: 
          Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
    sigma     1.14      0.24     0.77     1.71       3962    1
    
    Samples were drawn using sampling(NUTS). For each parameter, Eff.Sample 
    is a crude measure of effective sample size, and Rhat is the potential 
    scale reduction factor on split chains (at convergence, Rhat = 1).
    
    # OR
    library(broom)
    tidyMCMC(christ.brm$fit, conf.int = TRUE, conf.method = "HPDinterval", rhat = TRUE, ess = TRUE)
    
             term     estimate    std.error     conf.low  conf.high     rhat  ess
    1 b_Intercept -0.256918975 0.9756261920 -2.205145922 1.66121860 1.000152 6578
    2   b_RIPDENS  0.003027308 0.0007439753  0.001576751 0.00452126 1.000011 6750
    3       sigma  1.139166177 0.2404226588  0.723896152 1.61879905 1.000109 3962
    
    mcmcpvalue(as.matrix(christ.brm)[, c("b_RIPDENS")])
    
    [1] 0.0004444444
    
    posterior_interval(as.matrix(christ.brm), prob = 0.95)
    
                         2.5%        97.5%
    b_Intercept  -2.186278649  1.707350799
    b_RIPDENS     0.001527964  0.004492076
    sigma         0.773711067  1.706181809
    lp__        -12.603703660 -7.713089646
    
    (full = loo(christ.brm))
    
     LOOIC   SE
     51.08 4.22
    
    (reduced = loo(update(christ.brm, formula = . ~ 1)))
    
    SAMPLING FOR MODEL 'gaussian(identity) brms-model' NOW (CHAIN 1).
    
    Gradient evaluation took 1.7e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.17 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration: 1000 / 5000 [ 20%]  (Warmup)
    Iteration: 1500 / 5000 [ 30%]  (Warmup)
    Iteration: 2000 / 5000 [ 40%]  (Warmup)
    Iteration: 2500 / 5000 [ 50%]  (Warmup)
    Iteration: 2501 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.021586 seconds (Warm-up)
                   0.035253 seconds (Sampling)
                   0.056839 seconds (Total)
    
    
    SAMPLING FOR MODEL 'gaussian(identity) brms-model' NOW (CHAIN 2).
    
    Gradient evaluation took 3e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.03 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration: 1000 / 5000 [ 20%]  (Warmup)
    Iteration: 1500 / 5000 [ 30%]  (Warmup)
    Iteration: 2000 / 5000 [ 40%]  (Warmup)
    Iteration: 2500 / 5000 [ 50%]  (Warmup)
    Iteration: 2501 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.022546 seconds (Warm-up)
                   0.024211 seconds (Sampling)
                   0.046757 seconds (Total)
    
    
    SAMPLING FOR MODEL 'gaussian(identity) brms-model' NOW (CHAIN 3).
    
    Gradient evaluation took 6e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.06 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration: 1000 / 5000 [ 20%]  (Warmup)
    Iteration: 1500 / 5000 [ 30%]  (Warmup)
    Iteration: 2000 / 5000 [ 40%]  (Warmup)
    Iteration: 2500 / 5000 [ 50%]  (Warmup)
    Iteration: 2501 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.023441 seconds (Warm-up)
                   0.022783 seconds (Sampling)
                   0.046224 seconds (Total)
    
    
    SAMPLING FOR MODEL 'gaussian(identity) brms-model' NOW (CHAIN 1).
    
    Gradient evaluation took 7e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.07 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration: 1000 / 5000 [ 20%]  (Warmup)
    Iteration: 1500 / 5000 [ 30%]  (Warmup)
    Iteration: 2000 / 5000 [ 40%]  (Warmup)
    Iteration: 2500 / 5000 [ 50%]  (Warmup)
    Iteration: 2501 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.021962 seconds (Warm-up)
                   0.034148 seconds (Sampling)
                   0.05611 seconds (Total)
    
    
    SAMPLING FOR MODEL 'gaussian(identity) brms-model' NOW (CHAIN 2).
    
    Gradient evaluation took 3e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.03 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration: 1000 / 5000 [ 20%]  (Warmup)
    Iteration: 1500 / 5000 [ 30%]  (Warmup)
    Iteration: 2000 / 5000 [ 40%]  (Warmup)
    Iteration: 2500 / 5000 [ 50%]  (Warmup)
    Iteration: 2501 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.025875 seconds (Warm-up)
                   0.02375 seconds (Sampling)
                   0.049625 seconds (Total)
    
    
    SAMPLING FOR MODEL 'gaussian(identity) brms-model' NOW (CHAIN 3).
    
    Gradient evaluation took 4e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.04 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration: 1000 / 5000 [ 20%]  (Warmup)
    Iteration: 1500 / 5000 [ 30%]  (Warmup)
    Iteration: 2000 / 5000 [ 40%]  (Warmup)
    Iteration: 2500 / 5000 [ 50%]  (Warmup)
    Iteration: 2501 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.021365 seconds (Warm-up)
                   0.022538 seconds (Sampling)
                   0.043903 seconds (Total)
    
     LOOIC   SE
     62.64 3.53
    
    par(mfrow = 1:2, mar = c(5, 3.8, 1, 0) + 0.1, las = 3)
    plot(full, label_points = TRUE)
    plot(reduced, label_points = TRUE)
    
    plot of chunk tut7.2bQ2.5e1
  10. Generate graphical summaries
    Show MCMCpack code
    library(MCMCpack)
    christ.mcmc = christ.mcmcpack
    ## Calculate the fitted values
    library(newdata)
    newdata = new_data(christ, seq = "RIPDENS", length = 1000)
    Xmat = model.matrix(~RIPDENS, newdata)
    coefs = christ.mcmc[, 1:2]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(tidyMCMC(fit^3, conf.int = TRUE, conf.method = "HPDinterval"))
    
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_point(data = christ,
        aes(y = CWDBASAL, x = RIPDENS)) + geom_line() + geom_ribbon(aes(ymin = conf.low,
        ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_continuous(expression(Course ~
        woody ~ debris ~ basal ~ area ~ (m^{
        2
    } * km^{
        -1
    }))) + scale_x_continuous(expression(Riparian ~ density ~ (trees ~ km^{
        -1
    }))) + theme_classic()
    
    plot of chunk tut7.2bQ2.6a1
    library(MCMCpack)
    christ.mcmc = christ.mcmcpack
    ## Calculate the fitted values
    library(newdata)
    newdata = new_data(christ, seq = "RIPDENS", length = 1000)
    Xmat = model.matrix(~RIPDENS, newdata)
    coefs = christ.mcmc[, 1:2]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(t(fit^3))
    newdata = newdata %>% gather(key = Sample, value = fit, -RIPDENS, -CWDBASAL,
        -LAKE)
    newdata.sum = newdata %>% group_by(RIPDENS) %>% dplyr:::summarize(fit = median(fit))
    ## reduce the number of lines from over 6000 to 200
    newdata = newdata %>% filter(Sample < 201)
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_line(aes(y = fit,
        x = RIPDENS, group = Sample), alpha = 0.01) + geom_line(data = newdata.sum,
        aes(y = fit, x = RIPDENS), color = "blue") + geom_point(data = christ,
        aes(y = CWDBASAL, x = RIPDENS), color = "red") + scale_y_continuous(expression(Course ~
        woody ~ debris ~ basal ~ area ~ (m^{
        2
    } * km^{
        -1
    }))) + scale_x_continuous(expression(Riparian ~ density ~ (trees ~ km^{
        -1
    }))) + theme_classic()
    
    plot of chunk tut7.2bQ2.6a2
    Show JAGS code
    christ.mcmc = christ.r2jags$BUGSoutput$sims.matrix
    ## Calculate the fitted values
    library(newdata)
    newdata = new_data(christ, seq = "RIPDENS", length = 1000)
    Xmat = model.matrix(~RIPDENS, newdata)
    coefs = christ.mcmc[, c("alpha", "beta")]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(tidyMCMC(fit^3, conf.int = TRUE, conf.method = "HPDinterval"))
    
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_point(data = christ,
        aes(y = CWDBASAL, x = RIPDENS)) + geom_line() + geom_ribbon(aes(ymin = conf.low,
        ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_continuous(expression(Course ~
        woody ~ debris ~ basal ~ area ~ (m^{
        2
    } * km^{
        -1
    }))) + scale_x_continuous(expression(Riparian ~ density ~ (trees ~ km^{
        -1
    }))) + theme_classic()
    
    plot of chunk tut7.2bQ2.6b1
    christ.mcmc = christ.r2jags$BUGSoutput$sims.matrix
    ## Calculate the fitted values
    library(newdata)
    newdata = new_data(christ, seq = "RIPDENS", length = 1000)
    Xmat = model.matrix(~RIPDENS, newdata)
    coefs = christ.mcmc[, c("alpha", "beta")]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(t(fit^3))
    newdata = newdata %>% gather(key = Sample, value = fit, -RIPDENS, -CWDBASAL,
        -LAKE)
    newdata.sum = newdata %>% group_by(RIPDENS) %>% dplyr:::summarize(fit = median(fit))
    ## reduce the number of lines from over 6000 to 200
    newdata = newdata %>% filter(Sample < 201)
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_line(aes(y = fit,
        x = RIPDENS, group = Sample), alpha = 0.01) + geom_line(data = newdata.sum,
        aes(y = fit, x = RIPDENS), color = "blue") + geom_point(data = christ,
        aes(y = CWDBASAL, x = RIPDENS), color = "red") + scale_y_continuous(expression(Course ~
        woody ~ debris ~ basal ~ area ~ (m^{
        2
    } * km^{
        -1
    }))) + scale_x_continuous(expression(Riparian ~ density ~ (trees ~ km^{
        -1
    }))) + theme_classic()
    
    plot of chunk tut7.2bQ2.6b2
    Show RSTAN code
    christ.mcmc = as.matrix(christ.rstan)
    ## Calculate the fitted values
    library(newdata)
    newdata = new_data(christ, seq = "RIPDENS", length = 1000)
    Xmat = model.matrix(~RIPDENS, newdata)
    coefs = christ.mcmc[, c("beta0", "beta[1]")]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(tidyMCMC(fit^3, conf.int = TRUE, conf.method = "HPDinterval"))
    
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_point(data = christ,
        aes(y = CWDBASAL, x = RIPDENS)) + geom_line() + geom_ribbon(aes(ymin = conf.low,
        ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_continuous(expression(Course ~
        woody ~ debris ~ basal ~ area ~ (m^{
        2
    } * km^{
        -1
    }))) + scale_x_continuous(expression(Riparian ~ density ~ (trees ~ km^{
        -1
    }))) + theme_classic()
    
    plot of chunk tut7.2bQ2.6c1
    christ.mcmc = as.matrix(christ.rstan)
    ## Calculate the fitted values
    library(newdata)
    newdata = new_data(christ, seq = "RIPDENS", length = 1000)
    Xmat = model.matrix(~RIPDENS, newdata)
    coefs = christ.mcmc[, c("beta0", "beta[1]")]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(t(fit^3))
    newdata = newdata %>% gather(key = Sample, value = fit, -RIPDENS, -CWDBASAL,
        -LAKE)
    newdata.sum = newdata %>% group_by(RIPDENS) %>% dplyr:::summarize(fit = median(fit))
    ## reduce the number of lines from over 6000 to 200
    newdata = newdata %>% filter(Sample < 201)
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_line(aes(y = fit,
        x = RIPDENS, group = Sample), alpha = 0.01) + geom_line(data = newdata.sum,
        aes(y = fit, x = RIPDENS), color = "blue") + geom_point(data = christ,
        aes(y = CWDBASAL, x = RIPDENS), color = "red") + scale_y_continuous(expression(Course ~
        woody ~ debris ~ basal ~ area ~ (m^{
        2
    } * km^{
        -1
    }))) + scale_x_continuous(expression(Riparian ~ density ~ (trees ~ km^{
        -1
    }))) + theme_classic()
    
    plot of chunk tut7.2bQ2.6c2
    Show RSTANARM code
    newdata = newdata = new_data(christ, seq = "RIPDENS", length = 1000)
    fit = posterior_linpred(christ.rstanarm, newdata = newdata)
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(fit^3), conf.int = TRUE, conf.method = "HPDinterval"))
    
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_point(data = christ,
        aes(y = CWDBASAL, x = RIPDENS)) + geom_line() + geom_ribbon(aes(ymin = conf.low,
        ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_continuous(expression(Course ~
        woody ~ debris ~ basal ~ area ~ (m^{
        2
    } * km^{
        -1
    }))) + scale_x_continuous(expression(Riparian ~ density ~ (trees ~ km^{
        -1
    }))) + theme_classic()
    
    plot of chunk tut7.2bQ2.6d1
    library(rstanarm)
    christ.mcmc = as.matrix(christ.rstanarm)
    ## Calculate the fitted values
    library(newdata)
    newdata = new_data(christ, seq = "RIPDENS", length = 1000)
    Xmat = model.matrix(~RIPDENS, newdata)
    coefs = christ.mcmc[, c("(Intercept)", "RIPDENS")]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(t(fit^3))
    newdata = newdata %>% gather(key = Sample, value = fit, -RIPDENS, -CWDBASAL,
        -LAKE)
    newdata.sum = newdata %>% group_by(RIPDENS) %>% dplyr:::summarize(fit = median(fit))
    ## reduce the number of lines from over 6000 to 200
    newdata = newdata %>% filter(Sample < 201)
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_line(aes(y = fit,
        x = RIPDENS, group = Sample), alpha = 0.01) + geom_line(data = newdata.sum,
        aes(y = fit, x = RIPDENS), color = "blue") + geom_point(data = christ,
        aes(y = CWDBASAL, x = RIPDENS), color = "red") + scale_y_continuous(expression(Course ~
        woody ~ debris ~ basal ~ area ~ (m^{
        2
    } * km^{
        -1
    }))) + scale_x_continuous(expression(Riparian ~ density ~ (trees ~ km^{
        -1
    }))) + theme_classic()
    
    plot of chunk tut7.2bQ2.6d2
    Show BRMS code
    newdata = marginal_effects(christ.brm)$RIPDENS
    newdata = newdata %>% mutate_at(vars(estimate__, lower__, upper__), function(x) x^3)
    ggplot(newdata, aes(y = estimate__, x = RIPDENS)) + geom_point(data = christ,
        aes(y = CWDBASAL, x = RIPDENS)) + geom_line() + geom_ribbon(aes(ymin = lower__,
        ymax = upper__), fill = "blue", alpha = 0.3) + scale_y_continuous(expression(Course ~
        woody ~ debris ~ basal ~ area ~ (m^{
        2
    } * km^{
        -1
    }))) + scale_x_continuous(expression(Riparian ~ density ~ (trees ~ km^{
        -1
    }))) + theme_classic()
    
    plot of chunk tut7.2bQ2.6e1
    library(brms)
    christ.mcmc = as.matrix(christ.brm)
    ## Calculate the fitted values
    library(newdata)
    newdata = new_data(christ, seq = "RIPDENS", length = 1000)
    Xmat = model.matrix(~RIPDENS, newdata)
    coefs = christ.mcmc[, c("b_Intercept", "b_RIPDENS")]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(t(fit^3))
    newdata = newdata %>% gather(key = Sample, value = fit, -RIPDENS, -CWDBASAL,
        -LAKE)
    ## reduce the number of lines from over 6000 to 200
    newdata = newdata %>% filter(Sample < 201)
    newdata.sum = newdata %>% group_by(RIPDENS) %>% dplyr:::summarize(fit = median(fit))
    ggplot(newdata, aes(y = estimate, x = RIPDENS)) + geom_line(aes(y = fit,
        x = RIPDENS, group = Sample), alpha = 0.01) + geom_line(data = newdata.sum,
        aes(y = fit, x = RIPDENS), color = "blue") + geom_point(data = christ,
        aes(y = CWDBASAL, x = RIPDENS), color = "red") + scale_y_continuous(expression(Course ~
        woody ~ debris ~ basal ~ area ~ (m^{
        2
    } * km^{
        -1
    }))) + scale_x_continuous(expression(Riparian ~ density ~ (trees ~ km^{
        -1
    }))) + theme_classic()
    
    plot of chunk tut7.2bQ2.6e2
  11. Explore effect sizes. Lets base this on a reduction of riparian tree density from 1800 trees per km to 900 (ie. a 50% reduction)
    Show MCMCpack code
    library(MCMCpack)
    christ.mcmc = christ.mcmcpack
    newdata = data.frame(RIPDENS = c(1800, 900))
    Xmat = model.matrix(~RIPDENS, newdata)
    coefs = christ.mcmc[, c("(Intercept)", "RIPDENS")]
    fit = (coefs %*% t(Xmat))^3
    ## Raw effect size
    (RES = tidyMCMC(as.mcmc(fit[, 2] - fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term  estimate std.error  conf.low conf.high
    1 var1 -127.4968  42.52612 -212.4415 -47.65457
    
    ## Cohen's D
    cohenD = (fit[, 2] - fit[, 1])/sqrt(christ.mcmc[, "sigma2"])
    (cohenDES = tidyMCMC(as.mcmc(cohenD), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term  estimate std.error  conf.low conf.high
    1 var1 -120.0312  44.01978 -207.1585 -36.38872
    
    # Percentage change
    ESp = 100 * (fit[, 2] - fit[, 1])/fit[, 1]
    (PES = tidyMCMC(as.mcmc(ESp), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term  estimate std.error  conf.low conf.high
    1 var1 -87.16801  23.84596 -98.37591 -72.94357
    
    # Probability that the effect is greater than 25% (a decline of >25%)
    sum(-1 * ESp > 25)/length(ESp)
    
    [1] 0.9987
    
    ## fractional change
    fit = fit[fit[, 2] > 0, ]
    (FES = tidyMCMC(as.mcmc(fit[, 2]/fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term  estimate std.error   conf.low conf.high
    1 var1 0.1283199 0.2384596 0.01624085 0.2705643
    
    Show JAGS code
    christ.mcmc = christ.r2jags$BUGSoutput$sims.matrix
    ## Calculate the fitted values
    library(newdata)
    newdata = data.frame(RIPDENS = c(1800, 900))
    Xmat = model.matrix(~RIPDENS, newdata)
    coefs = christ.mcmc[, c("alpha", "beta")]
    fit = (coefs %*% t(Xmat))^3
    ## Raw effect size
    (RES = tidyMCMC(as.mcmc(fit[, 2] - fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term  estimate std.error  conf.low conf.high
    1 var1 -128.4078  42.24404 -213.3121 -50.28397
    
    ## Cohen's D
    cohenD = (fit[, 2] - fit[, 1])/christ.mcmc[, "sigma"]
    (cohenDES = tidyMCMC(as.mcmc(cohenD), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term  estimate std.error  conf.low conf.high
    1 var1 -121.2396  43.60707 -208.0248  -40.2417
    
    # Percentage change
    ESp = 100 * (fit[, 2] - fit[, 1])/fit[, 1]
    (PES = tidyMCMC(as.mcmc(ESp), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term  estimate std.error  conf.low conf.high
    1 var1 -87.62622  7.670893 -98.39554 -73.21562
    
    # Probability that the effect is greater than 25% (a decline of >25%)
    sum(-1 * ESp > 25)/length(ESp)
    
    [1] 0.999413
    
    ## fractional change
    fit = fit[fit[, 2] > 0, ]
    (FES = tidyMCMC(as.mcmc(fit[, 2]/fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term  estimate  std.error   conf.low conf.high
    1 var1 0.1237378 0.07670893 0.01604456 0.2678438
    
    Show RSTAN code
    christ.mcmc = as.matrix(christ.rstan)
    ## Calculate the fitted values
    library(newdata)
    newdata = data.frame(RIPDENS = c(1800, 900))
    Xmat = model.matrix(~RIPDENS, newdata)
    coefs = christ.mcmc[, c("beta0", "beta[1]")]
    fit = (coefs %*% t(Xmat))^3
    ## Raw effect size
    (RES = tidyMCMC(as.mcmc(fit[, 2] - fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error  conf.low conf.high
    1 var1 -127.901  43.49555 -212.4069 -47.67477
    
    ## Cohen's D
    cohenD = (fit[, 2] - fit[, 1])/christ.mcmc[, "sigma"]
    (cohenDES = tidyMCMC(as.mcmc(cohenD), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term  estimate std.error  conf.low conf.high
    1 var1 -115.8683  42.19086 -197.3489 -36.80674
    
    # Percentage change
    ESp = 100 * (fit[, 2] - fit[, 1])/fit[, 1]
    (PES = tidyMCMC(as.mcmc(ESp), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term  estimate std.error  conf.low conf.high
    1 var1 -87.35891  7.959909 -98.88673 -72.67531
    
    # Probability that the effect is greater than 25% (a decline of >25%)
    sum(-1 * ESp > 25)/length(ESp)
    
    [1] 0.998963
    
    ## fractional change
    fit = fit[fit[, 2] > 0, ]
    (FES = tidyMCMC(as.mcmc(fit[, 2]/fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term  estimate  std.error  conf.low conf.high
    1 var1 0.1264109 0.07959909 0.0111327 0.2732469
    
    Show RSTANARM code
    christ.mcmc = as.matrix(christ.rstanarm)
    ## Calculate the fitted values
    library(newdata)
    newdata = data.frame(RIPDENS = c(1800, 900))
    Xmat = model.matrix(~RIPDENS, newdata)
    coefs = christ.mcmc[, c("(Intercept)", "RIPDENS")]
    fit = (coefs %*% t(Xmat))^3
    ## Raw effect size
    (RES = tidyMCMC(as.mcmc(fit[, 2] - fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term  estimate std.error  conf.low conf.high
    1 var1 -127.5175  43.52311 -211.7174 -42.58836
    
    ## Cohen's D
    cohenD = (fit[, 2] - fit[, 1])/christ.mcmc[, "sigma"]
    (cohenDES = tidyMCMC(as.mcmc(cohenD), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term  estimate std.error  conf.low conf.high
    1 var1 -115.1682  43.20934 -199.9961 -33.38101
    
    # Percentage change
    ESp = 100 * (fit[, 2] - fit[, 1])/fit[, 1]
    (PES = tidyMCMC(as.mcmc(ESp), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term  estimate std.error  conf.low conf.high
    1 var1 -87.31871  8.666773 -98.73333  -73.0458
    
    # Probability that the effect is greater than 25% (a decline of >25%)
    sum(-1 * ESp > 25)/length(ESp)
    
    [1] 0.998963
    
    ## fractional change
    fit = fit[fit[, 2] > 0, ]
    (FES = tidyMCMC(as.mcmc(fit[, 2]/fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term  estimate  std.error   conf.low conf.high
    1 var1 0.1268129 0.08666773 0.01266668  0.269542
    
    Show BRMS code
    christ.mcmc = as.matrix(christ.brm)
    ## Calculate the fitted values
    library(newdata)
    newdata = data.frame(RIPDENS = c(1800, 900))
    Xmat = model.matrix(~RIPDENS, newdata)
    coefs = christ.mcmc[, c("b_Intercept", "b_RIPDENS")]
    fit = (coefs %*% t(Xmat))^3
    ## Raw effect size
    (RES = tidyMCMC(as.mcmc(fit[, 2] - fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term  estimate std.error  conf.low conf.high
    1 var1 -127.7564  43.13748 -213.7665 -46.06526
    
    ## Cohen's D
    cohenD = (fit[, 2] - fit[, 1])/christ.mcmc[, "sigma"]
    (cohenDES = tidyMCMC(as.mcmc(cohenD), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term  estimate std.error  conf.low conf.high
    1 var1 -116.5389  42.97048 -198.0587 -34.77462
    
    # Percentage change
    ESp = 100 * (fit[, 2] - fit[, 1])/fit[, 1]
    (PES = tidyMCMC(as.mcmc(ESp), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term  estimate std.error  conf.low conf.high
    1 var1 -87.56004  7.863212 -98.95192 -73.06729
    
    # Probability that the effect is greater than 25% (a decline of >25%)
    sum(-1 * ESp > 25)/length(ESp)
    
    [1] 0.9994074
    
    ## fractional change
    fit = fit[fit[, 2] > 0, ]
    (FES = tidyMCMC(as.mcmc(fit[, 2]/fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term  estimate  std.error   conf.low conf.high
    1 var1 0.1243996 0.07863212 0.01048081 0.2693271
    
  12. Finite-population standard deviations
    Show MCMCpack code
    library(MCMCpack)
    christ.mcmc = christ.mcmcpack
    newdata = christ
    Xmat = model.matrix(~RIPDENS, newdata)
    coefs = christ.mcmc[, c("(Intercept)", "RIPDENS")]
    fit = (coefs %*% t(Xmat))^3
    resid = sweep(fit, 2, christ$CWDBASAL, "-")
    sd.resid = apply(resid, 1, sd)
    sd.x = abs((fit[, 2] - fit[, 1])/(newdata$RIPDENS[2] - newdata$RIPDENS[1])) *
        sd(christ$RIPDENS)
    sd.all = cbind(sd.x, sd.resid)
    (fpsd = tidyMCMC(sd.all, conf.int = TRUE, conf.method = "HPDinterval"))
    
          term estimate std.error conf.low conf.high
    1     sd.x 44.74318  13.15610 20.33927  71.74818
    2 sd.resid 52.61889  15.60157 37.67623  82.38526
    
    # OR expressed as a percentage
    (fpsd.p = tidyMCMC(100 * sd.all/rowSums(sd.all), estimate.method = "median",
        conf.int = TRUE, conf.method = "HPDinterval"))
    
          term estimate std.error conf.low conf.high
    1     sd.x 46.76942  4.854287 36.97993  52.52833
    2 sd.resid 53.23058  4.854287 47.47167  63.02007
    
    ggplot(fpsd, aes(y = estimate, x = term)) + geom_pointrange(aes(ymin = conf.low,
        ymax = conf.high)) + geom_text(aes(label = sprintf("%.2f%%", fpsd.p$estimate),
        vjust = -1)) + scale_y_continuous("Finite population standard deviation") +
        scale_x_discrete() + coord_flip() + theme_classic()
    
    plot of chunk tut7.2bQ2.8a1
    Show JAGS code
    christ.mcmc = christ.r2jags$BUGSoutput$sims.matrix
    newdata = christ
    Xmat = model.matrix(~RIPDENS, newdata)
    coefs = christ.mcmc[, c("alpha", "beta")]
    fit = (coefs %*% t(Xmat))^3
    resid = sweep(fit, 2, christ$CWDBASAL, "-")
    sd.resid = apply(resid, 1, sd)
    sd.x = abs((fit[, 2] - fit[, 1])/(newdata$RIPDENS[2] - newdata$RIPDENS[1])) *
        sd(christ$RIPDENS)
    sd.all = cbind(sd.x, sd.resid)
    (fpsd = tidyMCMC(sd.all, conf.int = TRUE, conf.method = "HPDinterval"))
    
          term estimate std.error conf.low conf.high
    1     sd.x 44.99259  12.98809 21.03171  71.76557
    2 sd.resid 52.86000  15.79693 38.00992  83.79307
    
    # OR expressed as a percentage
    (fpsd.p = tidyMCMC(100 * sd.all/rowSums(sd.all), estimate.method = "median",
        conf.int = TRUE, conf.method = "HPDinterval"))
    
          term estimate std.error conf.low conf.high
    1     sd.x 46.69376  4.475378 37.24855  52.39210
    2 sd.resid 53.30624  4.475378 47.60790  62.75145
    
    ggplot(fpsd, aes(y = estimate, x = term)) + geom_pointrange(aes(ymin = conf.low,
        ymax = conf.high)) + geom_text(aes(label = sprintf("%.2f%%", fpsd.p$estimate),
        vjust = -1)) + scale_y_continuous("Finite population standard deviation") +
        scale_x_discrete() + coord_flip() + theme_classic()
    
    plot of chunk tut7.2bQ2.8b1
    Show RSTAN code
    christ.mcmc = as.matrix(christ.rstan)
    newdata = christ
    Xmat = model.matrix(~RIPDENS, newdata)
    coefs = christ.mcmc[, c("beta0", "beta[1]")]
    fit = (coefs %*% t(Xmat))^3
    resid = sweep(fit, 2, christ$CWDBASAL, "-")
    sd.resid = apply(resid, 1, sd)
    sd.x = abs((fit[, 2] - fit[, 1])/(newdata$RIPDENS[2] - newdata$RIPDENS[1])) *
        sd(christ$RIPDENS)
    sd.all = cbind(sd.x, sd.resid)
    (fpsd = tidyMCMC(sd.all, conf.int = TRUE, conf.method = "HPDinterval"))
    
          term estimate std.error conf.low conf.high
    1     sd.x 44.85837  13.43119 19.73555   70.9123
    2 sd.resid 52.82636  16.39363 37.84590   84.4382
    
    # OR expressed as a percentage
    (fpsd.p = tidyMCMC(100 * sd.all/rowSums(sd.all), estimate.method = "median",
        conf.int = TRUE, conf.method = "HPDinterval"))
    
          term estimate std.error conf.low conf.high
    1     sd.x 46.72086  4.700478 36.52322  52.45014
    2 sd.resid 53.27914  4.700478 47.54986  63.47678
    
    ggplot(fpsd, aes(y = estimate, x = term)) + geom_pointrange(aes(ymin = conf.low,
        ymax = conf.high)) + geom_text(aes(label = sprintf("%.2f%%", fpsd.p$estimate),
        vjust = -1)) + scale_y_continuous("Finite population standard deviation") +
        scale_x_discrete() + coord_flip() + theme_classic()
    
    plot of chunk tut7.2bQ2.8c1
    Show RSTANARM code
    christ.mcmc = as.matrix(christ.rstanarm)
    newdata = christ
    Xmat = model.matrix(~RIPDENS, newdata)
    coefs = christ.mcmc[, c("(Intercept)", "RIPDENS")]
    fit = (coefs %*% t(Xmat))^3
    resid = sweep(fit, 2, christ$CWDBASAL, "-")
    sd.resid = apply(resid, 1, sd)
    sd.x = abs((fit[, 2] - fit[, 1])/(newdata$RIPDENS[2] - newdata$RIPDENS[1])) *
        sd(christ$RIPDENS)
    sd.all = cbind(sd.x, sd.resid)
    (fpsd = tidyMCMC(sd.all, conf.int = TRUE, conf.method = "HPDinterval"))
    
          term estimate std.error conf.low conf.high
    1     sd.x 44.70379  13.48680 17.81688  71.65064
    2 sd.resid 52.85626  15.96105 37.88927  84.56797
    
    # OR expressed as a percentage
    (fpsd.p = tidyMCMC(100 * sd.all/rowSums(sd.all), estimate.method = "median",
        conf.int = TRUE, conf.method = "HPDinterval"))
    
          term estimate std.error conf.low conf.high
    1     sd.x 46.64012  4.871145 36.17485  52.36926
    2 sd.resid 53.35988  4.871145 47.63074  63.82515
    
    ggplot(fpsd, aes(y = estimate, x = term)) + geom_pointrange(aes(ymin = conf.low,
        ymax = conf.high)) + geom_text(aes(label = sprintf("%.2f%%", fpsd.p$estimate),
        vjust = -1)) + scale_y_continuous("Finite population standard deviation") +
        scale_x_discrete() + coord_flip() + theme_classic()
    
    plot of chunk tut7.2bQ2.8d1
    Show BRMS code
    christ.mcmc = as.matrix(christ.brm)
    newdata = christ
    Xmat = model.matrix(~RIPDENS, newdata)
    coefs = christ.mcmc[, c("b_Intercept", "b_RIPDENS")]
    fit = (coefs %*% t(Xmat))^3
    resid = sweep(fit, 2, christ$CWDBASAL, "-")
    sd.resid = apply(resid, 1, sd)
    sd.x = abs((fit[, 2] - fit[, 1])/(newdata$RIPDENS[2] - newdata$RIPDENS[1])) *
        sd(christ$RIPDENS)
    sd.all = cbind(sd.x, sd.resid)
    (fpsd = tidyMCMC(sd.all, conf.int = TRUE, conf.method = "HPDinterval"))
    
          term estimate std.error conf.low conf.high
    1     sd.x  44.7194  13.31368 18.65857  70.60969
    2 sd.resid  52.8973  16.02284 37.75326  84.87694
    
    # OR expressed as a percentage
    (fpsd.p = tidyMCMC(100 * sd.all/rowSums(sd.all), estimate.method = "median",
        conf.int = TRUE, conf.method = "HPDinterval"))
    
          term estimate std.error conf.low conf.high
    1     sd.x 46.53784  4.664826 36.44587  52.75618
    2 sd.resid 53.46216  4.664826 47.24382  63.55413
    
    ggplot(fpsd, aes(y = estimate, x = term)) + geom_pointrange(aes(ymin = conf.low,
        ymax = conf.high)) + geom_text(aes(label = sprintf("%.2f%%", fpsd.p$estimate),
        vjust = -1)) + scale_y_continuous("Finite population standard deviation") +
        scale_x_discrete() + coord_flip() + theme_classic()
    
    plot of chunk tut7.2bQ2.8e1
  13. $R^2$
    Show MCMCpack code
    library(MCMCpack)
    christ.mcmc = christ.mcmcpack
    newdata = christ
    Xmat = model.matrix(~RIPDENS, newdata)
    coefs = christ.mcmc[, c("(Intercept)", "RIPDENS")]
    fit = (coefs %*% t(Xmat))
    x = christ$CWDBASAL^(1/3)
    resid = sweep(fit, 2, x, "-")
    var_f = apply(fit, 1, var)
    var_e = apply(resid, 1, var)
    R2 = var_f/(var_f + var_e)
    tidyMCMC(as.mcmc(R2), conf.int = TRUE, conf.method = "HPDinterval")
    
      term  estimate std.error  conf.low conf.high
    1 var1 0.5568242 0.1266604 0.3009179  0.709935
    
    # for comparison
    summary(lm(I(CWDBASAL^(1/3)) ~ RIPDENS, data = christ))
    
    Call:
    lm(formula = I(CWDBASAL^(1/3)) ~ RIPDENS, data = christ)
    
    Residuals:
        Min      1Q  Median      3Q     Max 
    -1.4269 -0.7813 -0.1634  0.6242  1.8866 
    
    Coefficients:
                  Estimate Std. Error t value Pr(>|t|)    
    (Intercept) -0.2420810  0.8770701  -0.276 0.786572    
    RIPDENS      0.0030227  0.0006715   4.502 0.000498 ***
    ---
    Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    
    Residual standard error: 1.041 on 14 degrees of freedom
    Multiple R-squared:  0.5914,	Adjusted R-squared:  0.5622 
    F-statistic: 20.27 on 1 and 14 DF,  p-value: 0.0004976
    
    Show JAGS code
    christ.mcmc = christ.r2jags$BUGSoutput$sims.matrix
    newdata = christ
    Xmat = model.matrix(~RIPDENS, newdata)
    coefs = christ.mcmc[, c("alpha", "beta")]
    fit = (coefs %*% t(Xmat))
    x = christ$CWDBASAL^(1/3)
    resid = sweep(fit, 2, x, "-")
    var_f = apply(fit, 1, var)
    var_e = apply(resid, 1, var)
    R2 = var_f/(var_f + var_e)
    tidyMCMC(as.mcmc(R2), conf.int = TRUE, conf.method = "HPDinterval")
    
      term  estimate std.error  conf.low conf.high
    1 var1 0.5599356 0.1236288 0.3045365 0.7099365
    
    Show RSTAN code
    christ.mcmc = as.matrix(christ.rstan)
    newdata = christ
    Xmat = model.matrix(~RIPDENS, newdata)
    coefs = christ.mcmc[, c("beta0", "beta[1]")]
    fit = (coefs %*% t(Xmat))
    x = christ$CWDBASAL^(1/3)
    resid = sweep(fit, 2, x, "-")
    var_f = apply(fit, 1, var)
    var_e = apply(resid, 1, var)
    R2 = var_f/(var_f + var_e)
    tidyMCMC(as.mcmc(R2), conf.int = TRUE, conf.method = "HPDinterval")
    
      term  estimate std.error  conf.low conf.high
    1 var1 0.5558864 0.1264171 0.2944248 0.7099365
    
    Show RSTANARM code
    christ.mcmc = as.matrix(christ.rstanarm)
    newdata = christ
    Xmat = model.matrix(~RIPDENS, newdata)
    coefs = christ.mcmc[, c("(Intercept)", "RIPDENS")]
    fit = (coefs %*% t(Xmat))
    x = christ$CWDBASAL^(1/3)
    resid = sweep(fit, 2, x, "-")
    var_f = apply(fit, 1, var)
    var_e = apply(resid, 1, var)
    R2 = var_f/(var_f + var_e)
    tidyMCMC(as.mcmc(R2), conf.int = TRUE, conf.method = "HPDinterval")
    
      term  estimate std.error  conf.low conf.high
    1 var1 0.5553571 0.1285036 0.2933517 0.7099365
    
    Show BRMS code
    christ.mcmc = as.matrix(christ.brm)
    newdata = christ
    Xmat = model.matrix(~RIPDENS, newdata)
    coefs = christ.mcmc[, c("b_Intercept", "b_RIPDENS")]
    fit = (coefs %*% t(Xmat))
    x = christ$CWDBASAL^(1/3)
    resid = sweep(fit, 2, x, "-")
    var_f = apply(fit, 1, var)
    var_e = apply(resid, 1, var)
    R2 = var_f/(var_f + var_e)
    tidyMCMC(as.mcmc(R2), conf.int = TRUE, conf.method = "HPDinterval")
    
      term  estimate std.error  conf.low conf.high
    1 var1 0.5579719 0.1268644 0.2976436 0.7099361
    

Simple linear regression

Here is a modified example from Quinn and Keough (2002). Peake & Quinn (1993) investigated the relationship between the number of individuals of invertebrates living in amongst clumps of mussels on a rocky intertidal shore and the area of those mussel clumps.

Download PeakeQuinn data set
Format of peakquinn.csv data files
AREAINDIV
516.0018
469.0660
462.2557
938.60100
1357.1548
......

AREAArea of mussel clump mm2 - Predictor variable
INDIVNumber of individuals found within clump - Response variable
clump of mussels

Open the peakquinn data file.
Show code
peakquinn <- read.table("../downloads/data/peakquinn.csv", header = T, sep = ",", strip.white = T)
peakquinn
       AREA INDIV
1    516.00    18
2    469.06    60
3    462.25    57
4    938.60   100
5   1357.15    48
6   1773.66   118
7   1686.01   148
8   1786.29   214
9   3090.07   225
10  3980.12   283
11  4424.84   380
12  4451.68   278
13  4982.89   338
14  4450.86   274
15  5490.74   569
16  7476.21   509
17  7138.82   682
18  9149.94   600
19 10133.07   978
20  9287.69   363
21 13729.13  1402
22 20300.77   675
23 24712.72  1159
24 27144.03  1062
25 26117.81   632

The relationship between two continuous variables can be analyzed by simple linear regression. As with question 2, note that the levels of the predictor variable were measured, not fixed, and thus parameter estimates should be based on model II RMA regression. Note however, that the hypothesis test for slope is uneffected by whether the predictor variable is fixed or measured.

Before performing the analysis we need to check the assumptions. To evaluate the assumptions of linearity, normality and homogeneity of variance, construct a scatterplot

of INDIV against AREA (INDIV on y-axis, AREA on x-axis) including a lowess smoother and boxplots on the axes.

Show code
ggplot(peakquinn, aes(y = INDIV, x = AREA)) + geom_point() + geom_smooth()
plot of chunk tut7.2bQ3.1a
ggplot(peakquinn, aes(y = INDIV, x = 1)) + geom_boxplot()
plot of chunk tut7.2bQ3.1a
ggplot(peakquinn, aes(y = AREA, x = 1)) + geom_boxplot()
plot of chunk tut7.2bQ3.1a
  1. Consider the assumptions and suitability of the data for simple linear regression:
    1. In this case, the researchers are interested in investigating whether there is a relationship between the number of invertebrate individuals and mussel clump area as well as generating a predictive model. However, they are not interested in the specific magnitude of the relationship (slope) and have no intension of comparing their slope to any other non-zero values. Is model I or II regression
      appropriate in these circumstances?. Explain?
    2. Is there any evidence that the other assumptions are likely to be violated?
  2. There is clear evidence of non-normality and non-linearity. As with the previous example, the most appropriate approach would be to use a more suitable distribution. Nevertheless, we will reserve such an approach to a later tutorial and instead attempt to satisfy the assumptions via scale transformations for now. Lets try a log-log transformation of the response and predictor. Mimic this by log transforming the axes during exploratory data analysis.
    Show code
    ggplot(peakquinn, aes(y = INDIV, x = AREA)) + geom_point() + geom_smooth() + scale_y_log10() + scale_x_log10()
    
    plot of chunk tut7.2bQ3.2a
    ggplot(peakquinn, aes(y = INDIV, x = 1)) + geom_boxplot() + scale_y_log10()
    
    plot of chunk tut7.2bQ3.2a
    ggplot(peakquinn, aes(y = AREA, x = 1)) + geom_boxplot() + scale_y_log10()
    
    plot of chunk tut7.2bQ3.2a
  3. Once you are satisfied with the transformations, fit the appropriate Bayesian model.
    Show MCMCpack code
    library(MCMCpack)
    peakquinn.mcmcpack = MCMCregress(log10(INDIV) ~ log10(AREA), data = peakquinn)
    
    Show JAGS code
            modelString=" 
    	model {
    	#Likelihood
    	for (i in 1:n) {
    	y[i]~dnorm(mu[i],tau)
    	mu[i] <- alpha+beta*x[i]
    	}
    	
    	#Priors
    	alpha ~ dnorm (0.01,1.0E-6)
    	beta ~ dnorm(0,1.0E-6)
    	tau <- 1 / (sigma * sigma)
    	sigma~dgamma(0.001,0.001)
    	}
    	"
    
            peakquinn.list <- with(peakquinn,
            list(x=log10(AREA),
            y=log10(INDIV),n=nrow(peakquinn))
            )
    
            params <- c("alpha","beta","sigma")
            burnInSteps = 2000
            nChains = 3
            numSavedSteps = 50000
            thinSteps = 10
            nIter = ceiling((numSavedSteps * thinSteps)/nChains)
    
            peakquinn.r2jags <- jags(data=peakquinn.list,
            inits=NULL, #or inits=list(inits,inits,inits) # since there are three chains
            parameters.to.save=params,
            model.file=textConnection(modelString), #"../downloads/BUGSscripts/tut7.2bQ1_JAGS.txt",
            n.chains=nChains,
            n.iter=nIter,
            n.burnin=burnInSteps,
            n.thin=thinSteps
            )
    
    Compiling model graph
       Resolving undeclared variables
       Allocating nodes
    Graph information:
       Observed stochastic nodes: 25
       Unobserved stochastic nodes: 3
       Total graph size: 113
    
    Initializing model
    
    Show RSTAN code
    modelString = " 
    data { 
    int<lower=1> n;   // total number of observations 
    vector[n] Y;      // response variable 
    int<lower=1> nX;  // number of effects 
    matrix[n, nX] X;   // model matrix 
    } 
    ransformed data { 
    matrix[n, nX - 1] Xc;  // centered version of X 
    vector[nX - 1] means_X;  // column means of X before centering 
    
    for (i in 2:nX) { 
    means_X[i - 1] = mean(X[, i]); 
    Xc[, i - 1] = X[, i] - means_X[i - 1]; 
    }  
    } 
    parameters { 
    vector[nX-1] beta;  // population-level effects 
    real cbeta0;  // center-scale intercept 
    real<lower=0> sigma;  // residual SD 
    } 
    ransformed parameters { 
    } 
    model { 
    vector[n] mu; 
    mu = Xc * beta + cbeta0; 
    // prior specifications 
    beta ~ normal(0, 100); 
    cbeta0 ~ normal(0, 100); 
    sigma ~ cauchy(0, 5); 
    // likelihood contribution 
    Y ~ normal(mu, sigma); 
    } 
    generated quantities { 
    real beta0;  // population-level intercept 
    beta0 = cbeta0 - dot_product(means_X, beta); 
    }
    "
    
    Xmat <- model.matrix(~log10(AREA), data = peakquinn)
    peakquinn.list <- with(peakquinn, list(Y = log10(INDIV), X = Xmat, nX = ncol(Xmat), n = nrow(peakquinn)))
    
    library(rstan)
    peakquinn.rstan <- stan(data = peakquinn.list, model_code = modelString, chains = 3, iter = 5000, warmup = 500,
        thin = 2)
    
    SAMPLING FOR MODEL 'c89e04c2495a0b6eb4be2b406df0876b' NOW (CHAIN 1).
    
    Gradient evaluation took 1.6e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.16 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration:  501 / 5000 [ 10%]  (Sampling)
    Iteration: 1000 / 5000 [ 20%]  (Sampling)
    Iteration: 1500 / 5000 [ 30%]  (Sampling)
    Iteration: 2000 / 5000 [ 40%]  (Sampling)
    Iteration: 2500 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.010294 seconds (Warm-up)
                   0.081637 seconds (Sampling)
                   0.091931 seconds (Total)
    
    
    SAMPLING FOR MODEL 'c89e04c2495a0b6eb4be2b406df0876b' NOW (CHAIN 2).
    
    Gradient evaluation took 7e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.07 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration:  501 / 5000 [ 10%]  (Sampling)
    Iteration: 1000 / 5000 [ 20%]  (Sampling)
    Iteration: 1500 / 5000 [ 30%]  (Sampling)
    Iteration: 2000 / 5000 [ 40%]  (Sampling)
    Iteration: 2500 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.011199 seconds (Warm-up)
                   0.100166 seconds (Sampling)
                   0.111365 seconds (Total)
    
    
    SAMPLING FOR MODEL 'c89e04c2495a0b6eb4be2b406df0876b' NOW (CHAIN 3).
    
    Gradient evaluation took 7e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.07 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration:  501 / 5000 [ 10%]  (Sampling)
    Iteration: 1000 / 5000 [ 20%]  (Sampling)
    Iteration: 1500 / 5000 [ 30%]  (Sampling)
    Iteration: 2000 / 5000 [ 40%]  (Sampling)
    Iteration: 2500 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.010724 seconds (Warm-up)
                   0.079799 seconds (Sampling)
                   0.090523 seconds (Total)
    
    Show RSTANARM code
    peakquinn.rstanarm = stan_glm(log10(INDIV) ~ log10(AREA), data = peakquinn, iter = 5000, warmup = 500,
        chains = 3, thin = 2, refresh = 0, prior_intercept = normal(0, 100), prior = normal(0, 100), prior_aux = cauchy(0,
            5))
    
    Gradient evaluation took 2.7e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.27 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.111367 seconds (Warm-up)
                   0.358927 seconds (Sampling)
                   0.470294 seconds (Total)
    
    
    Gradient evaluation took 1.6e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.16 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.129212 seconds (Warm-up)
                   0.390084 seconds (Sampling)
                   0.519296 seconds (Total)
    
    
    Gradient evaluation took 1.1e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.11 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.145679 seconds (Warm-up)
                   0.363303 seconds (Sampling)
                   0.508982 seconds (Total)
    
    Show BRMS code
    peakquinn.brm = brm(log10(INDIV) ~ log10(AREA), data = peakquinn, iter = 5000, warmup = 500, chains = 3,
        thin = 2, refresh = 0, prior = c(prior(normal(0, 100), class = "Intercept"), prior(normal(0, 100),
            class = "b"), prior(cauchy(0, 5), class = "sigma")))
    
    Gradient evaluation took 1.7e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.17 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.0128 seconds (Warm-up)
                   0.087363 seconds (Sampling)
                   0.100163 seconds (Total)
    
    
    Gradient evaluation took 7e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.07 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.011621 seconds (Warm-up)
                   0.099485 seconds (Sampling)
                   0.111106 seconds (Total)
    
    
    Gradient evaluation took 7e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.07 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.010653 seconds (Warm-up)
                   0.100251 seconds (Sampling)
                   0.110904 seconds (Total)
    
  4. Explore MCMC diagnostics
    Show MCMCpack code
    library(MCMCpack)
    plot(peakquinn.mcmcpack)
    
    plot of chunk tut7.2bQ3.4a
    raftery.diag(peakquinn.mcmcpack)
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
                                                       
                 Burn-in  Total Lower bound  Dependence
                 (M)      (N)   (Nmin)       factor (I)
     (Intercept) 2        3741  3746         0.999     
     log10(AREA) 2        3962  3746         1.060     
     sigma2      2        3710  3746         0.990     
    
    autocorr.diag(peakquinn.mcmcpack)
    
             (Intercept)   log10(AREA)       sigma2
    Lag 0   1.0000000000  1.000000e+00  1.000000000
    Lag 1   0.0116532661  9.334020e-03  0.095839414
    Lag 5   0.0012783772  3.663530e-03 -0.008301125
    Lag 10  0.0003423311  9.355755e-05  0.019264269
    Lag 50 -0.0062782335 -6.907045e-03  0.001771369
    
    Show JAGS code
    library(R2jags)
    library(coda)
    peakquinn.mcmc = as.mcmc(peakquinn.r2jags)
    plot(peakquinn.mcmc)
    
    plot of chunk tut7.2bQ3.4b
    raftery.diag(peakquinn.mcmc)
    
    [[1]]
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
                                                    
              Burn-in  Total Lower bound  Dependence
              (M)      (N)   (Nmin)       factor (I)
     alpha    20       37830 3746         10.10     
     beta     10       37440 3746          9.99     
     deviance 10       37440 3746          9.99     
     sigma    10       37440 3746          9.99     
    
    
    [[2]]
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
                                                    
              Burn-in  Total Lower bound  Dependence
              (M)      (N)   (Nmin)       factor (I)
     alpha    20       36900 3746          9.85     
     beta     10       37440 3746          9.99     
     deviance 20       37830 3746         10.10     
     sigma    20       37830 3746         10.10     
    
    
    [[3]]
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
                                                    
              Burn-in  Total Lower bound  Dependence
              (M)      (N)   (Nmin)       factor (I)
     alpha    20       38780 3746         10.40     
     beta     20       36530 3746          9.75     
     deviance 20       38400 3746         10.30     
     sigma    20       36900 3746          9.85     
    
    autocorr.diag(peakquinn.mcmc)
    
                    alpha          beta     deviance        sigma
    Lag 0    1.0000000000  1.0000000000  1.000000000  1.000000000
    Lag 10   0.0001195037 -0.0003816953 -0.001896208  0.005446906
    Lag 50   0.0053945316  0.0055864308 -0.007529212 -0.006124288
    Lag 100 -0.0033999014 -0.0038914471  0.003445373  0.001132613
    Lag 500 -0.0016218704 -0.0022681430  0.003983872  0.003848320
    
    Show RSTAN code
    library(rstan)
    library(coda)
    s = as.array(peakquinn.rstan)
    peakquinn.mcmc <- do.call(mcmc.list, plyr:::alply(s[, , -(length(s[1, 1, ]))], 2, as.mcmc))
    plot(peakquinn.mcmc)
    
    plot of chunk tut7.2bQ3.4c
    raftery.diag(peakquinn.mcmc)
    
    $`1`
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
    
    You need a sample size of at least 3746 with these values of q, r and s
    
    $`2`
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
    
    You need a sample size of at least 3746 with these values of q, r and s
    
    $`3`
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
    
    You need a sample size of at least 3746 with these values of q, r and s
    
    autocorr.diag(peakquinn.mcmc)
    
                beta[1]        cbeta0        sigma        beta0
    Lag 0   1.000000000  1.0000000000  1.000000000  1.000000000
    Lag 1   0.003570983  0.0306426694  0.057421665  0.007040986
    Lag 5  -0.011594291 -0.0049307070 -0.004491589 -0.015518655
    Lag 10  0.003007244 -0.0305839541 -0.021560119  0.002349694
    Lag 50 -0.032332439  0.0002296363  0.015170809 -0.032066086
    
    library(rstan)
    library(coda)
    stan_ac(peakquinn.rstan)
    
    plot of chunk tut7.2bQ3.4c1
    stan_rhat(peakquinn.rstan)
    
    plot of chunk tut7.2bQ3.4c1
    stan_ess(peakquinn.rstan)
    
    plot of chunk tut7.2bQ3.4c1
    # using Bayeseplot
    library(bayesplot)
    detach("package:reshape")
    mcmc_trace(as.array(peakquinn.rstan))
    
    plot of chunk tut7.2bQ3.4c2
    mcmc_trace(as.array(peakquinn.rstan), regex_pars = "beta|sigma")
    
    plot of chunk tut7.2bQ3.4c2
    mcmc_dens(as.array(peakquinn.rstan))
    
    plot of chunk tut7.2bQ3.4c2
    detach("package:reshape")
    library(bayesplot)
    mcmc_combo(as.array(peakquinn.rstan))
    
    plot of chunk tut7.2bQ3.4c3
    Show RSTANARM code
    library(rstan)
    library(coda)
    s = as.array(peakquinn.rstanarm)
    peakquinn.mcmc <- do.call(mcmc.list, plyr:::alply(s[, , -(length(s[1, 1, ]))], 2, as.mcmc))
    plot(peakquinn.mcmc)
    
    plot of chunk tut7.2bQ3.4d
    raftery.diag(peakquinn.mcmc)
    
    $`1`
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
    
    You need a sample size of at least 3746 with these values of q, r and s
    
    $`2`
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
    
    You need a sample size of at least 3746 with these values of q, r and s
    
    $`3`
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
    
    You need a sample size of at least 3746 with these values of q, r and s
    
    autocorr.diag(peakquinn.mcmc)
    
            (Intercept)  log10(AREA)
    Lag 0   1.000000000  1.000000000
    Lag 1   0.028679084  0.022344878
    Lag 5  -0.004308483 -0.007113919
    Lag 10  0.009629726  0.010009127
    Lag 50 -0.013881750 -0.015410078
    
    library(rstan)
    library(coda)
    stan_ac(peakquinn.rstanarm)
    
    plot of chunk tut7.2bQ3.4d1
    stan_rhat(peakquinn.rstanarm)
    
    plot of chunk tut7.2bQ3.4d1
    stan_ess(peakquinn.rstanarm)
    
    plot of chunk tut7.2bQ3.4d1
    # using Bayeseplot
    library(bayesplot)
    detach("package:reshape")
    mcmc_trace(as.array(peakquinn.rstanarm))
    
    plot of chunk tut7.2bQ3.4d2
    mcmc_trace(as.array(peakquinn.rstanarm), regex_pars = "Intercept|x|sigma")
    
    plot of chunk tut7.2bQ3.4d2
    mcmc_dens(as.array(peakquinn.rstan))
    
    plot of chunk tut7.2bQ3.4d2
    detach("package:reshape")
    library(bayesplot)
    mcmc_combo(as.array(peakquinn.rstanarm))
    
    plot of chunk tut7.2bQ3.4d3
    library(rstanarm)
    posterior_vs_prior(peakquinn.rstanarm, color_by = "vs", group_by = TRUE, facet_args = list(scales = "free_y"))
    
    Gradient evaluation took 3.1e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.31 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.036027 seconds (Warm-up)
                   0.04039 seconds (Sampling)
                   0.076417 seconds (Total)
    
    
    Gradient evaluation took 1e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.1 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.050907 seconds (Warm-up)
                   0.042161 seconds (Sampling)
                   0.093068 seconds (Total)
    
    plot of chunk tut7.2bQ3.4d4
    Show BRMS code
    library(coda)
    library(brms)
    peakquinn.mcmc = as.mcmc(peakquinn.brm)
    plot(peakquinn.mcmc)
    
    plot of chunk tut7.2bQ3.4e
    raftery.diag(peakquinn.mcmc)
    
    [[1]]
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
    
    You need a sample size of at least 3746 with these values of q, r and s
    
    [[2]]
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
    
    You need a sample size of at least 3746 with these values of q, r and s
    
    [[3]]
    
    Quantile (q) = 0.025
    Accuracy (r) = +/- 0.005
    Probability (s) = 0.95 
    
    You need a sample size of at least 3746 with these values of q, r and s
    
    autocorr.diag(peakquinn.mcmc)
    
    Error in ts(x, start = start(x), end = end(x), deltat = thin(x)): invalid time series parameters specified
    
    library(coda)
    stan_ac(peakquinn.brm$fit)
    
    plot of chunk tut7.2bQ3.4e1
    stan_rhat(peakquinn.brm$fit)
    
    plot of chunk tut7.2bQ3.4e1
    stan_ess(peakquinn.brm$fit)
    
    plot of chunk tut7.2bQ3.4e1
  5. Perform model validation
    Show MCMCpack code
    library(MCMCpack)
    peakquinn.mcmc = as.data.frame(peakquinn.mcmcpack)
    # generate a model matrix
    newdata = data.frame(AREA = peakquinn$AREA)
    Xmat = model.matrix(~log10(AREA), newdata)
    ## get median parameter estimates
    coefs = apply(peakquinn.mcmc[, 1:2], 2, median)
    fit = as.vector(coefs %*% t(Xmat))
    resid = log10(peakquinn$INDIV) - fit
    ggplot() + geom_point(data = NULL, aes(y = resid, x = fit))
    
    plot of chunk tut7.2bQ3.5a1
    library(MCMCpack)
    peakquinn.mcmc = as.data.frame(peakquinn.mcmcpack)
    # generate a model matrix
    newdata = data.frame(AREA = peakquinn$AREA)
    Xmat = model.matrix(~log10(AREA), newdata)
    ## get median parameter estimates
    coefs = apply(peakquinn.mcmc[, 1:2], 2, median)
    fit = as.vector(coefs %*% t(Xmat))
    resid = log10(peakquinn$INDIV) - fit
    ggplot() + geom_point(data = NULL, aes(y = resid, x = peakquinn$AREA)) + scale_x_log10()
    
    plot of chunk tut7.2bQ3.5a2
    library(MCMCpack)
    peakquinn.mcmc = as.data.frame(peakquinn.mcmcpack)
    # generate a model matrix
    newdata = data.frame(AREA = peakquinn$AREA)
    Xmat = model.matrix(~log10(AREA), newdata)
    ## get median parameter estimates
    coefs = apply(peakquinn.mcmc[, 1:2], 2, median)
    fit = as.vector(coefs %*% t(Xmat))
    resid = log10(peakquinn$INDIV) - fit
    sresid = resid/sd(resid)
    ggplot() + geom_point(data = NULL, aes(y = sresid, x = fit))
    
    plot of chunk tut7.2bQ3.5a3
    library(MCMCpack)
    peakquinn.mcmc = as.matrix(peakquinn.mcmcpack)
    # generate a model matrix
    Xmat = model.matrix(~log10(AREA), peakquinn)
    ## get median parameter estimates
    coefs = peakquinn.mcmc[, 1:2]
    fit = coefs %*% t(Xmat)
    ## draw samples from this model
    yRep = sapply(1:nrow(peakquinn.mcmc), function(i) rnorm(nrow(peakquinn), fit[i, ], sqrt(peakquinn.mcmc[i,
        "sigma2"])))
    ggplot() + geom_density(data = NULL, aes(x = as.vector(10^yRep), fill = "Model"), alpha = 0.5) + geom_density(data = peakquinn,
        aes(x = INDIV, fill = "Obs"), alpha = 0.5) + scale_x_log10()
    
    plot of chunk tut7.2bQ3.5a4
    ## Plot predicted effects
    library(MCMCpack)
    peakquinn.mcmc = as.matrix(peakquinn.mcmcpack)
    # generate a model matrix
    newdata = with(peakquinn, data.frame(AREA = seq(min(AREA, na.rm = TRUE), max(AREA, na.rm = TRUE), len = 100)))
    Xmat = model.matrix(~log10(AREA), data = newdata)
    ## get median parameter estimates
    coefs = peakquinn.mcmc[, 1:2]
    fit = coefs %*% t(Xmat)
    fit = apply(fit, 2, function(x) rnorm(length(x), x, sqrt(peakquinn.mcmc[, "sigma2"])))
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(10^fit), conf.int = TRUE, conf.method = "HPDinterval"))
    ggplot(newdata, aes(y = estimate, x = AREA)) + geom_ribbon(aes(ymin = conf.low, ymax = conf.high), fill = "blue",
        alpha = 0.3) + geom_line() + geom_point(data = peakquinn, aes(y = INDIV)) + scale_x_log10()
    
    plot of chunk tut7.2bQ3.5a5
    ## Plot effects
    library(MCMCpack)
    peakquinn.mcmc = as.matrix(peakquinn.mcmcpack)
    # generate a model matrix
    newdata = with(peakquinn, data.frame(AREA = seq(min(AREA, na.rm = TRUE), max(AREA, na.rm = TRUE), len = 100)))
    Xmat = model.matrix(~log10(AREA), data = newdata)
    ## get median parameter estimates
    coefs = peakquinn.mcmc[, 1:2]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(10^fit), conf.int = TRUE, conf.method = "HPDinterval"))
    ggplot(newdata, aes(y = estimate, x = AREA)) + geom_ribbon(aes(ymin = conf.low, ymax = conf.high), fill = "blue",
        alpha = 0.3) + geom_line() + geom_point(data = peakquinn, aes(y = INDIV)) + scale_x_log10()
    
    plot of chunk tut7.2bQ3.5a6
    Show JAGS code
    library(R2jags)
    peakquinn.mcmc = peakquinn.r2jags$BUGSoutput$sims.matrix[, c("alpha", "beta")]
    # generate a model matrix
    newdata = data.frame(AREA = peakquinn$AREA)
    Xmat = model.matrix(~log10(AREA), newdata)
    ## get median parameter estimates
    coefs = apply(peakquinn.mcmc[, 1:2], 2, median)
    fit = as.vector(coefs %*% t(Xmat))
    resid = log10(peakquinn$INDIV) - fit
    ggplot() + geom_point(data = NULL, aes(y = resid, x = fit))
    
    plot of chunk tut7.2bQ3.5b1
    library(R2jags)
    peakquinn.mcmc = peakquinn.r2jags$BUGSoutput$sims.matrix[, c("alpha", "beta")]
    # generate a model matrix
    newdata = data.frame(AREA = peakquinn$AREA)
    Xmat = model.matrix(~log10(AREA), newdata)
    ## get median parameter estimates
    coefs = apply(peakquinn.mcmc[, 1:2], 2, median)
    fit = as.vector(coefs %*% t(Xmat))
    resid = log10(peakquinn$INDIV) - fit
    ggplot() + geom_point(data = NULL, aes(y = resid, x = peakquinn$AREA)) + scale_x_log10()
    
    plot of chunk tut7.2bQ3.5b2
    library(R2jags)
    peakquinn.mcmc = peakquinn.r2jags$BUGSoutput$sims.matrix[, c("alpha", "beta")]
    # generate a model matrix
    newdata = data.frame(AREA = peakquinn$AREA)
    Xmat = model.matrix(~log10(AREA), newdata)
    ## get median parameter estimates
    coefs = apply(peakquinn.mcmc[, 1:2], 2, median)
    fit = as.vector(coefs %*% t(Xmat))
    resid = log10(peakquinn$INDIV) - fit
    sresid = resid/sd(resid)
    ggplot() + geom_point(data = NULL, aes(y = sresid, x = fit))
    
    plot of chunk tut7.2bQ3.5b3
    library(R2jags)
    peakquinn.mcmc = peakquinn.r2jags$BUGSoutput$sims.matrix[, c("alpha", "beta", "sigma")]
    # generate a model matrix
    Xmat = model.matrix(~log10(AREA), peakquinn)
    ## get median parameter estimates
    coefs = peakquinn.mcmc[, 1:2]
    fit = coefs %*% t(Xmat)
    ## draw samples from this model
    yRep = sapply(1:nrow(peakquinn.mcmc), function(i) rnorm(nrow(peakquinn), fit[i, ], peakquinn.mcmc[i,
        "sigma"]))
    ggplot() + geom_density(data = NULL, aes(x = as.vector(10^yRep), fill = "Model"), alpha = 0.5) + geom_density(data = peakquinn,
        aes(x = INDIV, fill = "Obs"), alpha = 0.5) + scale_x_log10()
    
    plot of chunk tut7.2bQ3.5b4
    ## Plot predicted effects
    library(R2jags)
    peakquinn.mcmc = peakquinn.r2jags$BUGSoutput$sims.matrix[, c("alpha", "beta")]
    # generate a model matrix
    newdata = with(peakquinn, data.frame(AREA = seq(min(AREA, na.rm = TRUE), max(AREA, na.rm = TRUE), len = 100)))
    Xmat = model.matrix(~log10(AREA), data = newdata)
    ## get median parameter estimates
    coefs = peakquinn.mcmc[, 1:2]
    fit = coefs %*% t(Xmat)
    fit = apply(fit, 2, function(x) rnorm(length(x), x, peakquinn.mcmc[, "sigma2"]))
    
    Error in peakquinn.mcmc[, "sigma2"]: subscript out of bounds
    
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(10^fit), conf.int = TRUE, conf.method = "HPDinterval"))
    ggplot(newdata, aes(y = estimate, x = AREA)) + geom_ribbon(aes(ymin = conf.low, ymax = conf.high), fill = "blue",
        alpha = 0.3) + geom_line() + geom_point(data = peakquinn, aes(y = INDIV)) + scale_x_log10()
    
    plot of chunk tut7.2bQ3.5b5
    ## Plot effects
    library(R2jags)
    peakquinn.mcmc = peakquinn.r2jags$BUGSoutput$sims.matrix[, c("alpha", "beta")]
    # generate a model matrix
    newdata = with(peakquinn, data.frame(AREA = seq(min(AREA, na.rm = TRUE), max(AREA, na.rm = TRUE), len = 100)))
    Xmat = model.matrix(~log10(AREA), data = newdata)
    ## get median parameter estimates
    coefs = peakquinn.mcmc[, 1:2]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(10^fit), conf.int = TRUE, conf.method = "HPDinterval"))
    ggplot(newdata, aes(y = estimate, x = AREA)) + geom_ribbon(aes(ymin = conf.low, ymax = conf.high), fill = "blue",
        alpha = 0.3) + geom_line() + geom_point(data = peakquinn, aes(y = INDIV)) + scale_x_log10()
    
    plot of chunk tut7.2bQ3.5b6
    Show RSTAN code
    library(rstan)
    peakquinn.mcmc = as.matrix(peakquinn.rstan)[, c("beta0", "beta[1]")]
    # generate a model matrix
    newdata = data.frame(AREA = peakquinn$AREA)
    Xmat = model.matrix(~log10(AREA), newdata)
    ## get median parameter estimates
    coefs = apply(peakquinn.mcmc[, 1:2], 2, median)
    fit = as.vector(coefs %*% t(Xmat))
    resid = log10(peakquinn$INDIV) - fit
    ggplot() + geom_point(data = NULL, aes(y = resid, x = fit))
    
    plot of chunk tut7.2bQ3.5c1
    library(rstan)
    peakquinn.mcmc = as.matrix(peakquinn.rstan)[, c("beta0", "beta[1]")]
    # generate a model matrix
    newdata = data.frame(AREA = peakquinn$AREA)
    Xmat = model.matrix(~log10(AREA), newdata)
    ## get median parameter estimates
    coefs = apply(peakquinn.mcmc[, 1:2], 2, median)
    fit = as.vector(coefs %*% t(Xmat))
    resid = log10(peakquinn$INDIV) - fit
    ggplot() + geom_point(data = NULL, aes(y = resid, x = peakquinn$AREA)) + scale_x_log10()
    
    plot of chunk tut7.2bQ3.5c2
    library(rstan)
    peakquinn.mcmc = as.matrix(peakquinn.rstan)[, c("beta0", "beta[1]")]
    # generate a model matrix
    newdata = data.frame(AREA = peakquinn$AREA)
    Xmat = model.matrix(~log10(AREA), newdata)
    ## get median parameter estimates
    coefs = apply(peakquinn.mcmc[, 1:2], 2, median)
    fit = as.vector(coefs %*% t(Xmat))
    resid = log10(peakquinn$INDIV) - fit
    sresid = resid/sd(resid)
    ggplot() + geom_point(data = NULL, aes(y = sresid, x = fit))
    
    plot of chunk tut7.2bQ3.5c3
    library(rstan)
    peakquinn.mcmc = as.matrix(peakquinn.rstan)[, c("beta0", "beta[1]", "sigma")]
    # generate a model matrix
    Xmat = model.matrix(~log10(AREA), peakquinn)
    ## get median parameter estimates
    coefs = peakquinn.mcmc[, 1:2]
    fit = coefs %*% t(Xmat)
    ## draw samples from this model
    yRep = sapply(1:nrow(peakquinn.mcmc), function(i) rnorm(nrow(peakquinn), fit[i, ], peakquinn.mcmc[i,
        "sigma"]))
    ggplot() + geom_density(data = NULL, aes(x = as.vector(10^yRep), fill = "Model"), alpha = 0.5) + geom_density(data = peakquinn,
        aes(x = INDIV, fill = "Obs"), alpha = 0.5) + scale_x_log10()
    
    plot of chunk tut7.2bQ3.5c4
    ## Plot predicted effects
    library(rstan)
    peakquinn.mcmc = as.matrix(peakquinn.rstan)[, c("beta0", "beta[1]", "sigma")]
    # generate a model matrix
    newdata = with(peakquinn, data.frame(AREA = seq(min(AREA, na.rm = TRUE), max(AREA, na.rm = TRUE), len = 100)))
    Xmat = model.matrix(~log10(AREA), data = newdata)
    ## get median parameter estimates
    coefs = peakquinn.mcmc[, 1:2]
    fit = coefs %*% t(Xmat)
    fit = apply(fit, 2, function(x) rnorm(length(x), x, peakquinn.mcmc[, "sigma"]))
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(10^fit), conf.int = TRUE, conf.method = "HPDinterval"))
    ggplot(newdata, aes(y = estimate, x = AREA)) + geom_ribbon(aes(ymin = conf.low, ymax = conf.high), fill = "blue",
        alpha = 0.3) + geom_line() + geom_point(data = peakquinn, aes(y = INDIV)) + scale_x_log10()
    
    plot of chunk tut7.2bQ3.5c5
    ## Plot effects
    library(rstan)
    peakquinn.mcmc = as.matrix(peakquinn.rstan)[, c("beta0", "beta[1]")]
    # generate a model matrix
    newdata = with(peakquinn, data.frame(AREA = seq(min(AREA, na.rm = TRUE), max(AREA, na.rm = TRUE), len = 100)))
    Xmat = model.matrix(~log10(AREA), data = newdata)
    ## get median parameter estimates
    coefs = peakquinn.mcmc[, 1:2]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(10^fit), conf.int = TRUE, conf.method = "HPDinterval"))
    ggplot(newdata, aes(y = estimate, x = AREA)) + geom_ribbon(aes(ymin = conf.low, ymax = conf.high), fill = "blue",
        alpha = 0.3) + geom_line() + geom_point(data = peakquinn, aes(y = INDIV)) + scale_x_log10()
    
    plot of chunk tut7.2bQ3.5c6
    Show RSTANARM code
    library(rstanarm)
    resid = resid(peakquinn.rstanarm)
    fit = fitted(peakquinn.rstanarm)
    ggplot() + geom_point(data = NULL, aes(y = resid, x = fit))
    
    plot of chunk tut7.2bQ3.5d1
    ggplot() + geom_point(data = NULL, aes(y = resid, x = peakquinn$AREA)) + scale_x_log10()
    
    plot of chunk tut7.2bQ3.5d2
    sresid = resid/sd(resid)
    ggplot() + geom_point(data = NULL, aes(y = sresid, x = fit))
    
    plot of chunk tut7.2bQ3.5d3
    y_pred = posterior_predict(peakquinn.rstanarm)
    newdata = peakquinn %>% cbind(t(y_pred)) %>% gather(key = "Rep", value = "Value", -INDIV, -AREA)
    ggplot(newdata, aes(10^Value, x = AREA)) + geom_violin(color = "blue", fill = "blue", alpha = 0.5) +
        geom_violin(data = peakquinn, aes(y = INDIV, x = AREA), fill = "red", color = "red", alpha = 0.5) +
        scale_y_log10()
    
    plot of chunk tut7.2bQ3.5d4
    ## Calculate the fitted values
    newdata = data.frame(AREA = seq(min(peakquinn$AREA, na.rm = TRUE), max(peakquinn$AREA, na.rm = TRUE),
        len = 1000))
    fit = posterior_predict(peakquinn.rstanarm, newdata = newdata)
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(10^fit), conf.int = TRUE, conf.method = "HPDinterval"))
    
    ggplot(newdata, aes(y = estimate, x = AREA)) + geom_point(data = peakquinn, aes(y = INDIV)) + geom_line() +
        geom_ribbon(aes(ymin = conf.low, ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_continuous("Individuals") +
        scale_x_log10("Area") + theme_classic()
    
    plot of chunk tut7.2bQ3.5d4
    ## Marginal plots
    pp_check(peakquinn.rstanarm, x = peakquinn$AREA, plotfun = "ribbon")
    
    plot of chunk tut7.2bQ3.5d4
    newdata = with(peakquinn, data.frame(AREA = seq(min(AREA, na.rm = TRUE), max(AREA, na.rm = TRUE), len = 100)))
    fit = posterior_linpred(peakquinn.rstanarm, newdata = newdata)
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(10^fit), conf.int = TRUE, conf.method = "HPDinterval"))
    ggplot(newdata, aes(y = estimate, x = AREA)) + geom_ribbon(aes(ymin = conf.low, ymax = conf.high), fill = "blue",
        alpha = 0.3) + geom_line() + geom_point(data = peakquinn, aes(y = INDIV)) + scale_x_log10()
    
    plot of chunk tut7.2bQ3.5d4
    Show BRMS code
    library(brms)
    resid = resid(peakquinn.brm)[, "Estimate"]
    fit = fitted(peakquinn.brm)[, "Estimate"]
    ggplot() + geom_point(data = NULL, aes(y = resid, x = fit))
    
    plot of chunk tut7.2bQ3.5e1
    ggplot() + geom_point(data = NULL, aes(y = resid, x = peakquinn$AREA)) + scale_x_log10()
    
    plot of chunk tut7.2bQ3.5e2
    sresid = resid/sd(resid)
    ggplot() + geom_point(data = NULL, aes(y = sresid, x = fit))
    
    plot of chunk tut7.2bQ3.5e3
    y_pred = posterior_predict(peakquinn.brm)
    newdata = peakquinn %>% cbind(t(10^y_pred)) %>% gather(key = "Rep", value = "Value", -INDIV, -AREA)
    ggplot(newdata, aes(Value, x = AREA)) + geom_violin(color = "blue", fill = "blue", alpha = 0.5) + geom_violin(data = peakquinn,
        aes(y = INDIV, x = AREA), fill = "red", color = "red", alpha = 0.5)
    
    plot of chunk tut7.2bQ3.5e4
    ## Calculate the fitted values
    newdata = with(peakquinn, data.frame(AREA = seq(min(AREA, na.rm = TRUE), max(AREA, na.rm = TRUE), len = 1000)))
    fit = posterior_predict(peakquinn.brm, newdata = newdata)
    newdata = newdata %>% cbind(tidyMCMC(as.mcmc(10^fit), conf.int = TRUE, conf.method = "HPDinterval"))
    
    ggplot(newdata, aes(y = estimate, x = AREA)) + geom_point(data = peakquinn, aes(y = INDIV)) + geom_line() +
        geom_ribbon(aes(ymin = conf.low, ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_log10("Individual") +
        scale_x_log10("AREA") + theme_classic()
    
    plot of chunk tut7.2bQ3.5e4
    # marginal effects plots
    marginal_effects(peakquinn.brm)
    
    plot of chunk tut7.2bQ3.5e4
    marginal_effects(peakquinn.brm, spaghetti = TRUE, nsamples = 100)
    
    plot of chunk tut7.2bQ3.5e4
  6. All diagnostics appear reasonable.

  7. Explore parameter estimates
    Show MCMCpack code
    library(MCMCpack)
    summary(peakquinn.mcmcpack)
    
    Iterations = 1001:11000
    Thinning interval = 1 
    Number of chains = 1 
    Sample size per chain = 10000 
    
    1. Empirical mean and standard deviation for each variable,
       plus standard error of the mean:
    
                    Mean      SD  Naive SE Time-series SE
    (Intercept) -0.57131 0.27251 0.0027251      0.0026703
    log10(AREA)  0.83362 0.07441 0.0007441      0.0007266
    sigma2       0.03792 0.01237 0.0001237      0.0001336
    
    2. Quantiles for each variable:
    
                    2.5%      25%      50%      75%    97.5%
    (Intercept) -1.10158 -0.74580 -0.56897 -0.39754 -0.02977
    log10(AREA)  0.68383  0.78651  0.83319  0.88169  0.97917
    sigma2       0.02092  0.02922  0.03558  0.04388  0.06803
    
    library(broom)
    tidyMCMC(peakquinn.mcmcpack, conf.int = TRUE, conf.method = "HPDinterval")
    
             term    estimate  std.error    conf.low   conf.high
    1 (Intercept) -0.57130607 0.27250947 -1.09609681 -0.02482494
    2 log10(AREA)  0.83362289 0.07441021  0.69012962  0.98468559
    3      sigma2  0.03792093 0.01236899  0.01882708  0.06283368
    
    mcmcpvalue(peakquinn.mcmcpack[, 2])
    
    [1] 0
    
    Show JAGS code
    library(R2jags)
    print(peakquinn.r2jags)
    
    Inference for Bugs model at "5", fit using jags,
     3 chains, each with 166667 iterations (first 2000 discarded), n.thin = 10
     n.sims = 49401 iterations saved
             mu.vect sd.vect    2.5%     25%     50%     75%  97.5%  Rhat n.eff
    alpha     -0.577   0.269  -1.111  -0.754  -0.576  -0.400 -0.051 1.001 49000
    beta       0.835   0.074   0.692   0.787   0.835   0.884  0.980 1.001 49000
    sigma      0.192   0.030   0.144   0.171   0.188   0.209  0.260 1.001 49000
    deviance -12.183   2.579 -15.118 -14.064 -12.846 -11.015 -5.506 1.001 49000
    
    For each parameter, n.eff is a crude measure of effective sample size,
    and Rhat is the potential scale reduction factor (at convergence, Rhat=1).
    
    DIC info (using the rule, pD = var(deviance)/2)
    pD = 3.3 and DIC = -8.9
    DIC is an estimate of expected predictive error (lower deviance is better).
    
    # OR
    library(broom)
    tidyMCMC(as.mcmc(peakquinn.r2jags), conf.int = TRUE, conf.method = "HPDinterval")
    
          term    estimate  std.error    conf.low   conf.high
    1    alpha  -0.5767199 0.26947606  -1.1116200 -0.05173172
    2     beta   0.8351474 0.07352653   0.6919211  0.98028459
    3 deviance -12.1825546 2.57915960 -15.3448785 -7.08681085
    4    sigma   0.1915678 0.02967345   0.1381878  0.25108823
    
    mcmcpvalue(peakquinn.r2jags$BUGSoutput$sims.matrix[, c("beta")])
    
    [1] 0
    
    Show RSTAN code
    library(rstan)
    summary(peakquinn.rstan)
    
    $summary
                  mean      se_mean         sd       2.5%        25%        50%        75%       97.5%
    beta[1]  0.8345211 0.0009406821 0.07702748  0.6799697  0.7852477  0.8345370  0.8840285  0.98908670
    cbeta0   2.4528078 0.0004956690 0.03949651  2.3752328  2.4265938  2.4531440  2.4790586  2.53016722
    sigma    0.1965092 0.0004195304 0.03106664  0.1466567  0.1745136  0.1926655  0.2135549  0.26847916
    beta0   -0.5749167 0.0034557717 0.28196149 -1.1407613 -0.7548507 -0.5752530 -0.3930258 -0.01323992
    lp__    27.3242350 0.0198008852 1.32765528 23.9179494 26.7312808 27.6889601 28.2850874 28.80824526
               n_eff      Rhat
    beta[1] 6705.105 0.9998404
    cbeta0  6349.418 1.0003088
    sigma   5483.549 1.0000511
    beta0   6657.168 0.9999017
    lp__    4495.743 0.9999604
    
    $c_summary
    , , chains = chain:1
    
             stats
    parameter       mean         sd       2.5%        25%        50%        75%       97.5%
      beta[1]  0.8351555 0.07682432  0.6775663  0.7861514  0.8365360  0.8846239  0.98903431
      cbeta0   2.4537252 0.03880553  2.3809506  2.4284368  2.4538544  2.4793976  2.53310501
      sigma    0.1957253 0.03092306  0.1459999  0.1735727  0.1922146  0.2131895  0.26609723
      beta0   -0.5763009 0.28055386 -1.1323779 -0.7552083 -0.5821777 -0.3938731 -0.01575746
      lp__    27.3305899 1.29924695 23.9320943 26.7539850 27.6608027 28.2813034 28.78446771
    
    , , chains = chain:2
    
             stats
    parameter       mean         sd       2.5%        25%        50%        75%       97.5%
      beta[1]  0.8352273 0.07862704  0.6781426  0.7833919  0.8351356  0.8844430  0.99766912
      cbeta0   2.4516565 0.04038111  2.3744419  2.4250195  2.4519134  2.4788291  2.52975216
      sigma    0.1974370 0.03114833  0.1487654  0.1759307  0.1929279  0.2143715  0.26959720
      beta0   -0.5786301 0.28754632 -1.1756092 -0.7569717 -0.5795402 -0.3873010 -0.01341378
      lp__    27.2996775 1.36323093 23.9833846 26.6752326 27.6914222 28.2780846 28.81726593
    
    , , chains = chain:3
    
             stats
    parameter       mean         sd       2.5%        25%        50%        75%       97.5%
      beta[1]  0.8331806 0.07561802  0.6851647  0.7866751  0.8324022  0.8830087  0.98128877
      cbeta0   2.4530416 0.03927576  2.3732891  2.4273354  2.4539602  2.4791965  2.52623002
      sigma    0.1963653 0.03111777  0.1460359  0.1743035  0.1928699  0.2132741  0.26946511
      beta0   -0.5698192 0.27774535 -1.1144012 -0.7498764 -0.5687562 -0.3958906 -0.01360829
      lp__    27.3424375 1.31990785 23.8372128 26.7597502 27.7054566 28.3026957 28.82123035
    
    # OR
    library(broom)
    tidyMCMC(peakquinn.rstan, conf.int = TRUE, conf.method = "HPDinterval")
    
         term   estimate  std.error   conf.low   conf.high
    1 beta[1]  0.8345211 0.07702748  0.6713353  0.97767334
    2  cbeta0  2.4528078 0.03949651  2.3746189  2.52891005
    3   sigma  0.1965092 0.03106664  0.1412711  0.25845271
    4   beta0 -0.5749167 0.28196149 -1.1347320 -0.01195529
    
    mcmcpvalue(as.matrix(peakquinn.rstan)[, c("beta[1]")])
    
    [1] 0
    
    Show RSTANARM code
    library(rstanarm)
    summary(peakquinn.rstanarm)
    
    Model Info:
    
     function:  stan_glm
     family:    gaussian [identity]
     formula:   log10(INDIV) ~ log10(AREA)
     algorithm: sampling
     priors:    see help('prior_summary')
     sample:    6750 (posterior sample size)
     num obs:   25
    
    Estimates:
                    mean   sd   2.5%   25%   50%   75%   97.5%
    (Intercept)   -0.6    0.3 -1.1   -0.8  -0.6  -0.4   0.0   
    log10(AREA)    0.8    0.1  0.7    0.8   0.8   0.9   1.0   
    sigma          0.2    0.0  0.1    0.2   0.2   0.2   0.3   
    mean_PPD       2.5    0.1  2.3    2.4   2.5   2.5   2.6   
    log-posterior -3.4    1.3 -6.7   -4.0  -3.1  -2.5  -1.9   
    
    Diagnostics:
                  mcse Rhat n_eff
    (Intercept)   0.0  1.0  5690 
    log10(AREA)   0.0  1.0  5837 
    sigma         0.0  1.0  4379 
    mean_PPD      0.0  1.0  5756 
    log-posterior 0.0  1.0  3540 
    
    For each parameter, mcse is Monte Carlo standard error, n_eff is a crude measure of effective sample size, and Rhat is the potential scale reduction factor on split chains (at convergence Rhat=1).
    
    # OR
    library(broom)
    tidyMCMC(peakquinn.rstanarm$stanfit, conf.int = TRUE, conf.method = "HPDinterval", rhat = TRUE, ess = TRUE)
    
               term   estimate  std.error   conf.low   conf.high      rhat  ess
    1   (Intercept) -0.5836557 0.27940726 -1.1643511 -0.05480217 1.0007659 5690
    2   log10(AREA)  0.8369915 0.07598716  0.6827345  0.98388027 1.0007140 5837
    3         sigma  0.1962711 0.03115469  0.1408551  0.25886522 0.9995939 4379
    4      mean_PPD  2.4531215 0.05594231  2.3406396  2.56302601 0.9997911 5756
    5 log-posterior -3.4051806 1.27356338 -5.9644873 -1.79561380 1.0000918 3540
    
    mcmcpvalue(as.matrix(peakquinn.rstanarm)[, c("log10(AREA)")])
    
    [1] 0
    
    posterior_interval(peakquinn.rstanarm, prob = 0.95)
    
                      2.5%       97.5%
    (Intercept) -1.1490159 -0.03698934
    log10(AREA)  0.6878909  0.99053120
    sigma        0.1470404  0.26706512
    
    (full = loo(peakquinn.rstanarm))
    
    Computed from 6750 by 25 log-likelihood matrix
    
             Estimate  SE
    elpd_loo      4.0 4.0
    p_loo         3.4 1.3
    looic        -8.0 8.0
    
    Pareto k diagnostic values:
                             Count  Pct 
    (-Inf, 0.5]   (good)     24    96.0%
     (0.5, 0.7]   (ok)        1     4.0%
       (0.7, 1]   (bad)       0     0.0%
       (1, Inf)   (very bad)  0     0.0%
    
    All Pareto k estimates are ok (k < 0.7)
    See help('pareto-k-diagnostic') for details.
    
    (reduced = loo(update(peakquinn.rstanarm, formula = . ~ 1)))
    
    Gradient evaluation took 2.7e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.27 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.012857 seconds (Warm-up)
                   0.090834 seconds (Sampling)
                   0.103691 seconds (Total)
    
    
    Gradient evaluation took 8e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.08 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.011185 seconds (Warm-up)
                   0.089029 seconds (Sampling)
                   0.100214 seconds (Total)
    
    
    Gradient evaluation took 8e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.08 seconds.
    Adjust your expectations accordingly!
    
    
    
     Elapsed Time: 0.010407 seconds (Warm-up)
                   0.092465 seconds (Sampling)
                   0.102872 seconds (Total)
    
    Computed from 6750 by 25 log-likelihood matrix
    
             Estimate  SE
    elpd_loo    -19.0 3.7
    p_loo         2.0 0.8
    looic        38.0 7.3
    
    All Pareto k estimates are good (k < 0.5)
    See help('pareto-k-diagnostic') for details.
    
    par(mfrow = 1:2, mar = c(5, 3.8, 1, 0) + 0.1, las = 3)
    plot(full, label_points = TRUE)
    plot(reduced, label_points = TRUE)
    
    plot of chunk tut7.2bQ3.6d1
    compare_models(full, reduced)
    
    elpd_diff        se 
        -23.0       2.3 
    
    Show BRMS code
    library(brms)
    summary(peakquinn.brm)
    
     Family: gaussian(identity) 
    Formula: log10(INDIV) ~ log10(AREA) 
       Data: peakquinn (Number of observations: 25) 
    Samples: 3 chains, each with iter = 5000; warmup = 500; thin = 2; 
             total post-warmup samples = 6750
        ICs: LOO = Not computed; WAIC = Not computed
     
    Population-Level Effects: 
              Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
    Intercept    -0.58      0.28    -1.12    -0.02       6035    1
    log10AREA     0.83      0.08     0.68     0.98       5996    1
    
    Family Specific Parameters: 
          Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
    sigma      0.2      0.03     0.15     0.27       5767    1
    
    Samples were drawn using sampling(NUTS). For each parameter, Eff.Sample 
    is a crude measure of effective sample size, and Rhat is the potential 
    scale reduction factor on split chains (at convergence, Rhat = 1).
    
    # OR
    library(broom)
    tidyMCMC(peakquinn.brm$fit, conf.int = TRUE, conf.method = "HPDinterval", rhat = TRUE, ess = TRUE)
    
             term   estimate  std.error   conf.low   conf.high      rhat  ess
    1 b_Intercept -0.5760033 0.27691811 -1.1462869 -0.05047086 0.9996657 6035
    2 b_log10AREA  0.8348254 0.07564679  0.6799105  0.97781209 0.9996749 5996
    3       sigma  0.1965642 0.03131567  0.1396273  0.25739764 0.9999035 5767
    
    mcmcpvalue(as.matrix(peakquinn.brm)[, c("b_log10AREA")])
    
    [1] 0
    
    posterior_interval(as.matrix(peakquinn.brm), prob = 0.95)
    
                     2.5%       97.5%
    b_Intercept -1.120862 -0.02375458
    b_log10AREA  0.684706  0.98353056
    sigma        0.146823  0.26839084
    lp__        23.838600 28.81180829
    
    (full = loo(peakquinn.brm))
    
     LOOIC   SE
     -7.83 8.23
    
    (reduced = loo(update(peakquinn.brm, formula = . ~ 1)))
    
    SAMPLING FOR MODEL 'gaussian(identity) brms-model' NOW (CHAIN 1).
    
    Gradient evaluation took 1.5e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.15 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration: 1000 / 5000 [ 20%]  (Warmup)
    Iteration: 1500 / 5000 [ 30%]  (Warmup)
    Iteration: 2000 / 5000 [ 40%]  (Warmup)
    Iteration: 2500 / 5000 [ 50%]  (Warmup)
    Iteration: 2501 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.028246 seconds (Warm-up)
                   0.031009 seconds (Sampling)
                   0.059255 seconds (Total)
    
    
    SAMPLING FOR MODEL 'gaussian(identity) brms-model' NOW (CHAIN 2).
    
    Gradient evaluation took 1.4e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.14 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration: 1000 / 5000 [ 20%]  (Warmup)
    Iteration: 1500 / 5000 [ 30%]  (Warmup)
    Iteration: 2000 / 5000 [ 40%]  (Warmup)
    Iteration: 2500 / 5000 [ 50%]  (Warmup)
    Iteration: 2501 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.027503 seconds (Warm-up)
                   0.029819 seconds (Sampling)
                   0.057322 seconds (Total)
    
    
    SAMPLING FOR MODEL 'gaussian(identity) brms-model' NOW (CHAIN 3).
    
    Gradient evaluation took 3e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.03 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration: 1000 / 5000 [ 20%]  (Warmup)
    Iteration: 1500 / 5000 [ 30%]  (Warmup)
    Iteration: 2000 / 5000 [ 40%]  (Warmup)
    Iteration: 2500 / 5000 [ 50%]  (Warmup)
    Iteration: 2501 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.023562 seconds (Warm-up)
                   0.020834 seconds (Sampling)
                   0.044396 seconds (Total)
    
    
    SAMPLING FOR MODEL 'gaussian(identity) brms-model' NOW (CHAIN 1).
    
    Gradient evaluation took 1.1e-05 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.11 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration: 1000 / 5000 [ 20%]  (Warmup)
    Iteration: 1500 / 5000 [ 30%]  (Warmup)
    Iteration: 2000 / 5000 [ 40%]  (Warmup)
    Iteration: 2500 / 5000 [ 50%]  (Warmup)
    Iteration: 2501 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.028057 seconds (Warm-up)
                   0.030096 seconds (Sampling)
                   0.058153 seconds (Total)
    
    
    SAMPLING FOR MODEL 'gaussian(identity) brms-model' NOW (CHAIN 2).
    
    Gradient evaluation took 5e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.05 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration: 1000 / 5000 [ 20%]  (Warmup)
    Iteration: 1500 / 5000 [ 30%]  (Warmup)
    Iteration: 2000 / 5000 [ 40%]  (Warmup)
    Iteration: 2500 / 5000 [ 50%]  (Warmup)
    Iteration: 2501 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.027028 seconds (Warm-up)
                   0.028926 seconds (Sampling)
                   0.055954 seconds (Total)
    
    
    SAMPLING FOR MODEL 'gaussian(identity) brms-model' NOW (CHAIN 3).
    
    Gradient evaluation took 5e-06 seconds
    1000 transitions using 10 leapfrog steps per transition would take 0.05 seconds.
    Adjust your expectations accordingly!
    
    
    Iteration:    1 / 5000 [  0%]  (Warmup)
    Iteration:  500 / 5000 [ 10%]  (Warmup)
    Iteration: 1000 / 5000 [ 20%]  (Warmup)
    Iteration: 1500 / 5000 [ 30%]  (Warmup)
    Iteration: 2000 / 5000 [ 40%]  (Warmup)
    Iteration: 2500 / 5000 [ 50%]  (Warmup)
    Iteration: 2501 / 5000 [ 50%]  (Sampling)
    Iteration: 3000 / 5000 [ 60%]  (Sampling)
    Iteration: 3500 / 5000 [ 70%]  (Sampling)
    Iteration: 4000 / 5000 [ 80%]  (Sampling)
    Iteration: 4500 / 5000 [ 90%]  (Sampling)
    Iteration: 5000 / 5000 [100%]  (Sampling)
    
     Elapsed Time: 0.027537 seconds (Warm-up)
                   0.024572 seconds (Sampling)
                   0.052109 seconds (Total)
    
     LOOIC   SE
     37.81 7.22
    
    par(mfrow = 1:2, mar = c(5, 3.8, 1, 0) + 0.1, las = 3)
    plot(full, label_points = TRUE)
    plot(reduced, label_points = TRUE)
    
    plot of chunk tut7.2bQ3.6e1
    compare_models(full, reduced)
    
    Error in discrete == discrete[1]: comparison of these types is not implemented
    
  8. Generate graphical summaries
    Show MCMCpack code
    library(MCMCpack)
    peakquinn.mcmc = peakquinn.mcmcpack
    ## Calculate the fitted values
    newdata = with(peakquinn, data.frame(AREA = seq(min(AREA, na.rm = TRUE),
        max(AREA, na.rm = TRUE), len = 1000)))
    Xmat = model.matrix(~log10(AREA), newdata)
    coefs = peakquinn.mcmc[, 1:2]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(tidyMCMC(10^fit, conf.int = TRUE, conf.method = "HPDinterval"))
    
    ggplot(newdata, aes(y = estimate, x = AREA)) + geom_point(data = peakquinn,
        aes(y = INDIV, x = AREA)) + geom_line() + geom_ribbon(aes(ymin = conf.low,
        ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_log10(expression(Number ~
        of ~ individuals), breaks = c(1, 2, 5) %o% 10^c(-1:3)) + scale_x_log10(expression(Mussel ~
        clump ~ area ~ (mm^{
        2
    })), breaks = c(1, 2, 5) %o% 10^c(0:4)) + theme_classic()
    
    plot of chunk tut7.2bQ3.7a1
    library(MCMCpack)
    peakquinn.mcmc = peakquinn.mcmcpack
    ## Calculate the fitted values
    newdata = with(peakquinn, data.frame(AREA = seq(min(AREA, na.rm = TRUE),
        max(AREA, na.rm = TRUE), len = 1000)))
    Xmat = model.matrix(~log10(AREA), newdata)
    coefs = peakquinn.mcmc[, 1:2]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(t(10^fit))
    newdata = newdata %>% gather(key = Sample, value = fit, -AREA, )
    newdata.sum = newdata %>% group_by(AREA) %>% dplyr:::summarize(fit = median(fit))
    ## reduce the number of lines from over 6000 to 200
    newdata = newdata %>% filter(Sample < 201)
    ggplot(newdata, aes(y = estimate, x = AREA)) + geom_line(aes(y = fit, x = AREA,
        group = Sample), alpha = 0.01) + geom_line(data = newdata.sum, aes(y = fit,
        x = AREA), color = "blue") + geom_point(data = peakquinn, aes(y = INDIV,
        x = AREA), color = "red") + scale_y_log10(expression(Number ~ of ~
        individuals), breaks = c(1, 2, 5) %o% 10^c(-1:3)) + scale_x_log10(expression(Mussel ~
        clump ~ area ~ (mm^{
        2
    })), breaks = c(1, 2, 5) %o% 10^c(0:4)) + theme_classic()
    
    plot of chunk tut7.2bQ3.7a2
    Show JAGS code
    peakquinn.mcmc = peakquinn.r2jags$BUGSoutput$sims.matrix
    ## Calculate the fitted values
    newdata = with(peakquinn, data.frame(AREA = seq(min(AREA, na.rm = TRUE),
        max(AREA, na.rm = TRUE), len = 1000)))
    Xmat = model.matrix(~log10(AREA), newdata)
    coefs = peakquinn.mcmc[, c("alpha", "beta")]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(tidyMCMC(10^fit, conf.int = TRUE, conf.method = "HPDinterval"))
    
    ggplot(newdata, aes(y = estimate, x = AREA)) + geom_point(data = peakquinn,
        aes(y = INDIV, x = AREA)) + geom_line() + geom_ribbon(aes(ymin = conf.low,
        ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_log10(expression(Number ~
        of ~ individuals), breaks = c(1, 2, 5) %o% 10^c(-1:3)) + scale_x_log10(expression(Mussel ~
        clump ~ area ~ (mm^{
        2
    })), breaks = c(1, 2, 5) %o% 10^c(0:4)) + theme_classic()
    
    plot of chunk tut7.2bQ3.7b1
    peakquinn.mcmc = peakquinn.r2jags$BUGSoutput$sims.matrix
    ## Calculate the fitted values
    newdata = with(peakquinn, data.frame(AREA = seq(min(AREA, na.rm = TRUE),
        max(AREA, na.rm = TRUE), len = 1000)))
    Xmat = model.matrix(~log10(AREA), newdata)
    coefs = peakquinn.mcmc[, c("alpha", "beta")]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(t(10^fit))
    newdata = newdata %>% gather(key = Sample, value = fit, -AREA, )
    newdata.sum = newdata %>% group_by(AREA) %>% dplyr:::summarize(fit = median(fit))
    ## reduce the number of lines from over 6000 to 200
    newdata = newdata %>% filter(Sample < 201)
    ggplot(newdata, aes(y = estimate, x = AREA)) + geom_line(aes(y = fit, x = AREA,
        group = Sample), alpha = 0.01) + geom_line(data = newdata.sum, aes(y = fit,
        x = AREA), color = "blue") + geom_point(data = peakquinn, aes(y = INDIV,
        x = AREA), color = "red") + scale_y_log10(expression(Number ~ of ~
        individuals), breaks = c(1, 2, 5) %o% 10^c(-1:3)) + scale_x_log10(expression(Mussel ~
        clump ~ area ~ (mm^{
        2
    })), breaks = c(1, 2, 5) %o% 10^c(0:4)) + theme_classic()
    
    plot of chunk tut7.2bQ3.7b2
    Show RSTAN code
    peakquinn.mcmc = as.matrix(peakquinn.rstan)
    ## Calculate the fitted values
    newdata = with(peakquinn, data.frame(AREA = seq(min(AREA, na.rm = TRUE),
        max(AREA, na.rm = TRUE), len = 1000)))
    Xmat = model.matrix(~log10(AREA), newdata)
    coefs = peakquinn.mcmc[, c("beta0", "beta[1]")]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(tidyMCMC(10^fit, conf.int = TRUE, conf.method = "HPDinterval"))
    
    ggplot(newdata, aes(y = estimate, x = AREA)) + geom_point(data = peakquinn,
        aes(y = INDIV, x = AREA)) + geom_line() + geom_ribbon(aes(ymin = conf.low,
        ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_log10(expression(Number ~
        of ~ individuals), breaks = c(1, 2, 5) %o% 10^c(-1:3)) + scale_x_log10(expression(Mussel ~
        clump ~ area ~ (mm^{
        2
    })), breaks = c(1, 2, 5) %o% 10^c(0:4)) + theme_classic()
    
    plot of chunk tut7.2bQ3.7c1
    peakquinn.mcmc = as.matrix(peakquinn.rstan)
    ## Calculate the fitted values
    newdata = with(peakquinn, data.frame(AREA = seq(min(AREA, na.rm = TRUE),
        max(AREA, na.rm = TRUE), len = 1000)))
    Xmat = model.matrix(~log10(AREA), newdata)
    coefs = peakquinn.mcmc[, c("beta0", "beta[1]")]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(t(10^fit))
    newdata = newdata %>% gather(key = Sample, value = fit, -AREA, )
    newdata.sum = newdata %>% group_by(AREA) %>% dplyr:::summarize(fit = median(fit))
    ## reduce the number of lines from over 6000 to 200
    newdata = newdata %>% filter(Sample < 201)
    ggplot(newdata, aes(y = estimate, x = AREA)) + geom_line(aes(y = fit, x = AREA,
        group = Sample), alpha = 0.01) + geom_line(data = newdata.sum, aes(y = fit,
        x = AREA), color = "blue") + geom_point(data = peakquinn, aes(y = INDIV,
        x = AREA), color = "red") + scale_y_log10(expression(Number ~ of ~
        individuals), breaks = c(1, 2, 5) %o% 10^c(-1:3)) + scale_x_log10(expression(Mussel ~
        clump ~ area ~ (mm^{
        2
    })), breaks = c(1, 2, 5) %o% 10^c(0:4)) + theme_classic()
    
    plot of chunk tut7.2bQ3.7c2
    Show RSTANARM code
    peakquinn.mcmc = as.matrix(peakquinn.rstanarm)
    ## Calculate the fitted values
    newdata = with(peakquinn, data.frame(AREA = seq(min(AREA, na.rm = TRUE),
        max(AREA, na.rm = TRUE), len = 1000)))
    Xmat = model.matrix(~log10(AREA), newdata)
    coefs = peakquinn.mcmc[, c("(Intercept)", "log10(AREA)")]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(tidyMCMC(10^fit, conf.int = TRUE, conf.method = "HPDinterval"))
    
    ggplot(newdata, aes(y = estimate, x = AREA)) + geom_point(data = peakquinn,
        aes(y = INDIV, x = AREA)) + geom_line() + geom_ribbon(aes(ymin = conf.low,
        ymax = conf.high), fill = "blue", alpha = 0.3) + scale_y_log10(expression(Number ~
        of ~ individuals), breaks = c(1, 2, 5) %o% 10^c(-1:3)) + scale_x_log10(expression(Mussel ~
        clump ~ area ~ (mm^{
        2
    })), breaks = c(1, 2, 5) %o% 10^c(0:4)) + theme_classic()
    
    plot of chunk tut7.2bQ3.7d1
    peakquinn.mcmc = as.matrix(peakquinn.rstanarm)
    ## Calculate the fitted values
    newdata = with(peakquinn, data.frame(AREA = seq(min(AREA, na.rm = TRUE),
        max(AREA, na.rm = TRUE), len = 1000)))
    Xmat = model.matrix(~log10(AREA), newdata)
    coefs = peakquinn.mcmc[, c("(Intercept)", "log10(AREA)")]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(t(10^fit))
    newdata = newdata %>% gather(key = Sample, value = fit, -AREA, )
    newdata.sum = newdata %>% group_by(AREA) %>% dplyr:::summarize(fit = median(fit))
    ## reduce the number of lines from over 6000 to 200
    newdata = newdata %>% filter(Sample < 201)
    ggplot(newdata, aes(y = estimate, x = AREA)) + geom_line(aes(y = fit, x = AREA,
        group = Sample), alpha = 0.01) + geom_line(data = newdata.sum, aes(y = fit,
        x = AREA), color = "blue") + geom_point(data = peakquinn, aes(y = INDIV,
        x = AREA), color = "red") + scale_y_log10(expression(Number ~ of ~
        individuals), breaks = c(1, 2, 5) %o% 10^c(-1:3)) + scale_x_log10(expression(Mussel ~
        clump ~ area ~ (mm^{
        2
    })), breaks = c(1, 2, 5) %o% 10^c(0:4)) + theme_classic()
    
    plot of chunk tut7.2bQ3.7d2
    Show BRMS code
    newdata = marginal_effects(peakquinn.brm)$AREA
    newdata = newdata %>% mutate_at(vars(estimate__, lower__, upper__), function(x) 10^x)
    ggplot(newdata, aes(y = estimate__, x = AREA)) + geom_point(data = peakquinn,
        aes(y = INDIV, x = AREA)) + geom_line() + geom_ribbon(aes(ymin = lower__,
        ymax = upper__), fill = "blue", alpha = 0.3) + scale_y_log10(expression(Number ~
        of ~ individuals), breaks = c(1, 2, 5) %o% 10^c(-1:3)) + scale_x_log10(expression(Mussel ~
        clump ~ area ~ (mm^{
        2
    })), breaks = c(1, 2, 5) %o% 10^c(0:4)) + theme_classic()
    
    plot of chunk tut7.2bQ3.7e1
    peakquinn.mcmc = as.matrix(peakquinn.brm)
    ## Calculate the fitted values
    newdata = with(peakquinn, data.frame(AREA = seq(min(AREA, na.rm = TRUE),
        max(AREA, na.rm = TRUE), len = 1000)))
    Xmat = model.matrix(~log10(AREA), newdata)
    coefs = peakquinn.mcmc[, c("b_Intercept", "b_log10AREA")]
    fit = coefs %*% t(Xmat)
    newdata = newdata %>% cbind(t(10^fit))
    newdata = newdata %>% gather(key = Sample, value = fit, -AREA, )
    newdata.sum = newdata %>% group_by(AREA) %>% dplyr:::summarize(fit = median(fit))
    ## reduce the number of lines from over 6000 to 200
    newdata = newdata %>% filter(Sample < 201)
    ggplot(newdata, aes(y = estimate, x = AREA)) + geom_line(aes(y = fit, x = AREA,
        group = Sample), alpha = 0.01) + geom_line(data = newdata.sum, aes(y = fit,
        x = AREA), color = "blue") + geom_point(data = peakquinn, aes(y = INDIV,
        x = AREA), color = "red") + scale_y_log10(expression(Number ~ of ~
        individuals), breaks = c(1, 2, 5) %o% 10^c(-1:3)) + scale_x_log10(expression(Mussel ~
        clump ~ area ~ (mm^{
        2
    })), breaks = c(1, 2, 5) %o% 10^c(0:4)) + theme_classic()
    
    plot of chunk tut7.2bQ3.7e2
  9. Explore effect sizes. Lets base this on a doubling in mussel clump area from 5000$mm^2$ to 10,000$mm^2$.
    Show MCMCpack code
    library(MCMCpack)
    peakquinn.mcmc = peakquinn.mcmcpack
    newdata = data.frame(AREA = c(5000, 10000))
    Xmat = model.matrix(~log10(AREA), newdata)
    coefs = peakquinn.mcmc[, c("(Intercept)", "log10(AREA)")]
    fit = 10^(coefs %*% t(Xmat))
    ## Raw effect size
    (RES = tidyMCMC(as.mcmc(fit[, 2] - fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 256.6267  40.81119 175.6593  336.0038
    
    ## Cohen's D
    cohenD = (fit[, 2] - fit[, 1])/sqrt(peakquinn.mcmc[, "sigma2"])
    (cohenDES = tidyMCMC(as.mcmc(cohenD), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 1365.205  293.8033 809.7041  1956.093
    
    # Percentage change
    ESp = 100 * (fit[, 2] - fit[, 1])/fit[, 1]
    (PES = tidyMCMC(as.mcmc(ESp), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 78.45249  9.200604 60.57998  97.03649
    
    # Probability that the effect is greater than 100%
    sum(ESp > 100)/length(ESp)
    
    [1] 0.0128
    
    ## fractional change
    fit = fit[fit[, 2] > 0, ]
    (FES = tidyMCMC(as.mcmc(fit[, 2]/fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate  std.error conf.low conf.high
    1 var1 1.784525 0.09200604   1.6058  1.970365
    
    Show JAGS code
    peakquinn.mcmc = peakquinn.r2jags$BUGSoutput$sims.matrix
    newdata = data.frame(AREA = c(5000, 10000))
    Xmat = model.matrix(~log10(AREA), newdata)
    coefs = peakquinn.mcmc[, c("alpha", "beta")]
    fit = 10^(coefs %*% t(Xmat))
    ## Raw effect size
    (RES = tidyMCMC(as.mcmc(fit[, 2] - fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 257.3033  40.31442 180.5504   337.299
    
    ## Cohen's D
    cohenD = (fit[, 2] - fit[, 1])/peakquinn.mcmc[, "sigma"]
    (cohenDES = tidyMCMC(as.mcmc(cohenD), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 1373.274   287.682 821.8336  1943.753
    
    # Percentage change
    ESp = 100 * (fit[, 2] - fit[, 1])/fit[, 1]
    (PES = tidyMCMC(as.mcmc(ESp), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 78.63583  9.115099 61.54332  97.28545
    
    # Probability that the effect is greater than 100%
    sum(ESp > 100)/length(ESp)
    
    [1] 0.0147163
    
    ## fractional change
    fit = fit[fit[, 2] > 0, ]
    (FES = tidyMCMC(as.mcmc(fit[, 2]/fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate  std.error conf.low conf.high
    1 var1 1.786358 0.09115099 1.615433  1.972855
    
    Show RSTAN code
    peakquinn.mcmc = as.matrix(peakquinn.rstan)
    newdata = data.frame(AREA = c(5000, 10000))
    Xmat = model.matrix(~log10(AREA), newdata)
    coefs = peakquinn.mcmc[, c("beta0", "beta[1]")]
    fit = 10^(coefs %*% t(Xmat))
    ## Raw effect size
    (RES = tidyMCMC(as.mcmc(fit[, 2] - fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 256.9233  41.95914 177.3289  340.1042
    
    ## Cohen's D
    cohenD = (fit[, 2] - fit[, 1])/peakquinn.mcmc[, "sigma"]
    (cohenDES = tidyMCMC(as.mcmc(cohenD), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 1338.051  290.3574 744.3034  1875.826
    
    # Percentage change
    ESp = 100 * (fit[, 2] - fit[, 1])/fit[, 1]
    (PES = tidyMCMC(as.mcmc(ESp), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 78.58077  9.540803 59.25463  96.92869
    
    # Probability that the effect is greater than 100%
    sum(ESp > 100)/length(ESp)
    
    [1] 0.01911111
    
    ## fractional change
    fit = fit[fit[, 2] > 0, ]
    (FES = tidyMCMC(as.mcmc(fit[, 2]/fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate  std.error conf.low conf.high
    1 var1 1.785808 0.09540803 1.592546  1.969287
    
    Show RSTANARM code
    peakquinn.mcmc = as.matrix(peakquinn.rstanarm)
    newdata = data.frame(AREA = c(5000, 10000))
    Xmat = model.matrix(~log10(AREA), newdata)
    coefs = peakquinn.mcmc[, c("(Intercept)", "log10(AREA)")]
    fit = 10^(coefs %*% t(Xmat))
    ## Raw effect size
    (RES = tidyMCMC(as.mcmc(fit[, 2] - fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 258.0592  41.27676 177.8736  337.9139
    
    ## Cohen's D
    cohenD = (fit[, 2] - fit[, 1])/peakquinn.mcmc[, "sigma"]
    (cohenDES = tidyMCMC(as.mcmc(cohenD), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 1346.056  289.6647 821.0758  1950.451
    
    # Percentage change
    ESp = 100 * (fit[, 2] - fit[, 1])/fit[, 1]
    (PES = tidyMCMC(as.mcmc(ESp), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 78.88025  9.441726 60.33071  97.57047
    
    # Probability that the effect is greater than 100%
    sum(ESp > 100)/length(ESp)
    
    [1] 0.01940741
    
    ## fractional change
    fit = fit[fit[, 2] > 0, ]
    (FES = tidyMCMC(as.mcmc(fit[, 2]/fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate  std.error conf.low conf.high
    1 var1 1.788802 0.09441726 1.603307  1.975705
    
    Show BRMS code
    peakquinn.mcmc = as.matrix(peakquinn.brm)
    newdata = data.frame(AREA = c(5000, 10000))
    Xmat = model.matrix(~log10(AREA), newdata)
    coefs = peakquinn.mcmc[, c("b_Intercept", "b_log10AREA")]
    fit = 10^(coefs %*% t(Xmat))
    ## Raw effect size
    (RES = tidyMCMC(as.mcmc(fit[, 2] - fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 257.0839  41.93587 173.4779   335.417
    
    ## Cohen's D
    cohenD = (fit[, 2] - fit[, 1])/peakquinn.mcmc[, "sigma"]
    (cohenDES = tidyMCMC(as.mcmc(cohenD), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 1338.203  285.7687  816.383  1929.084
    
    # Percentage change
    ESp = 100 * (fit[, 2] - fit[, 1])/fit[, 1]
    (PES = tidyMCMC(as.mcmc(ESp), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate std.error conf.low conf.high
    1 var1 78.60938  9.368605 59.65756  96.38583
    
    # Probability that the effect is greater than 100%
    sum(ESp > 100)/length(ESp)
    
    [1] 0.01511111
    
    ## fractional change
    fit = fit[fit[, 2] > 0, ]
    (FES = tidyMCMC(as.mcmc(fit[, 2]/fit[, 1]), conf.int = TRUE, conf.method = "HPDinterval"))
    
      term estimate  std.error conf.low conf.high
    1 var1 1.786094 0.09368605 1.596576  1.963858
    
  10. Finite-population standard deviations
    Show MCMCpack code
    library(MCMCpack)
    peakquinn.mcmc = peakquinn.mcmcpack
    newdata = peakquinn
    Xmat = model.matrix(~log10(AREA), newdata)
    coefs = peakquinn.mcmc[, c("(Intercept)", "log10(AREA)")]
    fit = 10^(coefs %*% t(Xmat))
    resid = sweep(fit, 2, peakquinn$INDIV, "-")
    sd.resid = apply(resid, 1, sd)
    sd.x = abs((fit[, 2] - fit[, 1])/(newdata$AREA[2] - newdata$AREA[1])) *
        sd(peakquinn$AREA)
    sd.all = cbind(sd.x, sd.resid)
    (fpsd = tidyMCMC(sd.all, conf.int = TRUE, conf.method = "HPDinterval"))
    
          term estimate std.error conf.low conf.high
    1     sd.x 660.8782  75.05975 512.5846  809.6377
    2 sd.resid 251.2939  36.89695 211.2944  324.1390
    
    # OR expressed as a percentage
    (fpsd.p = tidyMCMC(100 * sd.all/rowSums(sd.all), estimate.method = "median",
        conf.int = TRUE, conf.method = "HPDinterval"))
    
          term estimate std.error conf.low conf.high
    1     sd.x 72.95323  3.908862 64.07417  78.92681
    2 sd.resid 27.04677  3.908862 21.07319  35.92583
    
    ggplot(fpsd, aes(y = estimate, x = term)) + geom_pointrange(aes(ymin = conf.low,
        ymax = conf.high)) + geom_text(aes(label = sprintf("%.2f%%", fpsd.p$estimate),
        vjust = -1)) + scale_y_continuous("Finite population standard deviation") +
        scale_x_discrete() + coord_flip() + theme_classic()
    
    plot of chunk tut7.2bQ3.9a1
    Show JAGS code
    peakquinn.mcmc = peakquinn.r2jags$BUGSoutput$sims.matrix
    newdata = peakquinn
    Xmat = model.matrix(~log10(AREA), newdata)
    coefs = peakquinn.mcmc[, c("alpha", "beta")]
    fit = 10^(coefs %*% t(Xmat))
    resid = sweep(fit, 2, peakquinn$INDIV, "-")
    sd.resid = apply(resid, 1, sd)
    sd.x = abs((fit[, 2] - fit[, 1])/(newdata$AREA[2] - newdata$AREA[1])) *
        sd(peakquinn$AREA)
    sd.all = cbind(sd.x, sd.resid)
    (fpsd = tidyMCMC(sd.all, conf.int = TRUE, conf.method = "HPDinterval"))
    
          term estimate std.error conf.low conf.high
    1     sd.x 660.1122  74.43848 515.7628  806.9890
    2 sd.resid 251.6663  36.80898 211.2570  324.5143
    
    # OR expressed as a percentage
    (fpsd.p = tidyMCMC(100 * sd.all/rowSums(sd.all), estimate.method = "median",
        conf.int = TRUE, conf.method = "HPDinterval"))
    
          term estimate std.error conf.low conf.high
    1     sd.x 72.86154    3.9199 64.30474  79.16061
    2 sd.resid 27.13846    3.9199 20.83939  35.69526
    
    ggplot(fpsd, aes(y = estimate, x = term)) + geom_pointrange(aes(ymin = conf.low,
        ymax = conf.high)) + geom_text(aes(label = sprintf("%.2f%%", fpsd.p$estimate),
        vjust = -1)) + scale_y_continuous("Finite population standard deviation") +
        scale_x_discrete() + coord_flip() + theme_classic()
    
    plot of chunk tut7.2bQ3.9b1
    Show RSTAN code
    peakquinn.mcmc = as.matrix(peakquinn.rstan)
    newdata = peakquinn
    Xmat = model.matrix(~log10(AREA), newdata)
    coefs = peakquinn.mcmc[, c("beta0", "beta[1]")]
    fit = 10^(coefs %*% t(Xmat))
    resid = sweep(fit, 2, peakquinn$INDIV, "-")
    sd.resid = apply(resid, 1, sd)
    sd.x = abs((fit[, 2] - fit[, 1])/(newdata$AREA[2] - newdata$AREA[1])) *
        sd(peakquinn$AREA)
    sd.all = cbind(sd.x, sd.resid)
    (fpsd = tidyMCMC(sd.all, conf.int = TRUE, conf.method = "HPDinterval"))
    
          term estimate std.error conf.low conf.high
    1     sd.x 659.7561  76.17899 508.2497  807.5814
    2 sd.resid 252.1489  38.36843 210.6826  327.9973
    
    # OR expressed as a percentage
    (fpsd.p = tidyMCMC(100 * sd.all/rowSums(sd.all), estimate.method = "median",
        conf.int = TRUE, conf.method = "HPDinterval"))
    
          term estimate std.error conf.low conf.high
    1     sd.x 72.86224  4.081213 64.21619  79.58738
    2 sd.resid 27.13776  4.081213 20.41262  35.78381
    
    ggplot(fpsd, aes(y = estimate, x = term)) + geom_pointrange(aes(ymin = conf.low,
        ymax = conf.high)) + geom_text(aes(label = sprintf("%.2f%%", fpsd.p$estimate),
        vjust = -1)) + scale_y_continuous("Finite population standard deviation") +
        scale_x_discrete() + coord_flip() + theme_classic()
    
    plot of chunk tut7.2bQ3.9c1
    Show RSTANARM code
    peakquinn.mcmc = as.matrix(peakquinn.rstanarm)
    newdata = peakquinn
    Xmat = model.matrix(~log10(AREA), newdata)
    coefs = peakquinn.mcmc[, c("(Intercept)", "log10(AREA)")]
    fit = 10^(coefs %*% t(Xmat))
    resid = sweep(fit, 2, peakquinn$INDIV, "-")
    sd.resid = apply(resid, 1, sd)
    sd.x = abs((fit[, 2] - fit[, 1])/(newdata$AREA[2] - newdata$AREA[1])) *
        sd(peakquinn$AREA)
    sd.all = cbind(sd.x, sd.resid)
    (fpsd = tidyMCMC(sd.all, conf.int = TRUE, conf.method = "HPDinterval"))
    
          term estimate std.error conf.low conf.high
    1     sd.x 658.8303  77.98878 512.2534  820.9864
    2 sd.resid 252.8086  38.02596 211.3581  330.0817
    
    # OR expressed as a percentage
    (fpsd.p = tidyMCMC(100 * sd.all/rowSums(sd.all), estimate.method = "median",
        conf.int = TRUE, conf.method = "HPDinterval"))
    
          term estimate std.error conf.low conf.high
    1     sd.x 72.83891  4.106887 63.33252  78.94102
    2 sd.resid 27.16109  4.106887 21.05898  36.66748
    
    ggplot(fpsd, aes(y = estimate, x = term)) + geom_pointrange(aes(ymin = conf.low,
        ymax = conf.high)) + geom_text(aes(label = sprintf("%.2f%%", fpsd.p$estimate),
        vjust = -1)) + scale_y_continuous("Finite population standard deviation") +
        scale_x_discrete() + coord_flip() + theme_classic()
    
    plot of chunk tut7.2bQ3.9d1
    Show BRMS code
    peakquinn.mcmc = as.matrix(peakquinn.brm)
    newdata = peakquinn
    Xmat = model.matrix(~log10(AREA), newdata)
    coefs = peakquinn.mcmc[, c("b_Intercept", "b_log10AREA")]
    fit = 10^(coefs %*% t(Xmat))
    resid = sweep(fit, 2, peakquinn$INDIV, "-")
    sd.resid = apply(resid, 1, sd)
    sd.x = abs((fit[, 2] - fit[, 1])/(newdata$AREA[2] - newdata$AREA[1])) *
        sd(peakquinn$AREA)
    sd.all = cbind(sd.x, sd.resid)
    (fpsd = tidyMCMC(sd.all, conf.int = TRUE, conf.method = "HPDinterval"))
    
          term estimate std.error conf.low conf.high
    1     sd.x 659.7398  76.91358 508.5955  810.7227
    2 sd.resid 252.1473  38.46217 210.1392  325.3136
    
    # OR expressed as a percentage
    (fpsd.p = tidyMCMC(100 * sd.all/rowSums(sd.all), estimate.method = "median",
        conf.int = TRUE, conf.method = "HPDinterval"))
    
          term estimate std.error conf.low conf.high
    1     sd.x 72.82011  4.014486  64.0221   79.2249
    2 sd.resid 27.17989  4.014486  20.7751   35.9779
    
    ggplot(fpsd, aes(y = estimate, x = term)) + geom_pointrange(aes(ymin = conf.low,
        ymax = conf.high)) + geom_text(aes(label = sprintf("%.2f%%", fpsd.p$estimate),
        vjust = -1)) + scale_y_continuous("Finite population standard deviation") +
        scale_x_discrete() + coord_flip() + theme_classic()
    
    plot of chunk tut7.2bQ3.9e1
  11. $R^2$
    Show MCMCpack code
    library(MCMCpack)
    peakquinn.mcmc = peakquinn.mcmcpack
    newdata = peakquinn
    Xmat = model.matrix(~log10(AREA), newdata)
    coefs = peakquinn.mcmc[, c("(Intercept)", "log10(AREA)")]
    fit = (coefs %*% t(Xmat))
    x = log10(peakquinn$INDIV)
    resid = sweep(fit, 2, x, "-")
    var_f = apply(fit, 1, var)
    var_e = apply(resid, 1, var)
    R2 = var_f/(var_f + var_e)
    tidyMCMC(as.mcmc(R2), conf.int = TRUE, conf.method = "HPDinterval")
    
      term  estimate  std.error conf.low conf.high
    1 var1 0.8498102 0.02907766 0.795766 0.8760876
    
    # for comparison
    summary(lm(log10(INDIV) ~ log10(AREA), data = peakquinn))
    
    Call:
    lm(formula = log10(INDIV) ~ log10(AREA), data = peakquinn)
    
    Residuals:
         Min       1Q   Median       3Q      Max 
    -0.43355 -0.06464  0.02219  0.11178  0.26818 
    
    Coefficients:
                Estimate Std. Error t value Pr(>|t|)    
    (Intercept) -0.57601    0.25904  -2.224   0.0363 *  
    log10(AREA)  0.83492    0.07066  11.816 3.01e-11 ***
    ---
    Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    
    Residual standard error: 0.1856 on 23 degrees of freedom
    Multiple R-squared:  0.8586,	Adjusted R-squared:  0.8524 
    F-statistic: 139.6 on 1 and 23 DF,  p-value: 3.007e-11
    
    Show JAGS code
    peakquinn.mcmc = peakquinn.r2jags$BUGSoutput$sims.matrix
    newdata = peakquinn
    Xmat = model.matrix(~log10(AREA), newdata)
    coefs = peakquinn.mcmc[, c("alpha", "beta")]
    fit = (coefs %*% t(Xmat))
    x = log10(peakquinn$INDIV)
    resid = sweep(fit, 2, x, "-")
    var_f = apply(fit, 1, var)
    var_e = apply(resid, 1, var)
    R2 = var_f/(var_f + var_e)
    tidyMCMC(as.mcmc(R2), conf.int = TRUE, conf.method = "HPDinterval")
    
      term  estimate  std.error  conf.low conf.high
    1 var1 0.8505598 0.02721339 0.7984761 0.8760876
    
    Show RSTAN code
    peakquinn.mcmc = as.matrix(peakquinn.rstan)
    newdata = peakquinn
    Xmat = model.matrix(~log10(AREA), newdata)
    coefs = peakquinn.mcmc[, c("beta0", "beta[1]")]
    fit = (coefs %*% t(Xmat))
    x = log10(peakquinn$INDIV)
    resid = sweep(fit, 2, x, "-")
    var_f = apply(fit, 1, var)
    var_e = apply(resid, 1, var)
    R2 = var_f/(var_f + var_e)
    tidyMCMC(as.mcmc(R2), conf.int = TRUE, conf.method = "HPDinterval")
    
      term  estimate  std.error  conf.low conf.high
    1 var1 0.8495326 0.02996109 0.7939627 0.8760876
    
    Show RSTANARM code
    peakquinn.mcmc = as.matrix(peakquinn.rstanarm)
    newdata = peakquinn
    Xmat = model.matrix(~log10(AREA), newdata)
    coefs = peakquinn.mcmc[, c("(Intercept)", "log10(AREA)")]
    fit = (coefs %*% t(Xmat))
    x = log10(peakquinn$INDIV)
    resid = sweep(fit, 2, x, "-")
    var_f = apply(fit, 1, var)
    var_e = apply(resid, 1, var)
    R2 = var_f/(var_f + var_e)
    tidyMCMC(as.mcmc(R2), conf.int = TRUE, conf.method = "HPDinterval")
    
      term  estimate  std.error  conf.low conf.high
    1 var1 0.8506467 0.02769766 0.7993714 0.8760876
    
    Show BRMS code
    peakquinn.mcmc = as.matrix(peakquinn.brm)
    newdata = peakquinn
    Xmat = model.matrix(~log10(AREA), newdata)
    coefs = peakquinn.mcmc[, c("b_Intercept", "b_log10AREA")]
    fit = (coefs %*% t(Xmat))
    x = log10(peakquinn$INDIV)
    resid = sweep(fit, 2, x, "-")
    var_f = apply(fit, 1, var)
    var_e = apply(resid, 1, var)
    R2 = var_f/(var_f + var_e)
    tidyMCMC(as.mcmc(R2), conf.int = TRUE, conf.method = "HPDinterval")
    
      term  estimate  std.error conf.low conf.high
    1 var1 0.8499476 0.02852317 0.794581 0.8760876
    

  Frequentist pooled variances t-test

t.test(y~x, data, var.equal=TRUE)
Error in t.test.formula(y ~ x, data, var.equal = TRUE): grouping factor must have exactly 2 levels
#OR
data.lm <- lm(y~x, data)
summary(data.lm)
Call:
lm(formula = y ~ x, data = data)

Residuals:
     Min       1Q   Median       3Q      Max 
-11.3455  -3.5205   0.6545   2.6319   7.3650 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)   40.747      2.669  15.268 4.03e-10 ***
x             -1.534      0.276  -5.558 7.06e-05 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 5.089 on 14 degrees of freedom
Multiple R-squared:  0.6881,	Adjusted R-squared:  0.6658 
F-statistic: 30.89 on 1 and 14 DF,  p-value: 7.057e-05

End of instructions

  Frequentist pooled variances t-test

hello

End of instructions