Julian Faraway 22 September 2020
See the introduction for an overview. Load the libraries:
library(ggplot2)
library(INLA)
Load up and look at the data:
data(pulp, package="faraway")
summary(pulp)
bright operator
Min. :59.8 a:5
1st Qu.:60.0 b:5
Median :60.5 c:5
Mean :60.4 d:5
3rd Qu.:60.7
Max. :61.0
ggplot(pulp, aes(x=operator, y=bright))+geom_point(position = position_jitter(width=0.1, height=0.0))
Run the default INLA model:
formula <- bright ~ f(operator, model="iid")
result <- inla(formula, family="gaussian", data=pulp)
result <- inla.hyperpar(result)
summary(result)
Call:
"inla(formula = formula, family = \"gaussian\", data = pulp)"
Time used:
Pre = 0.976, Running = 0.134, Post = 0.0733, Total = 1.18
Fixed effects:
mean sd 0.025quant 0.5quant 0.975quant mode kld
(Intercept) 60.4 0.093 60.216 60.4 60.584 60.4 0
Random effects:
Name Model
operator IID model
Model hyperparameters:
mean sd 0.025quant 0.5quant 0.975quant mode
Precision for the Gaussian observations 7.04 2.25 3.41 6.78 12.13 6.30
Precision for operator 19120.58 20029.37 100.47 12920.98 73424.29 14.40
Expected number of effective parameters(stdev): 1.17(0.488)
Number of equivalent replicates : 17.09
Marginal log-Likelihood: -19.41
Precision for the operator term is unreasonably high. This is due to the diffuse gamma prior on the precisions. Problems are seen with other packages also. We can improve the calculation but result would remain implausible so it is better we change the prior.
Try a truncated normal prior with low precision instead. A precision of 0.01 corresponds to an SD of 10. This is substantially larger than the SD of the response so the information supplied is very weak.
tnprior <- list(prec = list(prior="logtnormal", param = c(0,0.01)))
formula <- bright ~ f(operator, model="iid", hyper = tnprior)
result <- inla(formula, family="gaussian", data=pulp)
result <- inla.hyperpar(result)
summary(result)
Call:
"inla(formula = formula, family = \"gaussian\", data = pulp)"
Time used:
Pre = 1.01, Running = 0.146, Post = 0.0748, Total = 1.23
Fixed effects:
mean sd 0.025quant 0.5quant 0.975quant mode kld
(Intercept) 60.4 0.41 59.612 60.4 61.188 60.4 0.022
Random effects:
Name Model
operator IID model
Model hyperparameters:
mean sd 0.025quant 0.5quant 0.975quant mode
Precision for the Gaussian observations 10.44 3.52e+00 4.728 10.04 18.40 9.236
Precision for operator 68999.86 4.94e+07 0.231 6.67 139.05 0.176
Expected number of effective parameters(stdev): 3.43(0.637)
Number of equivalent replicates : 5.83
Marginal log-Likelihood: -20.36
The results appear more plausible. Transform to the SD scale. Make a table of summary statistics for the posteriors:
sigmaalpha <- inla.tmarginal(function(x) 1/sqrt(exp(x)),result$internal.marginals.hyperpar[[2]])
sigmaepsilon <- inla.tmarginal(function(x) 1/sqrt(exp(x)),result$internal.marginals.hyperpar[[1]])
restab <- sapply(result$marginals.fixed, function(x) inla.zmarginal(x,silent=TRUE))
restab <- cbind(restab, inla.zmarginal(sigmaalpha,silent=TRUE))
restab <- cbind(restab, inla.zmarginal(sigmaepsilon,silent = TRUE))
restab <- cbind(restab, sapply(result$marginals.random$operator,function(x) inla.zmarginal(x, silent = TRUE)))
colnames(restab) <- c("mu","alpha","epsilon",levels(pulp$operator))
data.frame(restab)
mu alpha epsilon a b c d
mean 60.4 0.5489 0.32346 -0.1298 -0.27684 0.17976 0.2274
sd 0.41052 0.59606 0.057735 0.42072 0.42591 0.42327 0.42414
quant0.025 59.608 0.082628 0.23336 -0.96363 -1.141 -0.59516 -0.53446
quant0.25 60.255 0.24926 0.28217 -0.28764 -0.44163 0.0076432 0.045395
quant0.5 60.398 0.38448 0.31548 -0.11579 -0.25576 0.15884 0.20378
quant0.75 60.54 0.6217 0.35584 0.029438 -0.092496 0.3353 0.38524
quant0.975 61.187 2.051 0.45891 0.64599 0.47118 1.0208 1.0773
The results are now comparable to previous fits to this data using likelihood and MCMC-based methods. Plot the posterior densities for the two SD terms:
ddf <- data.frame(rbind(sigmaalpha,sigmaepsilon),errterm=gl(2,dim(sigmaalpha)[1],labels = c("alpha","epsilon")))
ggplot(ddf, aes(x,y, linetype=errterm))+geom_line()+xlab("bright")+ylab("density")+xlim(0,2)
We see that the operator SD less precisely known than the error SD.
We can compute the probability that the operator SD is smaller than 0.1:
inla.pmarginal(0.1, sigmaalpha)
[1] 0.034449
The probability is small but not negligible.
Now try more informative gamma priors for the precisions. Define it so
the mean value of gamma prior is set to the inverse of the variance of
the response. We expect the two error variances to be lower than the
response variance so this is an overestimate. The variance of the gamma
prior (for the precision) is controlled by the apar
shape parameter in
the code. apar=1
is the exponential distribution. Shape values less
than one result in densities that have a mode at zero and decrease
monotonely. These have greater variance and hence less informative.
apar <- 0.5
bpar <- var(pulp$bright)*apar
lgprior <- list(prec = list(prior="loggamma", param = c(apar,bpar)))
formula <- bright ~ f(operator, model="iid", hyper = lgprior)
result <- inla(formula, family="gaussian", data=pulp)
result <- inla.hyperpar(result)
summary(result)
Call:
"inla(formula = formula, family = \"gaussian\", data = pulp)"
Time used:
Pre = 0.949, Running = 0.131, Post = 0.0766, Total = 1.16
Fixed effects:
mean sd 0.025quant 0.5quant 0.975quant mode kld
(Intercept) 60.4 0.233 59.931 60.4 60.869 60.4 0.002
Random effects:
Name Model
operator IID model
Model hyperparameters:
mean sd 0.025quant 0.5quant 0.975quant mode
Precision for the Gaussian observations 10.59 3.52 4.87 10.20 18.53 9.41
Precision for operator 11.12 9.02 1.17 8.74 35.00 4.53
Expected number of effective parameters(stdev): 3.49(0.364)
Number of equivalent replicates : 5.73
Marginal log-Likelihood: -17.93
Compute the summaries as before:
sigmaalpha <- inla.tmarginal(function(x) 1/sqrt(exp(x)),result$internal.marginals.hyperpar[[2]])
sigmaepsilon <- inla.tmarginal(function(x) 1/sqrt(exp(x)),result$internal.marginals.hyperpar[[1]])
restab <- sapply(result$marginals.fixed, function(x) inla.zmarginal(x,silent=TRUE))
restab <- cbind(restab, inla.zmarginal(sigmaalpha,silent=TRUE))
restab <- cbind(restab, inla.zmarginal(sigmaepsilon,silent = TRUE))
restab <- cbind(restab, sapply(result$marginals.random$operator,function(x) inla.zmarginal(x, silent = TRUE)))
colnames(restab) <- c("mu","alpha","epsilon",levels(pulp$operator))
data.frame(restab)
mu alpha epsilon a b c d
mean 60.4 0.38937 0.32063 -0.13278 -0.28218 0.18258 0.23238
sd 0.23275 0.20389 0.056154 0.24942 0.25188 0.25004 0.25086
quant0.025 59.93 0.16902 0.23255 -0.64645 -0.81221 -0.30165 -0.24821
quant0.25 60.271 0.25984 0.28052 -0.27426 -0.42425 0.034853 0.08279
quant0.5 60.399 0.33765 0.31303 -0.12944 -0.27424 0.17508 0.22334
quant0.75 60.527 0.45472 0.35221 0.010768 -0.13309 0.32149 0.37148
quant0.975 60.868 0.92011 0.45204 0.35291 0.19263 0.69904 0.75429
Make the plots:
ddf <- data.frame(rbind(sigmaalpha,sigmaepsilon),errterm=gl(2,dim(sigmaalpha)[1],labels = c("alpha","epsilon")))
ggplot(ddf, aes(x,y, linetype=errterm))+geom_line()+xlab("bright")+ylab("density")+xlim(0,2)
The posterior for the error SD is quite similar to that seen previously but the operator SD is larger and bounded away from zero.
We can compute the probability that the operator SD is smaller than 0.1:
inla.pmarginal(0.1, sigmaalpha)
[1] 7.2871e-05
The probability is very small. The choice of prior may be unsuitable in that no density is placed on an SD=0 (or infinite precision). We also have very little prior weight on low SD/high precision values. This leads to a posterior for the operator with very little density assigned to small values of the SD. But we can see from looking at the data or from prior analyses of the data that there is some possibility that the operator SD is negligibly small.
In Simpson et al (2015), penalized complexity priors are proposed. This requires that we specify a scaling for the SDs of the random effects. We use the SD of the residuals of the fixed effects only model (what might be called the base model in the paper) to provide this scaling.
sdres <- sd(pulp$bright)
pcprior <- list(prec = list(prior="pc.prec", param = c(3*sdres,0.01)))
formula <- bright ~ f(operator, model="iid", hyper = pcprior)
result <- inla(formula, family="gaussian", data=pulp)
result <- inla.hyperpar(result)
summary(result)
Call:
"inla(formula = formula, family = \"gaussian\", data = pulp)"
Time used:
Pre = 0.949, Running = 0.152, Post = 0.0778, Total = 1.18
Fixed effects:
mean sd 0.025quant 0.5quant 0.975quant mode kld
(Intercept) 60.4 0.173 60.049 60.4 60.752 60.4 0
Random effects:
Name Model
operator IID model
Model hyperparameters:
mean sd 0.025quant 0.5quant 0.975quant mode
Precision for the Gaussian observations 10.09 3.51e+00 4.48 9.67 18.05 8.82
Precision for operator 954240.12 6.54e+08 2.24 16.61 1101.86 5.90
Expected number of effective parameters(stdev): 3.03(0.742)
Number of equivalent replicates : 6.61
Marginal log-Likelihood: -17.97
Compute the summaries as before:
sigmaalpha <- inla.tmarginal(function(x) 1/sqrt(exp(x)),result$internal.marginals.hyperpar[[2]])
sigmaepsilon <- inla.tmarginal(function(x) 1/sqrt(exp(x)),result$internal.marginals.hyperpar[[1]])
restab <- sapply(result$marginals.fixed, function(x) inla.zmarginal(x,silent=TRUE))
restab <- cbind(restab, inla.zmarginal(sigmaalpha,silent=TRUE))
restab <- cbind(restab, inla.zmarginal(sigmaepsilon,silent = TRUE))
restab <- cbind(restab, sapply(result$marginals.random$operator,function(x) inla.zmarginal(x, silent = TRUE)))
colnames(restab) <- c("mu","alpha","epsilon",levels(pulp$operator))
data.frame(restab)
mu alpha epsilon a b c d
mean 60.4 0.27121 0.32985 -0.10938 -0.23306 0.15018 0.19075
sd 0.17283 0.15847 0.06051 0.19093 0.20358 0.19416 0.19867
quant0.025 60.048 0.030079 0.23563 -0.52204 -0.67978 -0.20284 -0.15633
quant0.25 60.302 0.16472 0.2864 -0.21783 -0.35386 0.024033 0.055881
quant0.5 60.399 0.24505 0.32141 -0.096252 -0.21757 0.13326 0.17326
quant0.75 60.496 0.34735 0.36398 0.0044809 -0.094222 0.26019 0.3052
quant0.975 60.75 0.66253 0.47167 0.24942 0.11059 0.57213 0.62442
Make the plots:
ddf <- data.frame(rbind(sigmaalpha,sigmaepsilon),errterm=gl(2,dim(sigmaalpha)[1],labels = c("alpha","epsilon")))
ggplot(ddf, aes(x,y, linetype=errterm))+geom_line()+xlab("bright")+ylab("density")+xlim(0,2)
We get a similar result to the truncated normal prior used earlier although the operator SD is generally smaller.
We can compute the probability that the operator SD is smaller than 0.1:
inla.pmarginal(0.1, sigmaalpha)
[1] 0.10372
The probability is small but not insubstantial.
sessionInfo()
R version 4.0.2 (2020-06-22)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Catalina 10.15.6
Matrix products: default
BLAS: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRblas.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib
locale:
[1] en_GB.UTF-8/en_GB.UTF-8/en_GB.UTF-8/C/en_GB.UTF-8/en_GB.UTF-8
attached base packages:
[1] parallel stats graphics grDevices utils datasets methods base
other attached packages:
[1] INLA_20.03.17 foreach_1.5.0 sp_1.4-2 Matrix_1.2-18 ggplot2_3.3.2 knitr_1.29
loaded via a namespace (and not attached):
[1] pillar_1.4.6 compiler_4.0.2 iterators_1.0.12 tools_4.0.2 digest_0.6.25
[6] evaluate_0.14 lifecycle_0.2.0 tibble_3.0.3 gtable_0.3.0 lattice_0.20-41
[11] pkgconfig_2.0.3 rlang_0.4.7 yaml_2.2.1 xfun_0.16 withr_2.2.0
[16] dplyr_1.0.2 stringr_1.4.0 MatrixModels_0.4-1 generics_0.0.2 vctrs_0.3.4
[21] grid_4.0.2 tidyselect_1.1.0 glue_1.4.2 R6_2.4.1 rmarkdown_2.3
[26] farver_2.0.3 purrr_0.3.4 magrittr_1.5 splines_4.0.2 scales_1.1.1
[31] codetools_0.2-16 ellipsis_0.3.1 htmltools_0.5.0.9000 colorspace_1.4-1 Deriv_4.0.1
[36] labeling_0.3 stringi_1.4.6 munsell_0.5.0 crayon_1.3.4