Abstract
Task We explore the code from the paper “Pointless spatial modeling” by Katie Wilson and Jon Wakefield.
set.seed(10)
load("kenya.rdata")
#' Read in population data
#' Follow instructions in pointless-spatial-modeling README as to how to get this
pop.dat <- raster("gpw_v4_population_count_rev11_2015_2pt5_min.tif")
pop.dat <- setMinMax(pop.dat)
kenya.extent <- extent(33.9, 42, -4.7, 5.1)
pop.dat.kenya <- crop(pop.dat, kenya.extent)
kenya.df1 <- fortify(adm0) %>%
mutate(id = as.numeric(id))
## Regions defined for each Polygons
kenya.df47 <- fortify(adm1) %>%
mutate(id = as.numeric(id))
## Regions defined for each Polygons
kenya.df8 <- fortify(adm0.5) %>%
mutate(id = as.numeric(id) + 1)
## Regions defined for each Polygons
#' Set-up variables for simulation
#' * Create mesh for first 5 scenarios: "mesh.true"
#' * Create D matrix used for scenario 2 and 3: "D" (47 x m)
#' * Create D matrix used for scenario 4 and 5: "D8" (see note above)
#' * Add columns to kenya.data indicating which polygons the EAs reside in
# Create internal mesh points
points.kenya <- spsample(adm0, 2500, "regular")
## Warning in proj4string(obj): CRS object has comment, which is lost in output; in tests, see
## https://cran.r-project.org/web/packages/sp/vignettes/CRS_warnings.html
boundary.kenya <- inla.nonconvex.hull(
points.kenya@coords,
convex = 0.1,
resolution = c(120, 120)
)
#' Determine population near these mesh points
pop.at.meshX <- raster::extract(pop.dat.kenya, points.kenya@coords)
pop.at.meshX[is.na(pop.at.meshX)] <- 0
pop.at.mesh <- data.frame(points.kenya@coords)
pop.at.mesh$pop <- pop.at.meshX
names(pop.at.mesh)[1:2] <- c("mlong", "mlat")
#' Make the mesh
mesh.true <- inla.mesh.2d(
pop.at.mesh[, 1:2],
offset = c(1, 2),
max.edge = 1 * c(1, 5)
)
plot(mesh.true)
#' adm1
#' Determine which polys the mesh points live in
meshgrid <- data.frame(
Longitude = mesh.true$loc[,1],
Latitude = mesh.true$loc[,2]
)
coordinates(meshgrid) <- ~ Longitude + Latitude
proj4string(meshgrid) <- proj4string(adm1)
meshlocs <- over(meshgrid, adm1)[, 1]
tapply(rep(1, length(meshlocs)), meshlocs, sum)
## 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
## 48 12 14 7 14 11 186 21 112 97 12 12 11 54 7 6 11 132 35 37 26 27 33 108 324 32 13 2 10 4 32 10 74 3 14 14 91 16 69 167 11 9
## 43 44 45 46 47
## 271 14 2 239 41
mesh.df <- data.frame(
mlong = mesh.true$loc[, 1],
mlat = mesh.true$loc[, 2],
loc = meshlocs,
id = 1:length(meshlocs)
)
#' adm0.5
# Determine which polys the mesh points live in
#' There is slight misalignment of the boundaries, which should completely
#' overlap. Thus, we manually enter the provinces based on which of the 47
#' districts the mesh point is in.
meshlocs8 <- over(meshgrid, adm0.5)[, 1]
mesh.df$loc8X <- meshlocs8
mapping47to8 <- as.vector(apply(table(mesh.df[, c("loc", "loc8X")]), 1, which.max))
mesh.df$loc8 <- mapping47to8[mesh.df$loc]
#' Population at mesh including polygon location
pop.at.mesh <- dplyr::right_join(mesh.df, pop.at.mesh)
## Joining, by = c("mlong", "mlat")
#' Create D matrix
#' adm1
D <- inla.spde.make.A(
mesh = mesh.true,
loc = as.matrix(pop.at.mesh[,1:2]),
block = pop.at.mesh$loc,
weights = pop.at.mesh$pop
)
D.tmp <- list()
D.tmp$D <- D / rowSums(D)
D.tmp$mesh.weights <- colSums(D)
mesh.df$weight.unscaled <- D.tmp$mesh.weights
D <- D.tmp$D
mesh.df$weight.scaled <- colSums(D)
nmesh.area <- 1 / tapply(rep(1, nrow(mesh.df)), mesh.df$loc, sum)
mesh.df$weight.comp <- nmesh.area[mesh.df$loc] #' Comparison weight
#' adm0.5
D8 <- inla.spde.make.A(
mesh = mesh.true,
loc = as.matrix(pop.at.mesh[,1:2]),
block = pop.at.mesh$loc8,
weights = pop.at.mesh$pop
)
D.tmp8 <- list()
D.tmp8$D <- D8 / rowSums(D8)
D.tmp8$mesh.weights <- colSums(D8)
mesh.df$weight.unscaled8 <- D.tmp8$mesh.weights
D8 <- D.tmp8$D
mesh.df$weight.scaled8 <- colSums(D8)
nmesh.area8 <- 1 / tapply(rep(1, nrow(mesh.df)), mesh.df$loc8, sum)
mesh.df$weight.comp8 <- nmesh.area8[mesh.df$loc8] #' Comparison weight
#' Set-up parameters
alpha <- 0
sigma2 <- 0.25
lambda2 <- 1 - sigma2
erange <- sqrt(8) / exp(0.5)
theta2 <- log(sqrt(8) / erange)
kappa <- exp(theta2)
tau2 <- 1 / (4 * pi * kappa^2 * lambda2)
theta1 <- log(sqrt(tau2))
#' Set-up field
spde <- inla.spde2.matern(mesh.true)
Q.true <- inla.spde.precision(spde, c(theta1, theta2))
field.true <- as.numeric(inla.qsample(1, Q = Q.true, seed = 50L))
## Warning in inla.qsample(1, Q = Q.true, seed = 50L): Since 'seed!=0', parallel model is disabled and serial model is selected
#' Connecting field to data
proj.survey <- inla.mesh.projector(
mesh.true,
loc = as.matrix(kenya.data[, c("LONGNUM", "LATNUM")])
)
field.survey <- inla.mesh.project(proj.survey, field = field.true)
kenya.data$field <- field.survey
kenya.data$mu <- alpha + kenya.data$field
#' Make matrix that will be used to obtain predictions of the surface
pred.info <- MakePredictionAMatrix(mesh.true, adm0, dims=c(110, 110))
A.pred <- pred.info$A.pred
stkgrid <- inla.stack(
data = list(y = NA, N = NA),
A = list(A.pred, 1),
effects = list(i = 1:spde$n.spde, alpha = rep(1, nrow(A.pred))), tag = 'prd.gr'
)
rel.points.clip <- pred.info$rel.points.clip
#' Simulate data
#' Census
#' Data simulated on 1km x 1km grid
pop.data.kenya.points <- data.frame(rasterToPoints(pop.dat.kenya, spatial = F))
names(pop.data.kenya.points) <- c("long", "lat", "pop")
coordinates(pop.data.kenya.points) <- ~ long + lat
pop.data.kenya.points@proj4string <- adm0@proj4string
pop.pt.insideX <- pop.data.kenya.points[adm0, ]
pop.pt.inside <- as.data.frame(pop.pt.insideX)
coordinates(pop.pt.inside) <- ~ long + lat
pop.pt.inside@proj4string <- adm0@proj4string
functions.R
# Make a smaller version of the A matrix so that predicting the risk surface
# is less computationally involved
#
# Args:
# mesh.true: The mesh
# adm0: Spatial polygons dataframe that is for the boundary of Kenya
#
# Return: list with prediction matrix
# and points where predictions will be made
MakePredictionAMatrix <- function(mesh.true, adm0, dims = c(120, 120)) {
smallproj <- inla.mesh.projector(mesh.true, dims=dims)
x <- smallproj$x
y <- smallproj$y
all.temp <- (expand.grid(x, y , KEEP.OUT.ATTRS=F))
names(all.temp) <- c("long", "lat")
coordinates(all.temp) <- ~ long + lat
all.temp@proj4string <- adm0@proj4string
rel.points <- all.temp[adm0, ]
rel.points.clip <- as.data.frame(rel.points)
A.pred <- inla.spde.make.A(mesh.true, loc=as.matrix(rel.points.clip))
return(list(A.pred=A.pred, rel.points.clip=rel.points.clip))
}
sessionInfo()
## R version 4.2.0 (2022-04-22)
## Platform: x86_64-apple-darwin17.0 (64-bit)
## Running under: macOS Monterey 12.6
##
## Matrix products: default
## LAPACK: /Library/Frameworks/R.framework/Versions/4.2/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] dplyr_1.0.9 INLA_22.05.07 foreach_1.5.2 Matrix_1.5-1 knitr_1.39 rgdal_1.5-30 raster_3.5-15
## [8] sp_1.4-7 rstan_2.21.5 ggplot2_3.3.6 StanHeaders_2.21.0-7 sf_1.0-7 bsae_0.2.7
##
## loaded via a namespace (and not attached):
## [1] viridis_0.6.2 sass_0.4.1 jsonlite_1.8.0 viridisLite_0.4.0 ids_1.0.1 splines_4.2.0 bslib_0.3.1 RcppParallel_5.1.5
## [9] assertthat_0.2.1 askpass_1.1 highr_0.9 stats4_4.2.0 yaml_2.3.5 pillar_1.7.0 lattice_0.20-45 glue_1.6.2
## [17] uuid_1.1-0 digest_0.6.29 colorspace_2.0-3 htmltools_0.5.2 plyr_1.8.7 pkgconfig_2.0.3 purrr_0.3.4 scales_1.2.0
## [25] processx_3.5.3 terra_1.5-21 tibble_3.1.7 openssl_2.0.1 proxy_0.4-26 bayesplot_1.9.0 generics_0.1.2 ellipsis_0.3.2
## [33] withr_2.5.0 cli_3.3.0 magrittr_2.0.3 crayon_1.5.1 evaluate_0.15 ps_1.7.0 fansi_1.0.3 class_7.3-20
## [41] pkgbuild_1.3.1 tools_4.2.0 loo_2.5.1 prettyunits_1.1.1 lifecycle_1.0.1 matrixStats_0.62.0 stringr_1.4.0 munsell_0.5.0
## [49] callr_3.7.0 compiler_4.2.0 jquerylib_0.1.4 e1071_1.7-9 rlang_1.0.2 classInt_0.4-3 units_0.8-0 grid_4.2.0
## [57] ggridges_0.5.3 iterators_1.0.14 rstudioapi_0.13 rmarkdown_2.14 orderly_1.4.3 gtable_0.3.0 codetools_0.2-18 inline_0.3.19
## [65] DBI_1.1.2 R6_2.5.1 splancs_2.01-43 gridExtra_2.3 fastmap_1.1.0 utf8_1.2.2 KernSmooth_2.23-20 stringi_1.7.6
## [73] Rcpp_1.0.8.3 vctrs_0.4.1 tidyselect_1.1.2 xfun_0.31